Bug 557087 (2/6) - Make the content aware of the new disabled state rule. r+a=sicking
authorMounir Lamouri <mounir.lamouri@gmail.com>
Sat, 18 Sep 2010 23:33:16 +0200
changeset 54342 b15d9c989201e77fdf2103fbf46fd3168f32a806
parent 54341 61050f17467da752486526bd4de3edb7b1752de6
child 54343 a89e21dcff9a6766a54ee9a16042965b53f2fec6
push id15858
push usermlamouri@mozilla.com
push dateMon, 20 Sep 2010 03:35:23 +0000
treeherdermozilla-central@8b47f3cabf9f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs557087
milestone2.0b7pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 557087 (2/6) - Make the content aware of the new disabled state rule. r+a=sicking
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/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLInputElement.h
content/html/content/src/nsHTMLLabelElement.cpp
content/html/content/src/nsHTMLObjectElement.cpp
content/html/content/src/nsHTMLOptGroupElement.cpp
content/html/content/src/nsHTMLOptionElement.cpp
content/html/content/src/nsHTMLOutputElement.cpp
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLSelectElement.h
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/content/src/nsTextEditorState.cpp
content/html/content/test/Makefile.in
content/html/content/test/test_bug430351.html
content/html/content/test/test_bug557087-2.html
content/html/content/test/test_bug557087-3.html
content/html/content/test/test_bug557087-4.html
content/html/content/test/test_bug557087-5.html
content/html/content/test/test_bug557087-6.html
layout/reftests/css-disabled/button/button-fieldset-1.html
layout/reftests/css-disabled/button/button-fieldset-2.html
layout/reftests/css-disabled/button/button-fieldset-3.html
layout/reftests/css-disabled/button/button-fieldset-4.html
layout/reftests/css-disabled/button/button-fieldset-ref.html
layout/reftests/css-disabled/button/reftest.list
layout/reftests/css-disabled/button/style.css
layout/reftests/css-disabled/fieldset/fieldset-fieldset-1.html
layout/reftests/css-disabled/fieldset/fieldset-fieldset-2.html
layout/reftests/css-disabled/fieldset/fieldset-fieldset-3.html
layout/reftests/css-disabled/fieldset/fieldset-fieldset-4.html
layout/reftests/css-disabled/fieldset/fieldset-fieldset-ref.html
layout/reftests/css-disabled/fieldset/reftest.list
layout/reftests/css-disabled/fieldset/style.css
layout/reftests/css-disabled/input/input-fieldset-1.html
layout/reftests/css-disabled/input/input-fieldset-2.html
layout/reftests/css-disabled/input/input-fieldset-3.html
layout/reftests/css-disabled/input/input-fieldset-4.html
layout/reftests/css-disabled/input/input-fieldset-ref.html
layout/reftests/css-disabled/input/reftest.list
layout/reftests/css-disabled/input/style.css
layout/reftests/css-disabled/label/label-ref.html
layout/reftests/css-disabled/label/label.html
layout/reftests/css-disabled/label/reftest.list
layout/reftests/css-disabled/label/style.css
layout/reftests/css-disabled/object/object-ref.html
layout/reftests/css-disabled/object/object.html
layout/reftests/css-disabled/object/reftest.list
layout/reftests/css-disabled/object/style.css
layout/reftests/css-disabled/output/output-ref.html
layout/reftests/css-disabled/output/output.html
layout/reftests/css-disabled/output/reftest.list
layout/reftests/css-disabled/output/style.css
layout/reftests/css-disabled/reftest.list
layout/reftests/css-disabled/select/reftest.list
layout/reftests/css-disabled/select/select-fieldset-1.html
layout/reftests/css-disabled/select/select-fieldset-2.html
layout/reftests/css-disabled/select/select-fieldset-3.html
layout/reftests/css-disabled/select/select-fieldset-4.html
layout/reftests/css-disabled/select/select-fieldset-ref.html
layout/reftests/css-disabled/select/style.css
layout/reftests/css-disabled/textarea/reftest.list
layout/reftests/css-disabled/textarea/style.css
layout/reftests/css-disabled/textarea/textarea-fieldset-1.html
layout/reftests/css-disabled/textarea/textarea-fieldset-2.html
layout/reftests/css-disabled/textarea/textarea-fieldset-3.html
layout/reftests/css-disabled/textarea/textarea-fieldset-4.html
layout/reftests/css-disabled/textarea/textarea-fieldset-ref.html
layout/reftests/css-enabled/button/button-fieldset-1.html
layout/reftests/css-enabled/button/button-fieldset-2.html
layout/reftests/css-enabled/button/button-fieldset-3.html
layout/reftests/css-enabled/button/button-fieldset-4.html
layout/reftests/css-enabled/button/button-fieldset-ref.html
layout/reftests/css-enabled/button/reftest.list
layout/reftests/css-enabled/button/style.css
layout/reftests/css-enabled/fieldset/fieldset-fieldset-1.html
layout/reftests/css-enabled/fieldset/fieldset-fieldset-2.html
layout/reftests/css-enabled/fieldset/fieldset-fieldset-3.html
layout/reftests/css-enabled/fieldset/fieldset-fieldset-4.html
layout/reftests/css-enabled/fieldset/fieldset-fieldset-ref.html
layout/reftests/css-enabled/fieldset/reftest.list
layout/reftests/css-enabled/input/input-fieldset-1.html
layout/reftests/css-enabled/input/input-fieldset-2.html
layout/reftests/css-enabled/input/input-fieldset-3.html
layout/reftests/css-enabled/input/input-fieldset-4.html
layout/reftests/css-enabled/input/input-fieldset-ref.html
layout/reftests/css-enabled/input/reftest.list
layout/reftests/css-enabled/input/style.css
layout/reftests/css-enabled/label/label-ref.html
layout/reftests/css-enabled/label/label.html
layout/reftests/css-enabled/label/reftest.list
layout/reftests/css-enabled/label/style.css
layout/reftests/css-enabled/object/object-ref.html
layout/reftests/css-enabled/object/object.html
layout/reftests/css-enabled/object/reftest.list
layout/reftests/css-enabled/object/style.css
layout/reftests/css-enabled/optgroup/optgroup-fieldset-1.html
layout/reftests/css-enabled/optgroup/optgroup-fieldset-ref.html
layout/reftests/css-enabled/optgroup/reftest.list
layout/reftests/css-enabled/optgroup/style.css
layout/reftests/css-enabled/option/option-fieldset-1.html
layout/reftests/css-enabled/option/option-fieldset-ref.html
layout/reftests/css-enabled/option/reftest.list
layout/reftests/css-enabled/option/style.css
layout/reftests/css-enabled/output/output-ref.html
layout/reftests/css-enabled/output/output.html
layout/reftests/css-enabled/output/reftest.list
layout/reftests/css-enabled/output/style.css
layout/reftests/css-enabled/reftest.list
layout/reftests/css-enabled/select/reftest.list
layout/reftests/css-enabled/select/select-fieldset-1.html
layout/reftests/css-enabled/select/select-fieldset-2.html
layout/reftests/css-enabled/select/select-fieldset-3.html
layout/reftests/css-enabled/select/select-fieldset-4.html
layout/reftests/css-enabled/select/select-fieldset-ref.html
layout/reftests/css-enabled/select/style.css
layout/reftests/css-enabled/textarea/reftest.list
layout/reftests/css-enabled/textarea/style.css
layout/reftests/css-enabled/textarea/textarea-fieldset-1.html
layout/reftests/css-enabled/textarea/textarea-fieldset-2.html
layout/reftests/css-enabled/textarea/textarea-fieldset-3.html
layout/reftests/css-enabled/textarea/textarea-fieldset-4.html
layout/reftests/css-enabled/textarea/textarea-fieldset-ref.html
layout/reftests/css-invalid/button/button-disabled-fieldset-1.html
layout/reftests/css-invalid/button/button-disabled-fieldset-2.html
layout/reftests/css-invalid/button/button-fieldset-ref.html
layout/reftests/css-invalid/button/reftest.list
layout/reftests/css-invalid/input/input-disabled-fieldset-1.html
layout/reftests/css-invalid/input/input-disabled-fieldset-2.html
layout/reftests/css-invalid/input/input-fieldset-ref.html
layout/reftests/css-invalid/input/reftest.list
layout/reftests/css-invalid/select/reftest.list
layout/reftests/css-invalid/select/select-disabled-fieldset-1.html
layout/reftests/css-invalid/select/select-disabled-fieldset-2.html
layout/reftests/css-invalid/select/select-fieldset-ref.html
layout/reftests/css-invalid/textarea/reftest.list
layout/reftests/css-invalid/textarea/textarea-disabled-fieldset-1.html
layout/reftests/css-invalid/textarea/textarea-disabled-fieldset-2.html
layout/reftests/css-invalid/textarea/textarea-fieldset-ref.html
layout/reftests/css-valid/button/button-disabled-fieldset-1.html
layout/reftests/css-valid/button/button-disabled-fieldset-2.html
layout/reftests/css-valid/button/button-fieldset-ref.html
layout/reftests/css-valid/button/reftest.list
layout/reftests/css-valid/input/input-disabled-fieldset-1.html
layout/reftests/css-valid/input/input-disabled-fieldset-2.html
layout/reftests/css-valid/input/input-fieldset-ref.html
layout/reftests/css-valid/input/reftest.list
layout/reftests/css-valid/select/reftest.list
layout/reftests/css-valid/select/select-disabled-fieldset-1.html
layout/reftests/css-valid/select/select-disabled-fieldset-2.html
layout/reftests/css-valid/select/select-fieldset-ref.html
layout/reftests/css-valid/textarea/reftest.list
layout/reftests/css-valid/textarea/textarea-disabled-fieldset-1.html
layout/reftests/css-valid/textarea/textarea-disabled-fieldset-2.html
layout/reftests/css-valid/textarea/textarea-fieldset-ref.html
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2307,25 +2307,26 @@ nsGenericHTMLElement::GetIsContentEditab
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 
 NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLFrameElement, TabIndex, tabindex, 0)
 
 nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-  : nsGenericHTMLElement(aNodeInfo),
-    mForm(nsnull)
+  : nsGenericHTMLElement(aNodeInfo)
+  , mForm(nsnull)
+  , mFieldSet(nsnull)
 {
 }
 
 nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
 {
   // Check that this element doesn't know anything about its form at this point.
-  NS_ASSERTION(!mForm, "How did we get here?");
+  NS_ASSERTION(!mForm, "mForm should be null at this point!");
 }
 
 NS_IMPL_QUERY_INTERFACE_INHERITED1(nsGenericHTMLFormElement,
                                    nsGenericHTMLElement,
                                    nsIFormControl)
 
 PRBool
 nsGenericHTMLFormElement::IsNodeOfType(PRUint32 aFlags) const
@@ -2489,16 +2490,19 @@ nsGenericHTMLFormElement::BindToTree(nsI
   // wouldn't be possible to find a form ancestor.
   // We should not call UpdateFormOwner if none of these conditions are
   // fulfilled.
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? !!GetCurrentDoc()
                                                   : !!aParent) {
     UpdateFormOwner(true, nsnull);
   }
 
+  // Set parent fieldset which should be used for the disabled state.
+  UpdateFieldSet();
+
   return NS_OK;
 }
 
 void
 nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   // Save state before doing anything
   SaveState();
@@ -2522,16 +2526,19 @@ nsGenericHTMLFormElement::UnbindFromTree
   // We have to remove the form id observer if there was one.
   // We will re-add one later if needed (during bind to tree).
   if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
                                       nsGkAtoms::form)) {
     RemoveFormIdObserver();
   }
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+
+  // The element might not have a fieldset anymore.
+  UpdateFieldSet();
 }
 
 nsresult
 nsGenericHTMLFormElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                         const nsAString* aValue, PRBool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     nsAutoString tmp;
@@ -2754,19 +2761,17 @@ nsGenericHTMLFormElement::IntrinsicState
 {
   // If you add attribute-dependent states here, you need to add them them to
   // AfterSetAttr too.  And add them to AfterSetAttr for all subclasses that
   // implement IntrinsicState() and are affected by that attribute.
   PRInt32 state = nsGenericHTMLElement::IntrinsicState();
 
   if (CanBeDisabled()) {
     // :enabled/:disabled
-    PRBool disabled;
-    GetBoolAttr(nsGkAtoms::disabled, &disabled);
-    if (disabled) {
+    if (IsDisabled()) {
       state |= NS_EVENT_STATE_DISABLED;
       state &= ~NS_EVENT_STATE_ENABLED;
     } else {
       state &= ~NS_EVENT_STATE_DISABLED;
       state |= NS_EVENT_STATE_ENABLED;
     }
   }
   
@@ -2784,17 +2789,17 @@ nsGenericHTMLFormElement::FocusTristate
 nsGenericHTMLFormElement::FocusState()
 {
   // We can't be focused if we aren't in a document
   nsIDocument* doc = GetCurrentDoc();
   if (!doc)
     return eUnfocusable;
 
   // first see if we are disabled or not. If disabled then do nothing.
-  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
+  if (IsDisabled()) {
     return eUnfocusable;
   }
 
   // If the window is not active, do not allow the focus to bring the
   // window to the front.  We update the focus controller, but do
   // nothing else.
   nsPIDOMWindow* win = doc->GetWindow();
   if (win) {
@@ -2941,16 +2946,43 @@ nsGenericHTMLFormElement::UpdateFormOwne
     }
 
     if (!idVal.IsEmpty()) {
       mForm->AddElementToTable(this, idVal);
     }
   }
 }
 
+void
+nsGenericHTMLFormElement::UpdateFieldSet()
+{
+  for (nsIContent* parent = GetParent(); parent; parent = parent->GetParent()) {
+    if (parent->IsHTML(nsGkAtoms::fieldset)) {
+      mFieldSet = static_cast<nsGenericHTMLFormElement*>(parent);
+      return;
+    }
+  }
+
+  // No fieldset found.
+  mFieldSet = nsnull;
+}
+
+void
+nsGenericHTMLFormElement::OnFieldSetDisabledChanged(PRInt32 aStates)
+{
+  aStates |= NS_EVENT_STATE_DISABLED | NS_EVENT_STATE_ENABLED;
+
+  nsIDocument* doc = GetCurrentDoc();
+  // TODO: should we use aNotify ?!
+  if (doc) {
+    MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
+    doc->ContentStatesChanged(this, nsnull, aStates);
+  }
+}
+
 //----------------------------------------------------------------------
 
 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
 {
   if (mFrameLoader) {
     mFrameLoader->Destroy();
   }
 }
@@ -3222,17 +3254,17 @@ nsGenericHTMLElement::IsHTMLFocusable(PR
       // contentEditable roots.
       tabIndex = 0;
     }
   }
   else {
     override = PR_FALSE;
 
     // Just check for disabled attribute on form controls
-    disabled = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+    disabled = IsDisabled();
     if (disabled) {
       tabIndex = -1;
     }
   }
 
   if (aTabIndex) {
     *aTabIndex = tabIndex;
   }
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -516,16 +516,23 @@ public:
    * @param aType     the name of the attribute.
    * @param aDefault  the default value if the attribute is missing or invalid.
    * @param aResult   string corresponding to the value [out].
    */
   NS_HIDDEN_(nsresult) GetEnumAttr(nsIAtom* aAttr,
                                    const char* aDefault,
                                    nsAString& aResult);
 
+  /**
+   * Returns the current disabled state of the element.
+   */
+  virtual bool IsDisabled() const {
+    return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+  }
+
 protected:
   /**
    * Add/remove this element to the documents name cache
    */
   void AddToNameTable(nsIAtom* aName) {
     NS_ASSERTION(HasFlag(NODE_HAS_NAME), "Node lacking NODE_HAS_NAME flag");
     nsIDocument* doc = GetCurrentDoc();
     if (doc && !IsInAnonymousSubtree()) {
@@ -838,16 +845,32 @@ public:
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
   virtual PRUint32 GetDesiredIMEState();
   virtual PRInt32 IntrinsicState() const;
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
+  virtual bool IsDisabled() const {
+    return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
+           (mFieldSet && mFieldSet->IsDisabled());
+  }
+
+  /**
+   * This callback is called by a fieldest on all it's elements whenever it's
+   * disabled attribute is changed so the element knows it's disabled state
+   * might have changed.
+   *
+   * @param aStates States for which a change should be notified.
+   * @note Classes redefining this method should not call ContentStatesChanged
+   * but they should pass aStates instead.
+   */
+  virtual void OnFieldSetDisabledChanged(PRInt32 aStates);
+
   /**
    * Returns if the control can be disabled.
    */
   PRBool CanBeDisabled() const;
 
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
@@ -876,16 +899,21 @@ protected:
    * with the id in @form. Otherwise, it *must* be null.
    *
    * @note Callers of UpdateFormOwner have to be sure the element is in a
    * document (GetCurrentDoc() != nsnull).
    */
   void UpdateFormOwner(bool aBindToTree, Element* aFormIdElement);
 
   /**
+   * This method will update mFieldset and set it to the first fieldset parent.
+   */
+  void UpdateFieldSet();
+
+  /**
    * Add a form id observer which will observe when the element with the id in
    * @form will change.
    *
    * @return The element associated with the current id in @form (may be null).
    */
   Element* AddFormIdObserver();
 
   /**
@@ -911,16 +939,19 @@ protected:
   };
 
   // Get our focus state.  If this returns eInactiveWindow, it will set this
   // element as the focused element for that window.
   FocusTristate FocusState();
 
   /** The form that contains this control */
   nsHTMLFormElement* mForm;
+
+  /* This is a pointer to our closest fieldset parent if any */
+  nsGenericHTMLFormElement* mFieldSet;
 };
 
 // If this flag is set on an nsGenericHTMLFormElement, that means that we have
 // added ourselves to our mForm.  It's possible to have a non-null mForm, but
 // not have this flag set.  That happens when the form is set via the content
 // sink.
 #define ADDED_TO_FORM (1 << ELEMENT_TYPE_SPECIFIC_BITS_OFFSET)
 
--- a/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/content/html/content/src/nsHTMLButtonElement.cpp
@@ -105,18 +105,23 @@ public:
 
   // overriden nsIFormControl methods
   NS_IMETHOD_(PRUint32) GetType() const { return mType; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   PRBool RestoreState(nsPresState* aState);
 
+  virtual void OnFieldSetDisabledChanged(PRInt32 aStates);
+
   PRInt32 IntrinsicState() const;
 
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                               nsIContent* aBindingParent,
+                               PRBool aCompileEventHandlers);
   /**
    * Called when an attribute is about to be changed
    */
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
   /**
    * Called when an attribute has just been changed
    */
@@ -279,17 +284,17 @@ nsHTMLButtonElement::IsHTMLFocusable(PRB
   if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
     return PR_TRUE;
   }
 
   *aIsFocusable = 
 #ifdef XP_MACOSX
     (!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
 #endif
-    !HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+    !IsDisabled();
 
   return PR_FALSE;
 }
 
 PRBool
 nsHTMLButtonElement::ParseAttribute(PRInt32 aNamespaceID,
                                     nsIAtom* aAttribute,
                                     const nsAString& aValue,
@@ -321,20 +326,18 @@ nsHTMLButtonElement::ParseAttribute(PRIn
                                               aResult);
 }
 
 nsresult
 nsHTMLButtonElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   // Do not process any DOM events if the element is disabled
   aVisitor.mCanHandle = PR_FALSE;
-  PRBool bDisabled;
-  nsresult rv = GetDisabled(&bDisabled);
-  if (NS_FAILED(rv) || bDisabled) {
-    return rv;
+  if (IsDisabled()) {
+    return NS_OK;
   }
 
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
 
   if (formControlFrame) {
     nsIFrame* formFrame = do_QueryFrame(formControlFrame);
     if (formFrame) {
       const nsStyleUserInterface* uiStyle = formFrame->GetStyleUserInterface();
@@ -559,23 +562,19 @@ nsHTMLButtonElement::SubmitNamesValues(n
 
   //
   // We only submit if we were the button pressed
   //
   if (aFormSubmission->GetOriginatingElement() != this) {
     return NS_OK;
   }
 
-  //
   // Disabled elements don't submit
-  //
-  PRBool disabled;
-  rv = GetDisabled(&disabled);
-  if (NS_FAILED(rv) || disabled) {
-    return rv;
+  if (IsDisabled()) {
+    return NS_OK;
   }
 
   //
   // Get the name (if no name, no submit)
   //
   nsAutoString name;
   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
   if (name.IsEmpty()) {
@@ -602,16 +601,33 @@ nsHTMLButtonElement::SubmitNamesValues(n
 void
 nsHTMLButtonElement::DoneCreatingElement()
 {
   // Restore state as needed.
   RestoreFormControlState(this, this);
 }
 
 nsresult
+nsHTMLButtonElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                nsIContent* aBindingParent,
+                                PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
+                                                     aBindingParent,
+                                                     aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If there is a disabled fieldset in the parent chain, the element is now
+  // barred from constraint validation.
+  UpdateBarredFromConstraintValidation();
+
+  return rv;
+}
+
+nsresult
 nsHTMLButtonElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                    const nsAString* aValue, PRBool aNotify)
 {
   if (aNotify && aName == nsGkAtoms::disabled &&
       aNameSpaceID == kNameSpaceID_None) {
     mDisabledChanged = PR_TRUE;
   }
 
@@ -657,19 +673,19 @@ nsHTMLButtonElement::SaveState()
 {
   if (!mDisabledChanged) {
     return NS_OK;
   }
   
   nsPresState *state = nsnull;
   nsresult rv = GetPrimaryPresState(this, &state);
   if (state) {
-    PRBool disabled;
-    GetDisabled(&disabled);
-    state->SetDisabled(disabled);
+    // We do not want to save the real disabled state but the disabled
+    // attribute.
+    state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
   }
 
   return rv;
 }
 
 PRBool
 nsHTMLButtonElement::RestoreState(nsPresState* aState)
 {
@@ -713,12 +729,20 @@ nsHTMLButtonElement::SetCustomValidity(c
   return NS_OK;
 }
 
 void
 nsHTMLButtonElement::UpdateBarredFromConstraintValidation()
 {
   SetBarredFromConstraintValidation(mType == NS_FORM_BUTTON_BUTTON ||
                                     mType == NS_FORM_BUTTON_RESET ||
-                                    HasAttr(kNameSpaceID_None,
-                                            nsGkAtoms::disabled));
+                                    IsDisabled());
 }
 
+void
+nsHTMLButtonElement::OnFieldSetDisabledChanged(PRInt32 aStates)
+{
+  UpdateBarredFromConstraintValidation();
+
+  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID;
+  nsGenericHTMLFormElement::OnFieldSetDisabledChanged(aStates);
+}
+
--- a/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -67,16 +67,18 @@ public:
   // nsIDOMHTMLElement
   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLFormElement::)
 
   // nsIDOMHTMLFieldSetElement
   NS_DECL_NSIDOMHTMLFIELDSETELEMENT
 
   // nsIContent
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
+  virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                                const nsAString* aValue, PRBool aNotify);
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_FIELDSET; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
 
@@ -95,16 +97,17 @@ private:
 // construction, destruction
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(FieldSet)
 
 
 nsHTMLFieldSetElement::nsHTMLFieldSetElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLFormElement(aNodeInfo)
+  , mElements(nsnull)
 {
   // <fieldset> is always barred from constraint validation.
   SetBarredFromConstraintValidation(PR_TRUE);
 }
 
 nsHTMLFieldSetElement::~nsHTMLFieldSetElement()
 {
 }
@@ -145,23 +148,45 @@ NS_IMPL_STRING_ATTR(nsHTMLFieldSetElemen
 NS_IMPL_NSICONSTRAINTVALIDATION(nsHTMLFieldSetElement)
 
 // nsIContent
 nsresult
 nsHTMLFieldSetElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   // Do not process any DOM events if the element is disabled.
   aVisitor.mCanHandle = PR_FALSE;
-  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
+  if (IsDisabled()) {
     return NS_OK;
   }
 
   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
 }
 
+nsresult
+nsHTMLFieldSetElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                                    const nsAString* aValue, PRBool aNotify)
+{
+  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled &&
+      nsINode::GetFirstChild()) {
+    if (!mElements) {
+      mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
+                                    PR_TRUE);
+    }
+
+    PRUint32 length = mElements->Length(PR_TRUE);
+    for (PRUint32 i=0; i<length; ++i) {
+      static_cast<nsGenericHTMLFormElement*>(mElements->GetNodeAt(i))
+        ->OnFieldSetDisabledChanged(0);
+    }
+  }
+
+  return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
+                                                aValue, aNotify);
+}
+
 // nsIDOMHTMLFieldSetElement
 
 NS_IMETHODIMP
 nsHTMLFieldSetElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
   return nsGenericHTMLFormElement::GetForm(aForm);
 }
 
@@ -180,21 +205,21 @@ nsHTMLFieldSetElement::MatchListedElemen
   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aContent);
   return formControl && formControl->GetType() != NS_FORM_LABEL;
 }
 
 NS_IMETHODIMP
 nsHTMLFieldSetElement::GetElements(nsIDOMHTMLCollection** aElements)
 {
   if (!mElements) {
-    mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull, PR_TRUE);
+    mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
+                                  PR_TRUE);
   }
 
   NS_ADDREF(*aElements = mElements);
-
   return NS_OK;
 }
 
 // nsIFormControl
 
 nsresult
 nsHTMLFieldSetElement::Reset()
 {
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1826,17 +1826,17 @@ nsHTMLInputElement::Click()
 {
   nsresult rv = NS_OK;
 
   if (GET_BOOLBIT(mBitField, BF_HANDLING_CLICK)) // Fixes crash as in bug 41599
       return rv;                      // --heikki@netscape.com
 
   // first see if we are disabled or not. If disabled then do nothing.
   nsAutoString disabled;
-  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
+  if (IsDisabled()) {
     return NS_OK;
   }
 
   // see what type of input we are.  Only click button, checkbox, radio,
   // reset, submit, & image
   if (mType == NS_FORM_INPUT_BUTTON   ||
       mType == NS_FORM_INPUT_CHECKBOX ||
       mType == NS_FORM_INPUT_RADIO    ||
@@ -1920,23 +1920,20 @@ nsHTMLInputElement::NeedToInitializeEdit
   return PR_FALSE;
 }
 
 nsresult
 nsHTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   // Do not process any DOM events if the element is disabled
   aVisitor.mCanHandle = PR_FALSE;
-  PRBool disabled;
-  nsresult rv = GetDisabled(&disabled);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (disabled) {
+  if (IsDisabled()) {
     return NS_OK;
   }
-  
+
   // For some reason or another we also need to check if the style shows us
   // as disabled.
   {
     nsIFrame* frame = GetPrimaryFrame();
     if (frame) {
       const nsStyleUserInterface* uiStyle = frame->GetStyleUserInterface();
 
       if (uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
@@ -2510,16 +2507,21 @@ nsHTMLInputElement::BindToTree(nsIDocume
   if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
     AddedToRadioGroup();
   }
 
   // An element can't suffer from value missing if it is not in a document.
   // We have to check if we suffer from that as we are now in a document.
   UpdateValueMissingValidityState();
 
+  // If there is a disabled fieldset in the parent chain, the element is now
+  // barred from constraint validation and can't suffer from value missing
+  // (call done before).
+  UpdateBarredFromConstraintValidation();
+
   return rv;
 }
 
 void
 nsHTMLInputElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   // If we have a form and are unbound from it,
   // nsGenericHTMLFormElement::UnbindFromTree() will unset the form and
@@ -2530,16 +2532,18 @@ nsHTMLInputElement::UnbindFromTree(PRBoo
     WillRemoveFromRadioGroup(PR_FALSE);
   }
 
   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
 
   // GetCurrentDoc is returning nsnull so we can update the value
   // missing validity state to reflect we are no longer into a doc.
   UpdateValueMissingValidityState();
+  // We might be no longer disabled because of parent chain changed.
+  UpdateBarredFromConstraintValidation();
 }
 
 void
 nsHTMLInputElement::HandleTypeChange(PRUint8 aNewType)
 {
   ValueModeType aOldValueMode = GetValueMode();
   nsAutoString aOldValue;
   GetValue(aOldValue);
@@ -2994,19 +2998,17 @@ nsHTMLInputElement::SubmitNamesValues(ns
 {
   nsresult rv = NS_OK;
 
   // Disabled elements don't submit
   // For type=reset, and type=button, we just never submit, period.
   // For type=image and type=button, we only submit if we were the button
   // pressed
   // For type=radio and type=checkbox, we only submit if checked=true
-  PRBool disabled;
-  rv = GetDisabled(&disabled);
-  if (disabled || mType == NS_FORM_INPUT_RESET ||
+  if (IsDisabled() || mType == NS_FORM_INPUT_RESET ||
       mType == NS_FORM_INPUT_BUTTON ||
       ((mType == NS_FORM_INPUT_SUBMIT || mType == NS_FORM_INPUT_IMAGE) &&
        aFormSubmission->GetOriginatingElement() != this) ||
       ((mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX) &&
        !GetChecked())) {
     return NS_OK;
   }
 
@@ -3186,19 +3188,19 @@ nsHTMLInputElement::SaveState()
     if (state) {
       state->SetStateProperty(inputState);
     }
   }
 
   if (GET_BOOLBIT(mBitField, BF_DISABLED_CHANGED)) {
     rv |= GetPrimaryPresState(this, &state);
     if (state) {
-      PRBool disabled;
-      GetDisabled(&disabled);
-      state->SetDisabled(disabled);
+      // We do not want to save the real disabled state but the disabled
+      // attribute.
+      state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
     }
   }
 
   return rv;
 }
 
 void
 nsHTMLInputElement::DoneCreatingElement()
@@ -3462,17 +3464,17 @@ nsHTMLInputElement::WillRemoveFromRadioG
 
 PRBool
 nsHTMLInputElement::IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex)
 {
   if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
     return PR_TRUE;
   }
 
-  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
+  if (IsDisabled()) {
     *aIsFocusable = PR_FALSE;
     return PR_TRUE;
   }
 
   if (IsSingleLineTextControl(PR_FALSE)) {
     *aIsFocusable = PR_TRUE;
     return PR_FALSE;
   }
@@ -3586,18 +3588,17 @@ nsHTMLInputElement::GetValueMode() const
       return VALUE_MODE_VALUE;
 #endif // DEBUG
   }
 }
 
 PRBool
 nsHTMLInputElement::IsMutable() const
 {
-  return !HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) &&
-         GetCurrentDoc() &&
+  return !IsDisabled() && GetCurrentDoc() &&
          !(DoesReadOnlyApply() &&
            HasAttr(kNameSpaceID_None, nsGkAtoms::readonly));
 }
 
 PRBool
 nsHTMLInputElement::DoesReadOnlyApply() const
 {
   switch (mType)
@@ -3851,17 +3852,17 @@ nsHTMLInputElement::UpdateAllValiditySta
 
 void
 nsHTMLInputElement::UpdateBarredFromConstraintValidation()
 {
   SetBarredFromConstraintValidation(mType == NS_FORM_INPUT_HIDDEN ||
                                     mType == NS_FORM_INPUT_BUTTON ||
                                     mType == NS_FORM_INPUT_RESET ||
                                     HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
-                                    HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
+                                    IsDisabled());
 }
 
 nsresult
 nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
                                          ValidityStateType aType)
 {
   nsresult rv = NS_OK;
 
@@ -4371,8 +4372,18 @@ nsHTMLInputElement::OnValueChanged(PRBoo
     nsIDocument* doc = GetCurrentDoc();
     if (doc) {
       MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
       doc->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_MOZ_PLACEHOLDER);
     }
   }
 }
 
+void
+nsHTMLInputElement::OnFieldSetDisabledChanged(PRInt32 aStates)
+{
+  UpdateValueMissingValidityState();
+  UpdateBarredFromConstraintValidation();
+
+  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID;
+  nsGenericHTMLFormElement::OnFieldSetDisabledChanged(aStates);
+}
+
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -154,16 +154,18 @@ public:
   // Overriden nsIFormControl methods
   NS_IMETHOD_(PRUint32) GetType() const { return mType; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual PRBool RestoreState(nsPresState* aState);
   virtual PRBool AllowDrop();
 
+  virtual void OnFieldSetDisabledChanged(PRInt32 aStates);
+
   // nsIContent
   virtual PRBool IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRInt32 *aTabIndex);
 
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
--- a/content/html/content/src/nsHTMLLabelElement.cpp
+++ b/content/html/content/src/nsHTMLLabelElement.cpp
@@ -76,16 +76,18 @@ public:
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_LABEL; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
 
   NS_IMETHOD Focus();
 
+  virtual bool IsDisabled() const { return PR_FALSE; }
+
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
 
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
--- a/content/html/content/src/nsHTMLObjectElement.cpp
+++ b/content/html/content/src/nsHTMLObjectElement.cpp
@@ -106,16 +106,18 @@ public:
   NS_IMETHOD_(PRUint32) GetType() const
   {
     return NS_FORM_OBJECT;
   }
 
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission *aFormSubmission);
 
+  virtual bool IsDisabled() const { return PR_FALSE; }
+
   virtual nsresult DoneAddingChildren(PRBool aHaveNotified);
   virtual PRBool IsDoneAddingChildren();
 
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom *aAttribute,
                                 const nsAString &aValue,
                                 nsAttrValue &aResult);
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
--- a/content/html/content/src/nsHTMLOptGroupElement.cpp
+++ b/content/html/content/src/nsHTMLOptGroupElement.cpp
@@ -133,20 +133,18 @@ NS_IMPL_STRING_ATTR(nsHTMLOptGroupElemen
 
 
 nsresult
 nsHTMLOptGroupElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = PR_FALSE;
   // Do not process any DOM events if the element is disabled
   // XXXsmaug This is not the right thing to do. But what is?
-  PRBool disabled;
-  nsresult rv = GetDisabled(&disabled);
-  if (NS_FAILED(rv) || disabled) {
-    return rv;
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
+    return NS_OK;
   }
 
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
     const nsStyleUserInterface* uiStyle = frame->GetStyleUserInterface();
     if (uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
         uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED) {
       return NS_OK;
@@ -195,19 +193,18 @@ nsHTMLOptGroupElement::RemoveChildAt(PRU
   }
   return rv;
 }
 
 PRInt32
 nsHTMLOptGroupElement::IntrinsicState() const
 {
   PRInt32 state = nsGenericHTMLElement::IntrinsicState();
-  PRBool disabled;
-  GetBoolAttr(nsGkAtoms::disabled, &disabled);
-  if (disabled) {
+
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
     state |= NS_EVENT_STATE_DISABLED;
     state &= ~NS_EVENT_STATE_ENABLED;
   } else {
     state &= ~NS_EVENT_STATE_DISABLED;
     state |= NS_EVENT_STATE_ENABLED;
   }
 
   return state;
--- a/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/content/html/content/src/nsHTMLOptionElement.cpp
@@ -352,19 +352,17 @@ nsHTMLOptionElement::IntrinsicState() co
   }
 
   // Also calling a non-const interface method (for :default)
   const_cast<nsHTMLOptionElement*>(this)->GetDefaultSelected(&selected);
   if (selected) {
     state |= NS_EVENT_STATE_DEFAULT;
   }
 
-  PRBool disabled;
-  GetBoolAttr(nsGkAtoms::disabled, &disabled);
-  if (disabled) {
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
     state |= NS_EVENT_STATE_DISABLED;
     state &= ~NS_EVENT_STATE_ENABLED;
   } else {
     state &= ~NS_EVENT_STATE_DISABLED;
     state |= NS_EVENT_STATE_ENABLED;
   }
 
   return state;
--- a/content/html/content/src/nsHTMLOutputElement.cpp
+++ b/content/html/content/src/nsHTMLOutputElement.cpp
@@ -69,16 +69,18 @@ public:
   // nsIDOMHTMLOutputElement
   NS_DECL_NSIDOMHTMLOUTPUTELEMENT
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_OUTPUT; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
 
+  virtual bool IsDisabled() const { return PR_FALSE; }
+
   nsresult Clone(nsINodeInfo* aNodeInfo, nsINode** aResult) const;
 
   PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
                         const nsAString& aValue, nsAttrValue& aResult);
 
   // This function is called when a callback function from nsIMutationObserver
   // has to be used to update the defaultValue attribute.
   void DescendantsChanged();
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -916,22 +916,18 @@ nsHTMLSelectElement::SetOptionsSelectedB
 #endif
   if (aChangedSomething) {
     *aChangedSomething = PR_FALSE;
   }
 
   nsresult rv;
 
   // Don't bother if the select is disabled
-  if (!aSetDisabled) {
-    PRBool selectIsDisabled = PR_FALSE;
-    rv = GetDisabled(&selectIsDisabled);
-    if (NS_SUCCEEDED(rv) && selectIsDisabled) {
-      return NS_OK;
-    }
+  if (!aSetDisabled && IsDisabled()) {
+    return NS_OK;
   }
 
   // Don't bother if there are no options
   PRUint32 numItems = 0;
   GetLength(&numItems);
   if (numItems == 0) {
     return NS_OK;
   }
@@ -1250,17 +1246,17 @@ nsHTMLSelectElement::Focus()
 PRBool
 nsHTMLSelectElement::IsHTMLFocusable(PRBool aWithMouse,
                                      PRBool *aIsFocusable, PRInt32 *aTabIndex)
 {
   if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
     return PR_TRUE;
   }
 
-  *aIsFocusable = !HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+  *aIsFocusable = !IsDisabled();
 
   return PR_FALSE;
 }
 
 NS_IMETHODIMP
 nsHTMLSelectElement::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
 {
   return mOptions->Item(aIndex, aReturn);
@@ -1304,16 +1300,33 @@ nsHTMLSelectElement::SelectSomething()
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
 nsresult
+nsHTMLSelectElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                nsIContent* aBindingParent,
+                                PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
+                                                     aBindingParent,
+                                                     aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If there is a disabled fieldset in the parent chain, the element is now
+  // barred from constraint validation.
+  UpdateBarredFromConstraintValidation();
+
+  return rv;
+}
+
+nsresult
 nsHTMLSelectElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                    const nsAString* aValue, PRBool aNotify)
 {
   if (aNotify && aName == nsGkAtoms::disabled &&
       aNameSpaceID == kNameSpaceID_None) {
     mDisabledChanged = PR_TRUE;
   }
 
@@ -1321,17 +1334,17 @@ nsHTMLSelectElement::BeforeSetAttr(PRInt
                                                  aValue, aNotify);
 }
 
 nsresult
 nsHTMLSelectElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                   const nsAString* aValue, PRBool aNotify)
 {
   if (aName == nsGkAtoms::disabled && aNameSpaceID == kNameSpaceID_None) {
-    SetBarredFromConstraintValidation(!!aValue);
+    UpdateBarredFromConstraintValidation();
     if (aNotify) {
       nsIDocument* doc = GetCurrentDoc();
       if (doc) {
         MOZ_AUTO_DOC_UPDATE(doc, UPDATE_CONTENT_STATE, PR_TRUE);
         doc->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_VALID |
                                                 NS_EVENT_STATE_INVALID);
       }
     }
@@ -1462,20 +1475,18 @@ nsHTMLSelectElement::GetAttributeMapping
 
 
 nsresult
 nsHTMLSelectElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = PR_FALSE;
   // Do not process any DOM events if the element is disabled
   // XXXsmaug This is not the right thing to do. But what is?
-  PRBool disabled;
-  nsresult rv = GetDisabled(&disabled);
-  if (NS_FAILED(rv) || disabled) {
-    return rv;
+  if (IsDisabled()) {
+    return NS_OK;
   }
 
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
   nsIFrame* formFrame = nsnull;
 
   if (formControlFrame &&
       (formFrame = do_QueryFrame(formControlFrame))) {
     const nsStyleUserInterface* uiStyle = formFrame->GetStyleUserInterface();
@@ -1528,19 +1539,19 @@ nsHTMLSelectElement::SaveState()
   }
 
   nsPresState *presState = nsnull;
   nsresult rv = GetPrimaryPresState(this, &presState);
   if (presState) {
     presState->SetStateProperty(state);
 
     if (mDisabledChanged) {
-      PRBool disabled;
-      GetDisabled(&disabled);
-      presState->SetDisabled(disabled);
+      // We do not want to save the real disabled state but the disabled
+      // attribute.
+      presState->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
     }
   }
 
   return rv;
 }
 
 PRBool
 nsHTMLSelectElement::RestoreState(nsPresState* aState)
@@ -1647,23 +1658,19 @@ nsHTMLSelectElement::Reset()
 
 static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
 
 NS_IMETHODIMP
 nsHTMLSelectElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
 {
   nsresult rv = NS_OK;
 
-  //
   // Disabled elements don't submit
-  //
-  PRBool disabled;
-  rv = GetDisabled(&disabled);
-  if (NS_FAILED(rv) || disabled) {
-    return rv;
+  if (IsDisabled()) {
+    return NS_OK;
   }
 
   //
   // Get the name (if no name, no submit)
   //
   nsAutoString name;
   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
   if (name.IsEmpty()) {
@@ -2088,8 +2095,24 @@ nsHTMLOptionCollection::Remove(PRInt32 a
 
   PRUint32 len = 0;
   mSelect->GetLength(&len);
   if (aIndex < 0 || (PRUint32)aIndex >= len)
     aIndex = 0;
 
   return mSelect->Remove(aIndex);
 }
+
+void
+nsHTMLSelectElement::UpdateBarredFromConstraintValidation()
+{
+  SetBarredFromConstraintValidation(IsDisabled());
+}
+
+void
+nsHTMLSelectElement::OnFieldSetDisabledChanged(PRInt32 aStates)
+{
+  UpdateBarredFromConstraintValidation();
+
+  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID;
+  nsGenericHTMLFormElement::OnFieldSetDisabledChanged(aStates);
+}
+
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -272,24 +272,29 @@ public:
 
   // Overriden nsIFormControl methods
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_SELECT; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual PRBool RestoreState(nsPresState* aState);
 
+  virtual void OnFieldSetDisabledChanged(PRInt32 aStates);
+
   PRInt32 IntrinsicState() const;
 
   // nsISelectElement
   NS_DECL_NSISELECTELEMENT
 
   /**
    * Called when an attribute is about to be changed
    */
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                               nsIContent* aBindingParent,
+                               PRBool aCompileEventHandlers);
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString* aValue, PRBool aNotify);
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
   
   virtual nsresult DoneAddingChildren(PRBool aHaveNotified);
@@ -315,16 +320,20 @@ public:
   }
 
   static nsHTMLSelectElement *FromSupports(nsISupports *aSupports)
   {
     return static_cast<nsHTMLSelectElement*>(static_cast<nsINode*>(aSupports));
   }
 
   virtual nsXPCClassInfo* GetClassInfo();
+
+  // nsIConstraintValidation
+  void UpdateBarredFromConstraintValidation();
+
 protected:
   friend class nsSafeOptionListMutation;
 
   // Helper Methods
   /**
    * Check whether the option specified by the index is selected
    * @param aIndex the index
    * @return whether the option at the index is selected
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -126,16 +126,18 @@ public:
 
   // nsIFormControl
   NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_TEXTAREA; }
   NS_IMETHOD Reset();
   NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission);
   NS_IMETHOD SaveState();
   virtual PRBool RestoreState(nsPresState* aState);
 
+  virtual void OnFieldSetDisabledChanged(PRInt32 aStates);
+
   virtual PRInt32 IntrinsicState() const;
 
   // nsITextControlElemet
   NS_IMETHOD SetValueChanged(PRBool aValueChanged);
   NS_IMETHOD_(PRBool) IsSingleLineTextControl() const;
   NS_IMETHOD_(PRBool) IsTextArea() const;
   NS_IMETHOD_(PRBool) IsPlainTextControl() const;
   NS_IMETHOD_(PRBool) IsPasswordTextControl() const;
@@ -155,16 +157,21 @@ public:
   NS_IMETHOD_(nsIContent*) GetRootEditorNode();
   NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
   NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify);
   NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
   NS_IMETHOD_(void) InitializeKeyboardEventListeners();
   NS_IMETHOD_(void) OnValueChanged(PRBool aNotify);
 
   // nsIContent
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                               nsIContent* aBindingParent,
+                               PRBool aCompileEventHandlers);
+  virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
+                              PRBool aNullParent = PR_TRUE);
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               PRInt32 aModType) const;
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
@@ -406,17 +413,17 @@ PRBool
 nsHTMLTextAreaElement::IsHTMLFocusable(PRBool aWithMouse,
                                        PRBool *aIsFocusable, PRInt32 *aTabIndex)
 {
   if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
     return PR_TRUE;
   }
 
   // disabled textareas are not focusable
-  *aIsFocusable = !HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
+  *aIsFocusable = !IsDisabled();
   return PR_FALSE;
 }
 
 NS_IMPL_STRING_ATTR(nsHTMLTextAreaElement, AccessKey, accesskey)
 NS_IMPL_BOOL_ATTR(nsHTMLTextAreaElement, Autofocus, autofocus)
 NS_IMPL_INT_ATTR(nsHTMLTextAreaElement, Cols, cols)
 NS_IMPL_BOOL_ATTR(nsHTMLTextAreaElement, Disabled, disabled)
 NS_IMPL_NON_NEGATIVE_INT_ATTR(nsHTMLTextAreaElement, MaxLength, maxlength)
@@ -638,20 +645,18 @@ nsHTMLTextAreaElement::GetAttributeMappi
   return &MapAttributesIntoRule;
 }
 
 nsresult
 nsHTMLTextAreaElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   // Do not process any DOM events if the element is disabled
   aVisitor.mCanHandle = PR_FALSE;
-  PRBool disabled;
-  nsresult rv = GetDisabled(&disabled);
-  if (NS_FAILED(rv) || disabled) {
-    return rv;
+  if (IsDisabled()) {
+    return NS_OK;
   }
 
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
   nsIFrame* formFrame = nsnull;
 
   if (formControlFrame &&
       (formFrame = do_QueryFrame(formControlFrame))) {
     const nsStyleUserInterface* uiStyle = formFrame->GetStyleUserInterface();
@@ -881,23 +886,19 @@ nsHTMLTextAreaElement::Reset()
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
 {
   nsresult rv = NS_OK;
 
-  //
   // Disabled elements don't submit
-  //
-  PRBool disabled;
-  rv = GetDisabled(&disabled);
-  if (NS_FAILED(rv) || disabled) {
-    return rv;
+  if (IsDisabled()) {
+    return NS_OK;
   }
 
   //
   // Get the name (if no name, no submit)
   //
   nsAutoString name;
   if (!GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
     return NS_OK;
@@ -946,19 +947,19 @@ nsHTMLTextAreaElement::SaveState()
     }
   }
 
   if (mDisabledChanged) {
     if (!state) {
       rv = GetPrimaryPresState(this, &state);
     }
     if (state) {
-      PRBool disabled;
-      GetDisabled(&disabled);
-      state->SetDisabled(disabled);
+      // We do not want to save the real disabled state but the disabled
+      // attribute.
+      state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
     }
   }
   return rv;
 }
 
 PRBool
 nsHTMLTextAreaElement::RestoreState(nsPresState* aState)
 {
@@ -1001,16 +1002,44 @@ nsHTMLTextAreaElement::IntrinsicState() 
       state |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
     }
   }
 
   return state;
 }
 
 nsresult
+nsHTMLTextAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                                  nsIContent* aBindingParent,
+                                  PRBool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
+                                                     aBindingParent,
+                                                     aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If there is a disabled fieldset in the parent chain, the element is now
+  // barred from constraint validation and can't suffer from value missing.
+  UpdateValueMissingValidityState();
+  UpdateBarredFromConstraintValidation();
+
+  return rv;
+}
+
+void
+nsHTMLTextAreaElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
+{
+  nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
+
+  // We might be no longer disabled because of parent chain changed.
+  UpdateValueMissingValidityState();
+  UpdateBarredFromConstraintValidation();
+}
+
+nsresult
 nsHTMLTextAreaElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                      const nsAString* aValue, PRBool aNotify)
 {
   if (aNotify && aName == nsGkAtoms::disabled &&
       aNameSpaceID == kNameSpaceID_None) {
     mDisabledChanged = PR_TRUE;
   }
 
@@ -1120,18 +1149,17 @@ nsHTMLTextAreaElement::CopyInnerTo(nsGen
     static_cast<nsHTMLTextAreaElement*>(aDest)->SetValue(value);
   }
   return NS_OK;
 }
 
 PRBool
 nsHTMLTextAreaElement::IsMutable() const
 {
-  return (!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) &&
-          !HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
+  return (!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) && !IsDisabled());
 }
 
 // nsIConstraintValidation
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::SetCustomValidity(const nsAString& aError)
 {
   nsIConstraintValidation::SetCustomValidity(aError);
@@ -1187,18 +1215,17 @@ nsHTMLTextAreaElement::UpdateValueMissin
   SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
 }
 
 void
 nsHTMLTextAreaElement::UpdateBarredFromConstraintValidation()
 {
   SetBarredFromConstraintValidation(HasAttr(kNameSpaceID_None,
                                             nsGkAtoms::readonly) ||
-                                    HasAttr(kNameSpaceID_None,
-                                            nsGkAtoms::disabled));
+                                    IsDisabled());
 }
 
 nsresult
 nsHTMLTextAreaElement::GetValidationMessage(nsAString& aValidationMessage,
                                             ValidityStateType aType)
 {
   nsresult rv = NS_OK;
 
@@ -1357,8 +1384,18 @@ nsHTMLTextAreaElement::OnValueChanged(PR
                                               // really needed but considering
                                               // we are already updating the
                                               // state for valid/invalid...
                                               NS_EVENT_STATE_MOZ_PLACEHOLDER);
     }
   }
 }
 
+void
+nsHTMLTextAreaElement::OnFieldSetDisabledChanged(PRInt32 aStates)
+{
+  UpdateValueMissingValidityState();
+  UpdateBarredFromConstraintValidation();
+
+  aStates |= NS_EVENT_STATE_VALID | NS_EVENT_STATE_INVALID;
+  nsGenericHTMLFormElement::OnFieldSetDisabledChanged(aStates);
+}
+
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1229,16 +1229,17 @@ nsTextEditorState::PrepareEditor(const n
     rv = newEditor->GetFlags(&editorFlags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Check if the readonly attribute is set.
     if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly))
       editorFlags |= nsIPlaintextEditor::eEditorReadonlyMask;
 
     // Check if the disabled attribute is set.
+    // TODO: call IsDisabled() here!
     if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) 
       editorFlags |= nsIPlaintextEditor::eEditorDisabledMask;
 
     // Disable the selection if necessary.
     if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
       mSelCon->SetDisplaySelection(nsISelectionController::SELECTION_OFF);
 
     newEditor->SetFlags(editorFlags);
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -225,12 +225,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug557628-2.html \
 		test_bug592802.html \
 		test_bug589696.html \
 		test_bug595429.html \
 		test_bug595447.html \
 		test_bug595449.html \
 		test_bug595457.html \
 		test_bug557087-1.html \
+		test_bug557087-2.html \
+		test_bug557087-3.html \
+		test_bug557087-4.html \
+		test_bug557087-5.html \
+		test_bug557087-6.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/html/content/test/test_bug430351.html
+++ b/content/html/content/test/test_bug430351.html
@@ -236,19 +236,16 @@ var nonFocusableElements = [
     "<input type=\"reset\" disabled>",
 
     "<input type=\"submit\" tabindex=\"0\" disabled>",
     "<input type=\"submit\" disabled>",
 
     "<input type=\"text\" tabindex=\"0\" disabled>",
     "<input type=\"text\" disabled>",
 
-    "<object tabindex=\"0\" disabled></object>",
-    "<object disabled></object>",
-
     "<select tabindex=\"0\" disabled></select>",
     "<select disabled></select>"
 ];
 
 var focusableInContentEditable = [
     "<button></button>",
     "<button tabindex=\"-1\"></button>",
     "<button tabindex=\"0\"></button>",
@@ -356,16 +353,20 @@ var focusableInContentEditable = [
     "<input type=\"text\" contenteditable=\"true\">",
 
     "<object></object>",
     "<object tabindex=\"-1\"></object>",
     "<object tabindex=\"0\"></object>",
     "<object tabindex=\"1\"></object>",
     "<object contenteditable=\"true\"></object>",
 
+    // Disabled doesn't work for <object>.
+    "<object tabindex=\"0\" disabled></object>",
+    "<object disabled></object>",
+
     "<select></select>",
     "<select tabindex=\"-1\"></select>",
     "<select tabindex=\"0\"></select>",
     "<select tabindex=\"1\"></select>",
     "<select contenteditable=\"true\"></select>"
 ];
 
 var focusableInDesignMode = [
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug557087-2.html
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=557087
+-->
+<head>
+  <title>Test for Bug 557087</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a>
+<p id="display"></p>
+<div id="content" style="display:none;">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 557087 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var elementsPreventingClick = [ "input", "button", "select", "textarea", "fieldset" ];
+var elementsWithClick = [ "option", "optgroup", "output", "label", "object" ];
+var gHandled = 0;
+
+function clickShouldNotHappenHandler(aEvent)
+{
+  aEvent.target.removeEventListener("click", clickShouldNotHappenHandler, false);
+  ok(false, "click event should be prevented! (test1)");
+  if (++gHandled >= elementsWithClick.length) {
+    test2();
+  }
+}
+
+function clickShouldNotHappenHandler2(aEvent)
+{
+  aEvent.target.removeEventListener("click", clickShouldNotHappenHandler3, false);
+  ok(false, "click event should be prevented! (test3)");
+  if (++gHandled >= elementsWithClick.length) {
+    test3();
+  }
+}
+
+function clickShouldHappenHandler(aEvent)
+{
+  aEvent.target.removeEventListener("click", clickShouldHappenHandler, false);
+  ok(true, "click event has been correctly received (test1)");
+  if (++gHandled >= elementsWithClick.length) {
+    test2();
+  }
+}
+
+function clickShouldHappenHandler2(aEvent)
+{
+  aEvent.target.removeEventListener("click", clickShouldHappenHandler2, false);
+  ok(true, "click event has been correctly received (test2)");
+  if (++gHandled >= elementsWithClick.length) {
+    test3();
+  }
+}
+
+function clickShouldHappenHandler3(aEvent)
+{
+  aEvent.target.removeEventListener("click", clickShouldHappenHandler3, false);
+  ok(true, "click event has been correctly received (test3)");
+  if (++gHandled >= (elementsWithClick.length +
+                     elementsPreventingClick.length)) {
+    SimpleTest.finish();
+  }
+}
+
+var fieldset1 = document.createElement("fieldset");
+var fieldset2 = document.createElement("fieldset");
+var content  = document.getElementById('content');
+fieldset1.disabled = true;
+content.appendChild(fieldset1);
+fieldset1.appendChild(fieldset2);
+
+function test1()
+{
+  gHandled = 0;
+
+  // Initialize children without click expected.
+  for each(var name in elementsPreventingClick) {
+    var element = document.createElement(name);
+    fieldset2.appendChild(element);
+    element.addEventListener("click", clickShouldNotHappenHandler, false);
+    sendMouseEvent({type:'click'}, element);
+  }
+
+  // Initialize children with click expected.
+  for each(var name in elementsWithClick) {
+    var element = document.createElement(name);
+    element.innerHTML = "foo";
+    fieldset2.appendChild(element);
+    element.addEventListener("click", clickShouldHappenHandler, false);
+    sendMouseEvent({type:'click'}, element);
+  }
+}
+
+function test2()
+{
+  gHandled = 0;
+  fieldset1.disabled = false;
+  fieldset2.disabled = true;
+
+  // Initialize children without click expected.
+  for each(var name in elementsPreventingClick) {
+    var element = document.createElement(name);
+    fieldset2.appendChild(element);
+    element.addEventListener("click", clickShouldNotHappenHandler2, false);
+    sendMouseEvent({type:'click'}, element);
+  }
+
+  // Initialize children with click expected.
+  for each(var name in elementsWithClick) {
+    var element = document.createElement(name);
+    element.innerHTML = "foo";
+    fieldset2.appendChild(element);
+    element.addEventListener("click", clickShouldHappenHandler2, false);
+    sendMouseEvent({type:'click'}, element);
+  }
+}
+
+function test3()
+{
+  gHandled = 0;
+  fieldset1.disabled = false;
+  fieldset2.disabled = false;
+
+  // All elements should accept the click.
+  for each(var name in elementsPreventingClick) {
+    var element = document.createElement(name);
+    fieldset2.appendChild(element);
+    element.addEventListener("click", clickShouldHappenHandler3, false);
+    sendMouseEvent({type:'click'}, element);
+  }
+
+  // Initialize children with click expected.
+  for each(var name in elementsWithClick) {
+    var element = document.createElement(name);
+    element.innerHTML = "foo";
+    fieldset2.appendChild(element);
+    element.addEventListener("click", clickShouldHappenHandler3, false);
+    sendMouseEvent({type:'click'}, element);
+  }
+}
+
+test1();
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug557087-3.html
@@ -0,0 +1,179 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=557087
+-->
+<head>
+  <title>Test for Bug 557087</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 557087 **/
+
+function checkValueMissing(aElement, aExpected)
+{
+  var msg = aExpected ? aElement.tagName + " should suffer from value missing"
+                      : aElement.tagName + " should not suffer from value missing"
+  is(aElement.validity.valueMissing, aExpected, msg);
+}
+
+function checkCandidateForConstraintValidation(aElement, aExpected)
+{
+  var msg = aExpected ? aElement.tagName + " should be candidate for constraint validation"
+                      : aElement.tagName + " should not be candidate for constraint validation"
+  is(aElement.willValidate, aExpected, msg);
+}
+
+function checkDisabledPseudoClass(aElement, aDisabled)
+{
+  var disabledElements = document.querySelectorAll(":disabled");
+  var found = false;
+
+  for each(var e in disabledElements) {
+    if (aElement == e) {
+      found = true;
+      break;
+    }
+  }
+
+  var msg = aDisabled ? aElement.tagName + " should have :disabled applying"
+                      : aElement.tagName + " should not have :disabled applying";
+  ok(aDisabled ? found : !found, msg);
+}
+
+function checkEnabledPseudoClass(aElement, aEnabled)
+{
+  var enabledElements = document.querySelectorAll(":enabled");
+  var found = false;
+
+  for each(var e in enabledElements) {
+    if (aElement == e) {
+      found = true;
+      break;
+    }
+  }
+
+  var msg = aEnabled ? aElement.tagName + " should have :enabled applying"
+                     : aElement.tagName + " should not have :enabled applying";
+  ok(aEnabled ? found : !found, msg);
+}
+
+function checkFocus(aElement, aExpected)
+{
+  aElement.setAttribute('tabindex', 1);
+
+  // We use the focus manager so we can test <label>.
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  var fm = Components.classes["@mozilla.org/focus-manager;1"]
+                     .getService(Components.interfaces.nsIFocusManager);
+  fm.setFocus(aElement, 0);
+
+  if (aExpected) {
+    is(document.activeElement, aElement, "element should be focused");
+  } else {
+    isnot(document.activeElement, aElement, "element should not be focused");
+  }
+
+  aElement.blur();
+  aElement.removeAttribute('tabindex');
+}
+
+var elements = [ "input", "button", "select", "textarea", "fieldset", "option",
+                 "optgroup", "label", "output", "object" ];
+
+var testData = {
+/* tag name | affected by disabled | test focus | test pseudo-classes | test willValidate */
+  "INPUT":    [ true,  true, true,  true,  true  ],
+  "BUTTON":   [ true,  true, true,  true,  false ],
+  "SELECT":   [ true,  true, true,  true,  false ],
+  "TEXTAREA": [ true,  true, true,  true,  true  ],
+  "FIELDSET": [ true,  true, true,  false, false ],
+  "OPTION":   [ false, true, true,  false, false ],
+  "OPTGROUP": [ false, true, true,  false, false ],
+  "OBJECT":   [ false, true, false, false, false ],
+  "LABEL":    [ false, true, false, false, false ],
+  "OUTPUT":   [ false, true, false, false, false ],
+};
+
+/**
+ * For not candidate elements without disabled attribute and not submittable,
+ * we only have to check that focus and click works even inside a disabled
+ * fieldset.
+ */
+function checkElement(aElement, aDisabled)
+{
+  var data = testData[aElement.tagName];
+  var expected = data[0] ? !aDisabled : true;
+
+  if (data[1]) {
+    checkFocus(aElement, expected);
+  }
+
+  if (data[2]) {
+    checkEnabledPseudoClass(aElement,  data[0] ? !aDisabled : true);
+    checkDisabledPseudoClass(aElement, data[0] ? aDisabled : false);
+  }
+
+  if (data[3]) {
+    checkCandidateForConstraintValidation(aElement, expected);
+  }
+
+  if (data[4]) {
+    checkValueMissing(aElement, expected);
+  }
+}
+
+var fieldset1 = document.createElement("fieldset");
+var fieldset2 = document.createElement("fieldset");
+var content  = document.getElementById('content');
+content.appendChild(fieldset1);
+fieldset1.appendChild(fieldset2);
+fieldset2.disabled = true;
+
+for each(var data in elements) {
+  var element = document.createElement(data);
+
+  if (data[4]) {
+    element.required = true;
+  }
+
+  fieldset2.appendChild(element);
+
+  checkElement(element, fieldset2.disabled);
+
+  // Make sure changes are correctly managed.
+  fieldset2.disabled = false;
+  checkElement(element, fieldset2.disabled);
+  fieldset2.disabled = true;
+  checkElement(element, fieldset2.disabled);
+
+  // Make sure if a fieldset which is not the first fieldset is disabled, the
+  // elements inside the second fielset are disabled.
+  fieldset2.disabled = false;
+  fieldset1.disabled = true;
+  checkElement(element, fieldset1.disabled);
+
+  // Make sure the state change of the inner fieldset will not confuse.
+  fieldset2.disabled = true;
+  fieldset2.disabled = false;
+  checkElement(element, fieldset1.disabled);
+
+  fieldset2.disabled = true;
+  fieldset1.disabled = false;
+  fieldset2.removeChild(element);
+}
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug557087-4.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=557087
+-->
+<head>
+  <title>Test for Bug 557087</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a>
+<p id="display"></p>
+<div id="content">
+  <iframe name='f'></iframe>
+  <form target='f' action="data:text/html">
+    <input type='text' id='a'>
+    <input type='checkbox' id='b'>
+    <input type='radio' id='c'>
+    <fieldset disabled>
+      <fieldset>
+        <input type='submit'>
+      </fieldset>
+    </fieldset>
+  </form>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 557087 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var gExpectedSubmits = 3;
+var gSubmitReceived = 0;
+var gEnd = false;
+
+var fieldsets = document.getElementsByTagName("fieldset");
+var form = document.forms[0];
+
+form.addEventListener("submit", function() {
+  ok(gEnd, gEnd ? "expected submit" : "non expected submit");
+  if (++gSubmitReceived >= gExpectedSubmits) {
+    form.removeEventListener("submit", arguments.callee, false);
+    SimpleTest.finish();
+  }
+}, false);
+
+var inputs = [
+  document.getElementById('a'),
+  document.getElementById('b'),
+  document.getElementById('c'),
+];
+
+function doSubmit()
+{
+  for each(e in inputs) {
+    e.focus();
+    synthesizeKey("VK_RETURN", {});
+  }
+}
+
+SimpleTest.waitForFocus(function() {
+  doSubmit();
+
+  fieldsets[1].disabled = true;
+  fieldsets[0].disabled = false;
+  doSubmit();
+
+  fieldsets[0].disabled = false;
+  fieldsets[1].disabled = false;
+
+  gEnd = true;
+  doSubmit();
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug557087-5.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=557087
+-->
+<head>
+  <title>Test for Bug 557087</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="runTest();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a>
+<p id="display"></p>
+<div id="content">
+  <iframe name='t'></iframe>
+  <form target='t' action="data:text/html,">
+    <fieldset disabled>
+      <fieldset>
+        <input name='i' value='i'>
+        <textarea name='t'>t</textarea>
+        <select name='s'><option>s</option></select>
+      </fieldset>
+    </fieldset>
+  </form>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 557087 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var testResults = [
+  "data:text/html,?",
+  "data:text/html,?",
+  "data:text/html,?i=i&t=t&s=s",
+];
+var gTestCount = 0;
+
+var form = document.forms[0];
+var iframe = document.getElementsByTagName('iframe')[0];
+var fieldsets = document.getElementsByTagName('fieldset');
+
+function runTest()
+{
+  iframe.addEventListener("load", function() {
+    is(iframe.contentWindow.location.href, testResults[gTestCount],
+       testResults[gTestCount] + " should have been loaded");
+
+    switch (++gTestCount) {
+      case 1:
+        fieldsets[1].disabled = true;
+        fieldsets[0].disabled = false;
+        form.submit();
+        SimpleTest.executeSoon(function() {
+          form.submit()
+        });
+        break;
+      case 2:
+        fieldsets[0].disabled = false;
+        fieldsets[1].disabled = false;
+        SimpleTest.executeSoon(function() {
+          form.submit()
+        });
+        break;
+      default:
+        iframe.removeEventListener("load", arguments.callee, false);
+        SimpleTest.executeSoon(SimpleTest.finish);
+    }
+  }, false);
+
+  form.submit();
+}
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug557087-6.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=557087
+-->
+<head>
+  <title>Test for Bug 557087</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <fieldset disabled>
+    <input>
+  </fieldset>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 557087 **/
+
+// Testing random stuff following review comments.
+
+var fieldset = document.getElementsByTagName("fieldset")[0];
+
+is(fieldset.elements.length, 1,
+   "there should be one element inside the fieldset");
+is(fieldset.elements[0], document.getElementsByTagName("input")[0],
+   "input should be the element inside the fieldset");
+
+document.body.removeChild(document.getElementById('content'));
+is(fieldset.querySelector("input:disabled"), fieldset.elements[0],
+   "the input should still be disabled");
+
+fieldset.disabled = false;
+is(fieldset.querySelector("input:enabled"), fieldset.elements[0],
+   "the input should be enabled");
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/button-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <button class="enabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/button-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <button class="disabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/button-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <button class="disabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/button-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <button class="enabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/button-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <button class="ref"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/reftest.list
@@ -0,0 +1,4 @@
+== button-fieldset-1.html button-fieldset-ref.html
+== button-fieldset-2.html button-fieldset-ref.html
+== button-fieldset-3.html button-fieldset-ref.html
+== button-fieldset-4.html button-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/button/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.disabled {
+  background-color: red;
+}
+
+:disabled.disabled {
+  background-color: green;
+}
+
+.enabled {
+  background-color: green;
+}
+
+:disabled.enabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/fieldset/fieldset-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <fieldset class="enabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/fieldset/fieldset-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <fieldset class="disabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/fieldset/fieldset-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <fieldset class="disabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/fieldset/fieldset-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <fieldset class="enabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/fieldset/fieldset-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <fieldset class="ref"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-disabled/fieldset/reftest.list
+++ b/layout/reftests/css-disabled/fieldset/reftest.list
@@ -1,2 +1,6 @@
 == fieldset-enabled.html fieldset-ref.html
 == fieldset-disabled.html fieldset-ref.html
+== fieldset-fieldset-1.html fieldset-fieldset-ref.html
+== fieldset-fieldset-2.html fieldset-fieldset-ref.html
+== fieldset-fieldset-3.html fieldset-fieldset-ref.html
+== fieldset-fieldset-4.html fieldset-fieldset-ref.html
--- a/layout/reftests/css-disabled/fieldset/style.css
+++ b/layout/reftests/css-disabled/fieldset/style.css
@@ -1,16 +1,19 @@
-fieldset.disabled {
+.ref {
+  background-color: green;
+}
+
+.disabled {
   background-color: red;
 }
 
-fieldset:disabled.disabled,
-fieldset.ref {
+:disabled.disabled {
   background-color: green;
 }
 
-fieldset.enabled {
+.enabled {
   background-color: green;
 }
 
-fieldset:disabled.enabled {
+:disabled.enabled {
   background-color: red;
 }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/input-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <input class="enabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/input-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <input class="disabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/input-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <input class="disabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/input-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <input class="enabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/input-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <input class="ref">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/reftest.list
@@ -0,0 +1,4 @@
+== input-fieldset-1.html input-fieldset-ref.html
+== input-fieldset-2.html input-fieldset-ref.html
+== input-fieldset-3.html input-fieldset-ref.html
+== input-fieldset-4.html input-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/input/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.disabled {
+  background-color: red;
+}
+
+:disabled.disabled {
+  background-color: green;
+}
+
+.enabled {
+  background-color: green;
+}
+
+:disabled.enabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/label/label-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <label class="ref">foo</label>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/label/label.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <label disabled>foo</label>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/label/reftest.list
@@ -0,0 +1,1 @@
+== label.html label-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/label/style.css
@@ -0,0 +1,12 @@
+label {
+  background-color: green;
+}
+
+label:disabled {
+  background-color: red;
+}
+
+/* ref should always be green! */
+.ref:disabled {
+  background-color: green;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/object/object-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <object class="ref">foo</object>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/object/object.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <object disabled>foo</object>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/object/reftest.list
@@ -0,0 +1,1 @@
+== object.html object-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/object/style.css
@@ -0,0 +1,12 @@
+object {
+  background-color: green;
+}
+
+object:disabled {
+  background-color: red;
+}
+
+/* ref should always be green! */
+.ref:disabled {
+  background-color: green;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/output/output-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <output class="ref">foo</output>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/output/output.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <output disabled>foo</output>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/output/reftest.list
@@ -0,0 +1,1 @@
+== output.html output-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/output/style.css
@@ -0,0 +1,12 @@
+output {
+  background-color: green;
+}
+
+output:disabled {
+  background-color: red;
+}
+
+/* ref should always be green! */
+.ref:disabled {
+  background-color: green;
+}
--- a/layout/reftests/css-disabled/reftest.list
+++ b/layout/reftests/css-disabled/reftest.list
@@ -1,1 +1,8 @@
 include fieldset/reftest.list
+include input/reftest.list
+include button/reftest.list
+include textarea/reftest.list
+include select/reftest.list
+include object/reftest.list
+include label/reftest.list
+include output/reftest.list
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/reftest.list
@@ -0,0 +1,4 @@
+== select-fieldset-1.html select-fieldset-ref.html
+== select-fieldset-2.html select-fieldset-ref.html
+== select-fieldset-3.html select-fieldset-ref.html
+== select-fieldset-4.html select-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/select-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <select class="enabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/select-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <select class="disabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/select-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <select class="disabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/select-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <select class="enabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/select-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <select class="ref"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/select/style.css
@@ -0,0 +1,23 @@
+select {
+  -moz-appearance: none;
+}
+
+.ref {
+  background-color: green;
+}
+
+.disabled {
+  background-color: red;
+}
+
+:disabled.disabled {
+  background-color: green;
+}
+
+.enabled {
+  background-color: green;
+}
+
+:disabled.enabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/reftest.list
@@ -0,0 +1,4 @@
+== textarea-fieldset-1.html textarea-fieldset-ref.html
+== textarea-fieldset-2.html textarea-fieldset-ref.html
+== textarea-fieldset-3.html textarea-fieldset-ref.html
+== textarea-fieldset-4.html textarea-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.disabled {
+  background-color: red;
+}
+
+:disabled.disabled {
+  background-color: green;
+}
+
+.enabled {
+  background-color: green;
+}
+
+:disabled.enabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/textarea-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <textarea class="enabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/textarea-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <textarea class="disabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/textarea-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <textarea class="disabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/textarea-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <textarea class="enabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-disabled/textarea/textarea-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <textarea class="ref"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/button-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <button class="enabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/button-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <button class="disabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/button-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <button class="disabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/button-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <button class="enabled"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/button-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <button class="ref"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/reftest.list
@@ -0,0 +1,4 @@
+== button-fieldset-1.html button-fieldset-ref.html
+== button-fieldset-2.html button-fieldset-ref.html
+== button-fieldset-3.html button-fieldset-ref.html
+== button-fieldset-4.html button-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/button/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.enabled {
+  background-color: red;
+}
+
+:enabled.enabled {
+  background-color: green;
+}
+
+.disabled {
+  background-color: green;
+}
+
+:enabled.disabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/fieldset/fieldset-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <fieldset class="enabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/fieldset/fieldset-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <fieldset class="disabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/fieldset/fieldset-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <fieldset class="disabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/fieldset/fieldset-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <fieldset class="enabled"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/fieldset/fieldset-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <fieldset class="ref"></fieldset>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-enabled/fieldset/reftest.list
+++ b/layout/reftests/css-enabled/fieldset/reftest.list
@@ -1,2 +1,6 @@
 == fieldset-enabled.html fieldset-ref.html
 == fieldset-disabled.html fieldset-ref.html
+== fieldset-fieldset-1.html fieldset-fieldset-ref.html
+== fieldset-fieldset-2.html fieldset-fieldset-ref.html
+== fieldset-fieldset-3.html fieldset-fieldset-ref.html
+== fieldset-fieldset-4.html fieldset-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/input-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <input class="enabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/input-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <input class="disabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/input-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <input class="disabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/input-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <input class="enabled">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/input-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <input class="ref">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/reftest.list
@@ -0,0 +1,4 @@
+== input-fieldset-1.html input-fieldset-ref.html
+== input-fieldset-2.html input-fieldset-ref.html
+== input-fieldset-3.html input-fieldset-ref.html
+== input-fieldset-4.html input-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/input/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.enabled {
+  background-color: red;
+}
+
+:enabled.enabled {
+  background-color: green;
+}
+
+.disabled {
+  background-color: green;
+}
+
+:enabled.disabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/label/label-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <label class="ref">foo</label>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/label/label.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <label>foo</label>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/label/reftest.list
@@ -0,0 +1,1 @@
+== label.html label-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/label/style.css
@@ -0,0 +1,12 @@
+label {
+  background-color: green;
+}
+
+label:enabled {
+  background-color: red;
+}
+
+/* ref should always be green! */
+.ref:enabled {
+  background-color: green;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/object/object-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <object class="ref">foo</object>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/object/object.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <object>foo</object>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/object/reftest.list
@@ -0,0 +1,1 @@
+== object.html object-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/object/style.css
@@ -0,0 +1,12 @@
+object {
+  background-color: green;
+}
+
+object:enabled {
+  background-color: red;
+}
+
+/* ref should always be green! */
+.ref:enabled {
+  background-color: green;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/optgroup/optgroup-fieldset-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <optgroup class="enabled">foo</optgroup>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/optgroup/optgroup-fieldset-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <optgroup class="ref">foo</optgroup>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/optgroup/reftest.list
@@ -0,0 +1,1 @@
+== optgroup-fieldset-1.html optgroup-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/optgroup/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.enabled {
+  background-color: red;
+}
+
+:enabled.enabled {
+  background-color: green;
+}
+
+.disabled {
+  background-color: green;
+}
+
+:enabled.disabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/option/option-fieldset-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <option class="enabled">foo</option>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/option/option-fieldset-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <option class="ref">foo</option>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/option/reftest.list
@@ -0,0 +1,1 @@
+== option-fieldset-1.html option-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/option/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.enabled {
+  background-color: red;
+}
+
+:enabled.enabled {
+  background-color: green;
+}
+
+.disabled {
+  background-color: green;
+}
+
+:enabled.disabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/output/output-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <output class="ref">foo</output>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/output/output.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <output>foo</output>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/output/reftest.list
@@ -0,0 +1,1 @@
+== output.html output-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/output/style.css
@@ -0,0 +1,12 @@
+output {
+  background-color: green;
+}
+
+output:enabled {
+  background-color: red;
+}
+
+/* ref should always be green! */
+.ref:enabled {
+  background-color: green;
+}
--- a/layout/reftests/css-enabled/reftest.list
+++ b/layout/reftests/css-enabled/reftest.list
@@ -1,1 +1,10 @@
 include fieldset/reftest.list
+include input/reftest.list
+include button/reftest.list
+include textarea/reftest.list
+include select/reftest.list
+include option/reftest.list
+include optgroup/reftest.list
+include object/reftest.list
+include label/reftest.list
+include output/reftest.list
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/reftest.list
@@ -0,0 +1,4 @@
+== select-fieldset-1.html select-fieldset-ref.html
+== select-fieldset-2.html select-fieldset-ref.html
+== select-fieldset-3.html select-fieldset-ref.html
+== select-fieldset-4.html select-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/select-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <select class="enabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/select-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <select class="disabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/select-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <select class="disabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/select-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <select class="enabled"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/select-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <select class="ref"></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/select/style.css
@@ -0,0 +1,23 @@
+select {
+  -moz-appearance: none;
+}
+
+.ref {
+  background-color: green;
+}
+
+.enabled {
+  background-color: red;
+}
+
+:enabled.enabled {
+  background-color: green;
+}
+
+.disabled {
+  background-color: green;
+}
+
+:enabled.disabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/reftest.list
@@ -0,0 +1,4 @@
+== textarea-fieldset-1.html textarea-fieldset-ref.html
+== textarea-fieldset-2.html textarea-fieldset-ref.html
+== textarea-fieldset-3.html textarea-fieldset-ref.html
+== textarea-fieldset-4.html textarea-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/style.css
@@ -0,0 +1,19 @@
+.ref {
+  background-color: green;
+}
+
+.enabled {
+  background-color: red;
+}
+
+:enabled.enabled {
+  background-color: green;
+}
+
+.disabled {
+  background-color: green;
+}
+
+:enabled.disabled {
+  background-color: red;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/textarea-fieldset-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="enabled">
+      <fieldset class="enabled">
+        <textarea class="enabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/textarea-fieldset-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled class="disabled">
+      <fieldset class="disabled">
+        <textarea class="disabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/textarea-fieldset-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="disabled">
+        <textarea class="disabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/textarea-fieldset-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName('fieldset');
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled class="enabled">
+      <fieldset class="enabled">
+        <textarea class="enabled"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-enabled/textarea/textarea-fieldset-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset class="ref">
+      <fieldset class="ref">
+        <textarea class="ref"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-disabled-fieldset-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notinvalid' id='b'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-disabled-fieldset-2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var e = document.getElementById('b');
+      e.setCustomValidity('foo');
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notinvalid' id='b'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/button/button-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <button style="background-color: green;"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-invalid/button/reftest.list
+++ b/layout/reftests/css-invalid/button/reftest.list
@@ -2,8 +2,10 @@
 == button-invalid.html button-ref.html
 == button-disabled.html button-ref.html
 == button-dyn-disabled.html button-ref.html
 == button-dyn-not-disabled.html button-ref.html
 == button-button.html button-ref.html
 == button-reset.html button-ref.html
 == button-type-invalid.html button-ref.html
 == button-type-barred.html button-ref.html
+== button-disabled-fieldset-1.html button-fieldset-ref.html
+== button-disabled-fieldset-2.html button-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/input/input-disabled-fieldset-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if input has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <input class='notinvalid' required>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/input/input-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if input has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <input class='notinvalid' required>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/input/input-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <input style="background-color: green;">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-invalid/input/reftest.list
+++ b/layout/reftests/css-invalid/input/reftest.list
@@ -15,9 +15,11 @@
 == input-email-invalid.html input-withtext-ref.html
 == input-email-valid.html input-email-ref.html
 == input-url-invalid.html input-withtext-ref.html
 == input-url-valid.html input-url-ref.html
 == input-pattern-valid.html input-withtext-ref.html
 == input-pattern-invalid.html input-withtext-ref.html
 == input-type-barred.html input-button-ref.html
 == input-type-invalid.html input-ref.html
+== input-disabled-fieldset-1.html input-fieldset-ref.html
+== input-disabled-fieldset-2.html input-fieldset-ref.html
 # input type='hidden' shouldn't show
--- a/layout/reftests/css-invalid/select/reftest.list
+++ b/layout/reftests/css-invalid/select/reftest.list
@@ -1,5 +1,7 @@
 == select-valid.html select-ref.html
 == select-invalid.html select-ref.html
 == select-disabled.html select-disabled-ref.html
 == select-dyn-disabled.html select-disabled-ref.html
 == select-dyn-not-disabled.html select-ref.html
+== select-disabled-fieldset-1.html select-fieldset-ref.html
+== select-disabled-fieldset-2.html select-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/select/select-disabled-fieldset-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if select has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onLoadHandler()
+    {
+      var e = document.getElementById('s');
+      e.setCustomValidity('foo');
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <select class='notinvalid' id='s'></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/select/select-disabled-fieldset-2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if select has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var e = document.getElementById('s');
+      e.setCustomValidity('foo');
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <select class='notinvalid' id='s'></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/select/select-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <select style="background-color: green;" disabled></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-invalid/textarea/reftest.list
+++ b/layout/reftests/css-invalid/textarea/reftest.list
@@ -5,8 +5,10 @@
 == textarea-dyn-not-disabled.html textarea-ref.html
 == textarea-readonly.html textarea-ref.html
 == textarea-dyn-readonly.html textarea-ref.html
 == textarea-dyn-not-readonly.html textarea-ref.html
 == textarea-maxlength-valid.html textarea-ref.html
 == textarea-maxlength-invalid.html textarea-withtext-ref.html
 == textarea-required-valid.html textarea-withtext-ref.html
 == textarea-required-invalid.html textarea-ref.html
+== textarea-disabled-fieldset-1.html textarea-fieldset-ref.html
+== textarea-disabled-fieldset-2.html textarea-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/textarea/textarea-disabled-fieldset-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if textarea has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body onload="onLoadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <textarea class='notinvalid' required></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/textarea/textarea-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if textarea has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :invalid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <textarea class='notinvalid' required></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-invalid/textarea/textarea-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <textarea style="background-color: green;"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/button/button-disabled-fieldset-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled>
+      <fieldset>
+        <button class='notvalid'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/button/button-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if button has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <button class='notvalid'></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/button/button-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <button style="background-color: green;"></button>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-valid/button/reftest.list
+++ b/layout/reftests/css-valid/button/reftest.list
@@ -2,8 +2,10 @@
 == button-invalid.html button-ref.html
 == button-disabled.html button-ref.html
 == button-dyn-disabled.html button-ref.html
 == button-dyn-not-disabled.html button-ref.html
 == button-button.html button-ref.html
 == button-reset.html button-ref.html
 == button-type-invalid.html button-ref.html
 == button-type-barred.html button-ref.html
+== button-disabled-fieldset-1.html button-fieldset-ref.html
+== button-disabled-fieldset-2.html button-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/input/input-disabled-fieldset-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if input has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled>
+      <fieldset>
+        <input class='notvalid'>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/input/input-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if input has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <input class='notvalid'>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/input/input-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <input style="background-color: green;">
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-valid/input/reftest.list
+++ b/layout/reftests/css-valid/input/reftest.list
@@ -15,9 +15,11 @@
 == input-email-invalid.html input-withtext-ref.html
 == input-email-valid.html input-email-ref.html
 == input-url-invalid.html input-withtext-ref.html
 == input-url-valid.html input-url-ref.html
 == input-pattern-valid.html input-withtext-ref.html
 == input-pattern-invalid.html input-withtext-ref.html
 == input-type-barred.html input-button-ref.html
 == input-type-invalid.html input-ref.html
+== input-disabled-fieldset-1.html input-fieldset-ref.html
+== input-disabled-fieldset-2.html input-fieldset-ref.html
 # input type='hidden' shouldn't show
--- a/layout/reftests/css-valid/select/reftest.list
+++ b/layout/reftests/css-valid/select/reftest.list
@@ -1,5 +1,7 @@
 == select-valid.html select-ref.html
 == select-invalid.html select-ref.html
 == select-disabled.html select-disabled-ref.html
 == select-dyn-disabled.html select-disabled-ref.html
 == select-dyn-not-disabled.html select-ref.html
+== select-disabled-fieldset-1.html select-fieldset-ref.html
+== select-disabled-fieldset-2.html select-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/select/select-disabled-fieldset-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if select has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled>
+      <fieldset>
+        <select class='notvalid'></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/select/select-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if select has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <select class='notvalid'></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/select/select-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <select style="background-color: green;" disabled></select>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
--- a/layout/reftests/css-valid/textarea/reftest.list
+++ b/layout/reftests/css-valid/textarea/reftest.list
@@ -5,8 +5,10 @@
 == textarea-dyn-not-disabled.html textarea-ref.html
 == textarea-readonly.html textarea-ref.html
 == textarea-dyn-readonly.html textarea-ref.html
 == textarea-dyn-not-readonly.html textarea-ref.html
 == textarea-maxlength-valid.html textarea-ref.html
 == textarea-maxlength-invalid.html textarea-withtext-ref.html
 == textarea-required-valid.html textarea-withtext-ref.html
 == textarea-required-invalid.html textarea-ref.html
+== textarea-disabled-fieldset-1.html textarea-fieldset-ref.html
+== textarea-disabled-fieldset-2.html textarea-fieldset-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/textarea/textarea-disabled-fieldset-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <!-- Test: if textarea has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <body>
+    <fieldset disabled>
+      <fieldset>
+        <textarea class='notvalid'></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/textarea/textarea-disabled-fieldset-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <!-- Test: if textarea has a disabled fieldset ancestor, it is barred from
+             constraint validation and should not be affected by :valid
+             pseudo-class. -->
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <script>
+    function onloadHandler()
+    {
+      var fieldsets = document.getElementsByTagName("fieldset");
+      fieldsets[1].disabled = true;
+      fieldsets[0].disabled = false;
+      document.documentElement.className='';
+    }
+  </script>
+  <body onload="onloadHandler();">
+    <fieldset disabled>
+      <fieldset>
+        <textarea class='notvalid'></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-valid/textarea/textarea-fieldset-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <fieldset>
+      <fieldset>
+        <textarea style="background-color: green;"></textarea>
+      </fieldset>
+    </fieldset>
+  </body>
+</html>