Bug 629200 part 3 - Make AfterSetAttr take an nsAttrValue; r=bz
authorBrian Birtles <birtles@gmail.com>
Tue, 07 Feb 2012 15:54:38 +0900
changeset 86433 adb8a322cbe320d3d85bb95b0bc7fc1e633b3246
parent 86432 415f3b807d452beb9433381a4e5bf97ecde0b8d4
child 86434 c22a4f1815c6d7f59f1fac511fdad4afb2215a3e
push id94
push userbturner@mozilla.com
push dateWed, 08 Feb 2012 05:39:15 +0000
reviewersbz
bugs629200
milestone13.0a1
Bug 629200 part 3 - Make AfterSetAttr take an nsAttrValue; r=bz
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/base/src/nsStyledElement.cpp
content/base/src/nsStyledElement.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLButtonElement.cpp
content/html/content/src/nsHTMLFieldSetElement.cpp
content/html/content/src/nsHTMLFieldSetElement.h
content/html/content/src/nsHTMLFormElement.cpp
content/html/content/src/nsHTMLFormElement.h
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLInputElement.h
content/html/content/src/nsHTMLMenuItemElement.cpp
content/html/content/src/nsHTMLMenuItemElement.h
content/html/content/src/nsHTMLScriptElement.cpp
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLSelectElement.h
content/html/content/src/nsHTMLTableElement.cpp
content/html/content/src/nsHTMLTableElement.h
content/html/content/src/nsHTMLTextAreaElement.cpp
content/svg/content/src/nsSVGAnimationElement.cpp
content/svg/content/src/nsSVGAnimationElement.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGFilters.cpp
content/svg/content/src/nsSVGFilters.h
content/svg/content/src/nsSVGImageElement.cpp
content/svg/content/src/nsSVGImageElement.h
content/svg/content/src/nsSVGScriptElement.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -4940,17 +4940,17 @@ nsGenericElement::SetAttr(PRInt32 aNames
 
   nsAttrValue attrValue;
   if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
     attrValue.SetTo(aValue);
   }
 
   return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
                           attrValue, modType, hasListeners, aNotify,
-                          &aValue);
+                          true);
 }
 
 nsresult
 nsGenericElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                 nsIAtom* aPrefix, nsAttrValue& aParsedValue,
                                 bool aNotify)
 {
   // Keep this in sync with SetAttr above
@@ -4958,20 +4958,16 @@ nsGenericElement::SetParsedAttr(PRInt32 
   NS_ENSURE_ARG_POINTER(aName);
   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
                "Don't call SetAttr with unknown namespace");
 
   if (!mAttrsAndChildren.CanFitMoreAttrs()) {
     return NS_ERROR_FAILURE;
   }
 
-  // XXX Remove
-  nsAutoString value;
-  aParsedValue.ToString(value);
-
   PRUint8 modType;
   bool hasListeners;
   nsAttrValue oldValue;
 
   if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aParsedValue, aNotify,
                             oldValue, &modType, &hasListeners)) {
     return NS_OK;
   }
@@ -4980,37 +4976,44 @@ nsGenericElement::SetParsedAttr(PRInt32 
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aNotify) {
     nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
   }
 
   return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
                           aParsedValue, modType, hasListeners, aNotify,
-                          &value);
+                          true);
 }
 
 nsresult
 nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
                                    nsIAtom* aName,
                                    nsIAtom* aPrefix,
                                    const nsAttrValue& aOldValue,
                                    nsAttrValue& aParsedValue,
                                    PRUint8 aModType,
                                    bool aFireMutation,
                                    bool aNotify,
-                                   const nsAString* aValueForAfterSetAttr)
+                                   bool aCallAfterSetAttr)
 {
   nsresult rv;
 
   nsIDocument* document = GetCurrentDoc();
   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
 
   nsMutationGuard::DidMutate();
 
+  // Copy aParsedValue for later use since it will be lost when we call
+  // SetAndTakeMappedAttr below
+  nsAttrValue aValueForAfterSetAttr;
+  if (aCallAfterSetAttr) {
+    aValueForAfterSetAttr.SetTo(aParsedValue);
+  }
+
   if (aNamespaceID == kNameSpaceID_None) {
     // XXXbz Perhaps we should push up the attribute mapping function
     // stuff to nsGenericElement?
     if (!IsAttributeMapped(aName) ||
         !SetMappedAttribute(document, aName, aParsedValue, &rv)) {
       rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
     }
   }
@@ -5038,18 +5041,18 @@ nsGenericElement::SetAttrAndNotify(PRInt
   if (aNotify) {
     nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
   }
 
   if (aNamespaceID == kNameSpaceID_XMLEvents && 
       aName == nsGkAtoms::event && mNodeInfo->GetDocument()) {
     mNodeInfo->GetDocument()->AddXMLEventsContent(this);
   }
-  if (aValueForAfterSetAttr) {
-    rv = AfterSetAttr(aNamespaceID, aName, aValueForAfterSetAttr, aNotify);
+  if (aCallAfterSetAttr) {
+    rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aFireMutation) {
     nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
 
     nsCOMPtr<nsIDOMAttr> attrNode;
     nsAutoString ns;
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -645,28 +645,27 @@ protected:
    * @param aPrefix       aPrefix of attribute
    * @param aOldValue     previous value of attribute. Only needed if
    *                      aFireMutation is true.
    * @param aParsedValue  parsed new value of attribute
    * @param aModType      nsIDOMMutationEvent::MODIFICATION or ADDITION.  Only
    *                      needed if aFireMutation or aNotify is true.
    * @param aFireMutation should mutation-events be fired?
    * @param aNotify       should we notify document-observers?
-   * @param aValueForAfterSetAttr If not null, AfterSetAttr will be called
-   *                      with the value pointed by this parameter.
+   * @param aCallAfterSetAttr should we call AfterSetAttr?
    */
   nsresult SetAttrAndNotify(PRInt32 aNamespaceID,
                             nsIAtom* aName,
                             nsIAtom* aPrefix,
                             const nsAttrValue& aOldValue,
                             nsAttrValue& aParsedValue,
                             PRUint8 aModType,
                             bool aFireMutation,
                             bool aNotify,
-                            const nsAString* aValueForAfterSetAttr);
+                            bool aCallAfterSetAttr);
 
   /**
    * Convert an attribute string value to attribute type based on the type of
    * attribute.  Called by SetAttr().  Note that at the moment we only do this
    * for attributes in the null namespace (kNameSpaceID_None).
    *
    * @param aNamespaceID the namespace of the attribute to convert
    * @param aAttribute the attribute to convert
@@ -729,17 +728,17 @@ protected:
    * @param aName the localname of the attribute being set
    * @param aValue the value it's being set to.  If null, the attr is being
    *        removed.
    * @param aNotify Whether we plan to notify document observers.
    */
   // Note that this is inlined so that when subclasses call it it gets
   // inlined.  Those calls don't go through a vtable.
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify)
+                                const nsAttrValue* aValue, bool aNotify)
   {
     return NS_OK;
   }
 
   /**
    * Hook to allow subclasses to produce a different nsEventListenerManager if
    * needed for attachment of attribute-defined handlers
    */
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -141,17 +141,17 @@ nsStyledElementNotElementCSSInlineStyle:
   }
 
   return nsGenericElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
 }
 
 nsresult
 nsStyledElementNotElementCSSInlineStyle::AfterSetAttr(PRInt32 aNamespaceID,
                                                       nsIAtom* aAttribute,
-                                                      const nsAString* aValue,
+                                                      const nsAttrValue* aValue,
                                                       bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_None && !aValue &&
       aAttribute == nsGkAtoms::id) {
     // The id has been removed when calling UnsetAttr but we kept it because
     // the id is used for some layout stuff between UnsetAttr and AfterSetAttr.
     // Now. the id is really removed so it would not be safe to keep this flag.
     ClearHasID();
@@ -197,17 +197,17 @@ nsStyledElementNotElementCSSInlineStyle:
 
   // XXXbz do we ever end up with ADDITION here?  I doubt it.
   PRUint8 modType = modification ?
     static_cast<PRUint8>(nsIDOMMutationEvent::MODIFICATION) :
     static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
 
   return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nsnull,
                           oldValue, attrValue, modType, hasListeners,
-                          aNotify, nsnull);
+                          aNotify, false);
 }
 
 css::StyleRule*
 nsStyledElementNotElementCSSInlineStyle::GetInlineStyleRule()
 {
   if (!MayHaveStyle()) {
     return nsnull;
   }
--- a/content/base/src/nsStyledElement.h
+++ b/content/base/src/nsStyledElement.h
@@ -84,17 +84,17 @@ public:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual void UnbindFromTree(bool aDeep, bool aNullParent);
 
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   nsIDOMCSSStyleDeclaration* GetStyle(nsresult* retval);
 
 protected:
 
   /**
    * Parse a style attr value into a CSS rulestruct (or, if there is no
    * document, leave it as a string) and return as nsAttrValue.
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1278,21 +1278,24 @@ nsGenericHTMLElement::GetHrefURIForAncho
   nsCOMPtr<nsIURI> uri;
   GetURIAttr(nsGkAtoms::href, nsnull, getter_AddRefs(uri));
 
   return uri.forget();
 }
 
 nsresult
 nsGenericHTMLElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                   const nsAString* aValue, bool aNotify)
+                                   const nsAttrValue* aValue, bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_None) {
-    if (nsContentUtils::IsEventAttributeName(aName, EventNameType_HTML) && aValue) {
-      nsresult rv = AddScriptEventListener(aName, *aValue);
+    if (nsContentUtils::IsEventAttributeName(aName, EventNameType_HTML) &&
+        aValue) {
+      NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eString,
+        "Expected string value for script body");
+      nsresult rv = AddScriptEventListener(aName, aValue->GetStringValue());
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else if (aNotify && aName == nsGkAtoms::spellcheck) {
       SyncEditorsOnSubtree(this);
     }
   }
 
   return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
@@ -2795,26 +2798,27 @@ nsGenericHTMLFormElement::BeforeSetAttr(
   }
 
   return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
                                              aValue, aNotify);
 }
 
 nsresult
 nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                       const nsAString* aValue, bool aNotify)
+                                       const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     // add the control to the hashtable as needed
 
     if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
-        aValue) {
-      if (!aValue->IsEmpty()) {
-        mForm->AddElementToTable(this, *aValue);
-      }
+        aValue && !aValue->IsEmptyString()) {
+      NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eAtom,
+        "Expected atom value for name/id");
+      mForm->AddElementToTable(this,
+        nsDependentAtomString(aValue->GetAtomValue()));
     }
 
     if (mForm && aName == nsGkAtoms::type) {
       nsAutoString tmp;
 
       GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
 
       if (!tmp.IsEmpty()) {
@@ -2836,17 +2840,17 @@ nsGenericHTMLFormElement::AfterSetAttr(P
       UpdateState(aNotify);
     }
 
     if (aName == nsGkAtoms::form) {
       // We need a new form id observer.
       nsIDocument* doc = GetCurrentDoc();
       if (doc) {
         Element* formIdElement = nsnull;
-        if (aValue && !aValue->IsEmpty()) {
+        if (aValue && !aValue->IsEmptyString()) {
           formIdElement = AddFormIdObserver();
         }
 
         // Because we have a new @form value (or no more @form), we have to
         // update our form owner.
         UpdateFormOwner(false, formIdElement);
       }
     }
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -626,17 +626,17 @@ protected:
   /**
    * Determine whether an attribute is an event (onclick, etc.)
    * @param aName the attribute
    * @return whether the name is an event handler name
    */
   bool IsEventName(nsIAtom* aName);
 
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   virtual nsEventListenerManager*
     GetEventListenerManagerForAttr(nsIAtom* aAttrName, bool* aDefer);
 
   virtual const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const;
 
   /**
    * Helper method for NS_IMPL_STRING_ATTR macro.
@@ -948,17 +948,17 @@ public:
   virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
                                  PRInt32* aTabIndex);
 
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValue* aValue, bool aNotify);
 
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   void UpdateEditableFormControlState(bool aNotify);
 
   /**
    * This method will update the form owner, using @form or looking to a parent.
    *
    * @param aBindToTree Whether the element is being attached to the tree.
    * @param aFormIdElement The element associated with the id in @form. If
--- a/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/content/html/content/src/nsHTMLButtonElement.cpp
@@ -135,17 +135,17 @@ public:
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValue* aValue, bool aNotify);
   /**
    * Called when an attribute has just been changed
    */
   nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                        const nsAString* aValue, bool aNotify);
+                        const nsAttrValue* aValue, bool aNotify);
   
   // nsIContent overrides...
   virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
   virtual bool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
@@ -606,17 +606,17 @@ nsHTMLButtonElement::BeforeSetAttr(PRInt
   }
 
   return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLButtonElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                  const nsAString* aValue, bool aNotify)
+                                  const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::type) {
       if (!aValue) {
         mType = kButtonDefaultType->value;
       }
 
       UpdateState(aNotify);
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -114,17 +114,17 @@ nsHTMLFieldSetElement::PreHandleEvent(ns
     return NS_OK;
   }
 
   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
 }
 
 nsresult
 nsHTMLFieldSetElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                    const nsAString* aValue, bool aNotify)
+                                    const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled &&
       nsINode::GetFirstChild()) {
     if (!mElements) {
       mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
                                     true);
     }
 
--- a/content/html/content/src/nsHTMLFieldSetElement.h
+++ b/content/html/content/src/nsHTMLFieldSetElement.h
@@ -75,17 +75,17 @@ public:
   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLFormElement::)
 
   // nsIDOMHTMLFieldSetElement
   NS_DECL_NSIDOMHTMLFIELDSETELEMENT
 
   // nsIContent
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   virtual nsresult InsertChildAt(nsIContent* aChild, PRUint32 aIndex,
                                      bool aNotify);
   virtual nsresult RemoveChildAt(PRUint32 aIndex, bool aNotify);
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_FIELDSET; }
   NS_IMETHOD Reset();
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -372,17 +372,17 @@ nsHTMLFormElement::SetAttr(PRInt32 aName
     mNotifiedObservers = notifiedObservers;
   }
   return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                        aNotify);
 }
 
 nsresult
 nsHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify)
+                                const nsAttrValue* aValue, bool aNotify)
 {
   if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
     // Update all form elements states because they might be [no longer]
     // affected by :-moz-ui-valid or :-moz-ui-invalid.
     for (PRUint32 i = 0, length = mControls->mElements.Length();
          i < length; ++i) {
       mControls->mElements[i]->UpdateState(true);
     }
--- a/content/html/content/src/nsHTMLFormElement.h
+++ b/content/html/content/src/nsHTMLFormElement.h
@@ -169,17 +169,17 @@ public:
                    const nsAString& aValue, bool aNotify)
   {
     return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
   }
   virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   /**
    * Forget all information about the current submission (and the fact that we
    * are currently submitting at all).
    */
   void ForgetCurrentSubmission();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -751,18 +751,17 @@ nsHTMLInputElement::BeforeSetAttr(PRInt3
   }
 
   return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                 const nsAString* aValue,
-                                 bool aNotify)
+                                 const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     //
     // When name or type changes, radio should be added to radio group.
     // (type changes are handled in the form itself currently)
     // If the parser is not done creating the radio, we also should not do it.
     //
     if ((aName == nsGkAtoms::name ||
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -379,17 +379,17 @@ protected:
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValue* aValue, bool aNotify);
   /**
    * Called when an attribute has just been changed
    */
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   /**
    * Dispatch a select event. Returns true if the event was not cancelled.
    */
   bool DispatchSelectEvent(nsPresContext* aPresContext);
 
   void SelectAll(nsPresContext* aPresContext);
   bool IsImage() const
--- a/content/html/content/src/nsHTMLMenuItemElement.cpp
+++ b/content/html/content/src/nsHTMLMenuItemElement.cpp
@@ -412,17 +412,17 @@ nsHTMLMenuItemElement::GetText(nsAString
   nsContentUtils::GetNodeTextContent(this, false, text);
 
   text.CompressWhitespace(true, true);
   aText = text;
 }
 
 nsresult
 nsHTMLMenuItemElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                    const nsAString* aValue, bool aNotify)
+                                    const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if ((aName == nsGkAtoms::radiogroup || aName == nsGkAtoms::type) &&
         mType == CMD_TYPE_RADIO &&
         !mParserCreating) {
       if (IsInDoc() && GetParent()) {
         AddedToRadioGroup();
       }
--- a/content/html/content/src/nsHTMLMenuItemElement.h
+++ b/content/html/content/src/nsHTMLMenuItemElement.h
@@ -101,17 +101,17 @@ public:
    */
   bool IsChecked() const { return mChecked; }
   bool IsCheckedDirty() const { return mCheckedDirty; }
 
   void GetText(nsAString& aText);
 
 protected:
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   void WalkRadioGroup(Visitor* aVisitor);
 
   nsHTMLMenuItemElement* GetSelectedRadio();
 
   void AddedToRadioGroup();
 
   void InitChecked();
--- a/content/html/content/src/nsHTMLScriptElement.cpp
+++ b/content/html/content/src/nsHTMLScriptElement.cpp
@@ -113,17 +113,17 @@ public:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // nsGenericElement
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   // nsScriptElement
   virtual bool HasScriptContent();
 };
 
 
@@ -236,17 +236,17 @@ nsresult
 nsHTMLScriptElement::SetAsync(bool aValue)
 {
   mForceAsync = false;
   return SetBoolAttr(nsGkAtoms::async, aValue);
 }
 
 nsresult
 nsHTMLScriptElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                  const nsAString* aValue, bool aNotify)
+                                  const nsAttrValue* aValue, bool aNotify)
 {
   if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
     mForceAsync = false;
   }
   return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
                                             aNotify);
 }
 
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -1379,17 +1379,17 @@ nsHTMLSelectElement::BeforeSetAttr(PRInt
   }
 
   return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLSelectElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                  const nsAString* aValue, bool aNotify)
+                                  const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::disabled) {
       UpdateBarredFromConstraintValidation();
     } else if (aName == nsGkAtoms::required) {
       UpdateValueMissingValidityState();
     }
 
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -389,17 +389,17 @@ public:
    */
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                nsIContent* aBindingParent,
                                bool aCompileEventHandlers);
   virtual void UnbindFromTree(bool aDeep, bool aNullParent);
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValue* aValue, bool aNotify);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   
   virtual void DoneAddingChildren(bool aHaveNotified);
   virtual bool IsDoneAddingChildren() {
     return mIsDoneAddingChildren;
   }
 
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -1272,17 +1272,17 @@ nsHTMLTableElement::BeforeSetAttr(PRInt3
     ReleaseInheritedAttributes();
   }
   return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
                                              aNotify);
 }
 
 nsresult
 nsHTMLTableElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                 const nsAString* aValue,
+                                 const nsAttrValue* aValue,
                                  bool aNotify)
 {
   if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
     BuildInheritedAttributes();
   }
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                             aNotify);
 }
--- a/content/html/content/src/nsHTMLTableElement.h
+++ b/content/html/content/src/nsHTMLTableElement.h
@@ -84,17 +84,17 @@ public:
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValue* aValue, bool aNotify);
   /**
    * Called when an attribute has just been changed
    */
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTableElement,
                                            nsGenericHTMLElement)
   nsMappedAttributes* GetAttributesMappedForCell();
   already_AddRefed<nsIDOMHTMLTableSectionElement> GetTHead() {
     return GetSection(nsGkAtoms::thead);
   }
   already_AddRefed<nsIDOMHTMLTableSectionElement> GetTFoot() {
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -279,17 +279,17 @@ protected:
   /**
    * Common method to call from the various mutation observer methods.
    * aContent is a content node that's either the one that changed or its
    * parent; we should only respond to the change if aContent is non-anonymous.
    */
   void ContentChanged(nsIContent* aContent);
 
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom *aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   /**
    * Return if an element should have a specific validity UI
    * (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes).
    *
    * @return Whether the elemnet should have a validity UI.
    */
   bool ShouldShowValidityUI() const {
@@ -1271,17 +1271,17 @@ nsHTMLTextAreaElement::ContentChanged(ns
     // further auditing.
     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     Reset();
   }
 }
 
 nsresult
 nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                    const nsAString* aValue, bool aNotify)
+                                    const nsAttrValue* aValue, bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
         aName == nsGkAtoms::readonly) {
       UpdateValueMissingValidityState();
 
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
--- a/content/svg/content/src/nsSVGAnimationElement.cpp
+++ b/content/svg/content/src/nsSVGAnimationElement.cpp
@@ -371,30 +371,32 @@ nsSVGAnimationElement::ParseAttribute(PR
   }
 
   return nsSVGAnimationElementBase::ParseAttribute(aNamespaceID, aAttribute,
                                                    aValue, aResult);
 }
 
 nsresult
 nsSVGAnimationElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                    const nsAString* aValue, bool aNotify)
+                                    const nsAttrValue* aValue, bool aNotify)
 {
   nsresult rv =
     nsSVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue,
                                             aNotify);
 
   if (aNamespaceID != kNameSpaceID_XLink || aName != nsGkAtoms::href)
     return rv;
 
   if (!aValue) {
     mHrefTarget.Unlink();
     AnimationTargetChanged();
   } else if (IsInDoc()) {
-    UpdateHrefTarget(this, *aValue);
+    NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eString,
+                      "Expected href attribute to be string type");
+    UpdateHrefTarget(this, aValue->GetStringValue());
   } // else: we're not yet in a document -- we'll update the target on
     // next BindToTree call.
 
   return rv;
 }
 
 nsresult
 nsSVGAnimationElement::UnsetAttr(PRInt32 aNamespaceID,
--- a/content/svg/content/src/nsSVGAnimationElement.h
+++ b/content/svg/content/src/nsSVGAnimationElement.h
@@ -79,17 +79,17 @@ public:
   virtual bool IsNodeOfType(PRUint32 aFlags) const;
 
   // nsGenericElement specializations
   virtual bool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   // nsISMILAnimationElement interface
   virtual const Element& AsElement() const;
   virtual Element& AsElement();
   virtual bool PassesConditionalProcessingTests();
   virtual const nsAttrValue* GetAnimAttr(nsIAtom* aName) const;
   virtual bool GetAnimAttr(nsIAtom* aAttName, nsAString& aResult) const;
   virtual bool HasAnimAttr(nsIAtom* aAttName) const;
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -255,29 +255,32 @@ nsSVGElement::BindToTree(nsIDocument* aD
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsSVGElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                           const nsAString* aValue, bool aNotify)
-{  
+                           const nsAttrValue* aValue, bool aNotify)
+{
   // If this is an svg presentation attribute we need to map it into
   // the content stylerule.
   // XXX For some reason incremental mapping doesn't work, so for now
   // just delete the style rule and lazily reconstruct it in
   // GetContentStyleRule()
   if (aNamespaceID == kNameSpaceID_None && IsAttributeMapped(aName)) {
     mContentStyleRule = nsnull;
   }
 
   if (IsEventName(aName) && aValue) {
-    nsresult rv = AddScriptEventListener(GetEventNameForAttr(aName), *aValue);
+    NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eString,
+      "Expected string value for script body");
+    nsresult rv = AddScriptEventListener(GetEventNameForAttr(aName),
+                                         aValue->GetStringValue());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return nsSVGElementBase::AfterSetAttr(aNamespaceID, aName, aValue, aNotify);
 }
 
 bool
 nsSVGElement::ParseAttribute(PRInt32 aNamespaceID,
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -245,17 +245,17 @@ public:
     return nsnull;
   }
   virtual nsIAtom* GetTransformListAttrName() const {
     return nsnull;
   }
 
 protected:
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
   virtual bool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
                                 const nsAString& aValue, nsAttrValue& aResult);
   static nsresult ReportAttributeParseFailure(nsIDocument* aDocument,
                                               nsIAtom* aAttribute,
                                               const nsAString& aValue);
 
   // Hooks for subclasses
   virtual bool IsEventName(nsIAtom* aName);
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -5547,17 +5547,17 @@ nsSVGFEImageElement::IsAttributeMapped(c
   };
   
   return FindAttributeDependence(name, map) ||
     nsSVGFEImageElementBase::IsAttributeMapped(name);
 }
 
 nsresult
 nsSVGFEImageElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                  const nsAString* aValue, bool aNotify)
+                                  const nsAttrValue* aValue, bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
 
     // If there isn't a frame we still need to load the image in case
     // the frame is created later e.g. by attaching to a document.
     // If there is a frame then it should deal with loading as the image
     // url may be animated.
     if (!GetPrimaryFrame()) {
--- a/content/svg/content/src/nsSVGFilters.h
+++ b/content/svg/content/src/nsSVGFilters.h
@@ -283,17 +283,17 @@ public:
   NS_FORWARD_NSIDOMELEMENT(nsSVGFEImageElementBase::)
 
   // nsIContent
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual nsEventStates IntrinsicState() const;
 
   // imgIDecoderObserver
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
                           const PRUnichar *statusArg);
--- a/content/svg/content/src/nsSVGImageElement.cpp
+++ b/content/svg/content/src/nsSVGImageElement.cpp
@@ -165,17 +165,17 @@ nsSVGImageElement::LoadSVGImage(bool aFo
   return LoadImage(href, aForce, aNotify);
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods:
 
 nsresult
 nsSVGImageElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify)
+                                const nsAttrValue* aValue, bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
 
     // If there isn't a frame we still need to load the image in case
     // the frame is created later e.g. by attaching to a document.
     // If there is a frame then it should deal with loading as the image
     // url may be animated
     if (!GetPrimaryFrame()) {
--- a/content/svg/content/src/nsSVGImageElement.h
+++ b/content/svg/content/src/nsSVGImageElement.h
@@ -73,17 +73,17 @@ public:
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGImageElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGImageElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGImageElementBase::)
 
   // nsIContent interface
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
 
   virtual nsEventStates IntrinsicState() const;
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const;
 
--- a/content/svg/content/src/nsSVGScriptElement.cpp
+++ b/content/svg/content/src/nsSVGScriptElement.cpp
@@ -90,17 +90,17 @@ public:
   // nsScriptElement
   virtual bool HasScriptContent();
 
   // nsIContent specializations:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers);
   virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, bool aNotify);
+                                const nsAttrValue* aValue, bool aNotify);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 protected:
   virtual StringAttributesInfo GetStringInfo();
 
   enum { HREF };
@@ -275,16 +275,16 @@ nsSVGScriptElement::BindToTree(nsIDocume
     MaybeProcessScript();
   }
 
   return NS_OK;
 }
 
 nsresult
 nsSVGScriptElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                 const nsAString* aValue, bool aNotify)
+                                 const nsAttrValue* aValue, bool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_XLink && aName == nsGkAtoms::href) {
     MaybeProcessScript();
   }
   return nsSVGScriptElementBase::AfterSetAttr(aNamespaceID, aName,
                                               aValue, aNotify);
 }
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1092,62 +1092,76 @@ nsXULElement::BeforeSetAttr(PRInt32 aNam
     }
 
     return nsStyledElement::BeforeSetAttr(aNamespaceID, aName,
                                           aValue, aNotify);
 }
 
 nsresult
 nsXULElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                           const nsAString* aValue, bool aNotify)
+                           const nsAttrValue* aValue, bool aNotify)
 {
     if (aNamespaceID == kNameSpaceID_None) {
         // XXX UnsetAttr handles more attributes than we do. See bug 233642.
 
         // Add popup and event listeners. We can't call AddListenerFor since
         // the attribute isn't set yet.
         MaybeAddPopupListener(aName);
         if (nsContentUtils::IsEventAttributeName(aName, EventNameType_XUL) && aValue) {
             // If mPrototype->mScriptTypeID != GetScriptTypeID(), it means
             // we are resolving an overlay with a different default script
             // language.  We can't defer compilation of those handlers as
             // we will have lost the script language (storing it on each
             // nsXULPrototypeAttribute is expensive!)
             bool defer = mPrototype == nsnull ||
                            mPrototype->mScriptTypeID == GetScriptTypeID();
-            AddScriptEventListener(aName, *aValue, defer);
+            if (aValue->Type() == nsAttrValue::eString) {
+                AddScriptEventListener(aName, aValue->GetStringValue(), defer);
+            } else {
+                nsAutoString body;
+                aValue->ToString(body);
+                AddScriptEventListener(aName, body, defer);
+            }
         }
 
         // Hide chrome if needed
         if (mNodeInfo->Equals(nsGkAtoms::window) && aValue) {
-          if (aName == nsGkAtoms::hidechrome) {
-              HideWindowChrome(aValue->EqualsLiteral("true"));
-          }
-          else if (aName == nsGkAtoms::chromemargin) {
-              SetChromeMargins(aValue);
-          }
+            if (aName == nsGkAtoms::hidechrome) {
+                HideWindowChrome(
+                  aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
+            }
+            else if (aName == nsGkAtoms::chromemargin) {
+                SetChromeMargins(aValue);
+            }
         }
 
         // title, (in)activetitlebarcolor and drawintitlebar are settable on
         // any root node (windows, dialogs, etc)
         nsIDocument *document = GetCurrentDoc();
         if (document && document->GetRootElement() == this) {
             if (aName == nsGkAtoms::title) {
                 document->NotifyPossibleTitleChange(false);
             }
             else if ((aName == nsGkAtoms::activetitlebarcolor ||
-                      aName == nsGkAtoms::inactivetitlebarcolor)) {
+                      aName == nsGkAtoms::inactivetitlebarcolor) && aValue) {
                 nscolor color = NS_RGBA(0, 0, 0, 0);
-                nsAttrValue attrValue;
-                attrValue.ParseColor(*aValue);
-                attrValue.GetColorValue(color);
+                if (aValue->Type() == nsAttrValue::eColor) {
+                    aValue->GetColorValue(color);
+                } else {
+                    nsAutoString tmp;
+                    nsAttrValue attrValue;
+                    aValue->ToString(tmp);
+                    attrValue.ParseColor(tmp);
+                    attrValue.GetColorValue(color);
+                }
                 SetTitlebarColor(color, aName == nsGkAtoms::activetitlebarcolor);
             }
             else if (aName == nsGkAtoms::drawintitlebar) {
-                SetDrawsInTitlebar(aValue && aValue->EqualsLiteral("true"));
+                SetDrawsInTitlebar(aValue &&
+                    aValue->Equals(NS_LITERAL_STRING("true"), eCaseMatters));
             }
             else if (aName == nsGkAtoms::localedir) {
                 // if the localedir changed on the root element, reset the document direction
                 nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
                 if (xuldoc) {
                     xuldoc->ResetDocumentDirection();
                 }
             }
@@ -2430,33 +2444,37 @@ public:
     }
 
 private:
     nsCOMPtr<nsIWidget> mWidget;
     nsIntMargin mMargin;
 };
 
 void
-nsXULElement::SetChromeMargins(const nsAString* aValue)
+nsXULElement::SetChromeMargins(const nsAttrValue* aValue)
 {
     if (!aValue)
         return;
 
     nsIWidget* mainWidget = GetWindowWidget();
     if (!mainWidget)
         return;
 
     // top, right, bottom, left - see nsAttrValue
-    nsAttrValue attrValue;
     nsIntMargin margins;
-
-    nsAutoString data;
-    data.Assign(*aValue);
-    if (attrValue.ParseIntMarginValue(data) &&
-        attrValue.GetIntMarginValue(margins)) {
+    bool gotMargins = false;
+
+    if (aValue->Type() == nsAttrValue::eIntMarginValue) {
+        gotMargins = aValue->GetIntMarginValue(margins);
+    } else {
+        nsAutoString tmp;
+        aValue->ToString(tmp);
+        gotMargins = nsContentUtils::ParseIntMarginValue(tmp, margins);
+    }
+    if (gotMargins) {
         nsContentUtils::AddScriptRunner(new MarginSetter(mainWidget, margins));
     }
 }
 
 void
 nsXULElement::ResetChromeMargins()
 {
     nsIWidget* mainWidget = GetWindowWidget();
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -623,17 +623,17 @@ protected:
     const nsAttrValue* FindLocalOrProtoAttr(PRInt32 aNameSpaceID,
                                             nsIAtom *aName) const {
         return nsXULElement::GetAttrInfo(aNameSpaceID, aName).mValue;
     }
 
     virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                    const nsAttrValue* aValue, bool aNotify);
     virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                  const nsAString* aValue, bool aNotify);
+                                  const nsAttrValue* aValue, bool aNotify);
 
     virtual void UpdateEditableState(bool aNotify);
 
     virtual bool ParseAttribute(PRInt32 aNamespaceID,
                                   nsIAtom* aAttribute,
                                   const nsAString& aValue,
                                   nsAttrValue& aResult);
 
@@ -651,17 +651,17 @@ protected:
     void AddListenerFor(const nsAttrName& aName,
                         bool aCompileEventHandlers);
     void MaybeAddPopupListener(nsIAtom* aLocalName);
 
     nsIWidget* GetWindowWidget();
 
     // attribute setters for widget
     nsresult HideWindowChrome(bool aShouldHide);
-    void SetChromeMargins(const nsAString* aValue);
+    void SetChromeMargins(const nsAttrValue* aValue);
     void ResetChromeMargins();
     void SetTitlebarColor(nscolor aColor, bool aActive);
 
     void SetDrawsInTitlebar(bool aState);
 
     const nsAttrName* InternalGetExistingAttrNameFromQName(const nsAString& aStr) const;
 
     void RemoveBroadcaster(const nsAString & broadcasterId);