From 495e0b741db3c6668ac606ba705af963c7bbee36 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Mon, 4 Oct 2021 20:51:27 +0000 Subject: [PATCH] Bug 1556351 - Part 5: Make nsGenericHTMLFormControlElement implement nsIFormControl; r=smaug nsGenericHTMLFormElement doesn't implement nsIFormControl now as HTMLElement would inherit it to be able to be added into HTMLFormElement and HTMLFieldSetElement and support some common form feature. So some places that call the nsIFormControl method on nsGenericHTMLFormElement directly would need to queryInterface it to nsIFormControl first, this should be fine as those places are not in a hot path. Differential Revision: https://phabricator.services.mozilla.com/D124788 --- dom/base/nsContentUtils.cpp | 2 +- dom/base/nsINode.cpp | 20 ++--- dom/html/HTMLButtonElement.h | 2 - dom/html/HTMLFormControlsCollection.cpp | 23 ++++-- dom/html/HTMLFormControlsCollection.h | 3 +- dom/html/HTMLFormElement.cpp | 57 +++++++++----- dom/html/HTMLFormElement.h | 2 +- dom/html/nsGenericHTMLElement.cpp | 100 ++++++++++++++---------- dom/html/nsGenericHTMLElement.h | 62 ++++++++------- 9 files changed, 161 insertions(+), 110 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 9b847abeb49e..6c231ed7cb60 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3079,7 +3079,7 @@ void nsContentUtils::GenerateStateKey(nsIContent* aContent, Document* aDocument, if (appendedForm) { // Append the index of the control in the form - int32_t index = formElement->IndexOfControl(control); + int32_t index = formElement->IndexOfContent(aContent); if (index > -1) { KeyAppendInt(index, aKey); diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 81209300bd6e..5df409d80f47 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -679,16 +679,16 @@ void nsINode::LastRelease() { document->RemoveAllPropertiesFor(this); } - // I wonder whether it's faster to do the HasFlag check first.... - if (IsNodeOfType(nsINode::eHTML_FORM_CONTROL) && HasFlag(ADDED_TO_FORM)) { - // Tell the form (if any) this node is going away. Don't - // notify, since we're being destroyed in any case. - static_cast(this)->ClearForm(true, true); - } - - if (IsHTMLElement(nsGkAtoms::img) && HasFlag(ADDED_TO_FORM)) { - HTMLImageElement* imageElem = static_cast(this); - imageElem->ClearForm(true); + if (HasFlag(ADDED_TO_FORM)) { + if (nsGenericHTMLFormControlElement* formControl = + nsGenericHTMLFormControlElement::FromNode(this)) { + // Tell the form (if any) this node is going away. Don't + // notify, since we're being destroyed in any case. + formControl->ClearForm(true, true); + } else if (HTMLImageElement* imageElem = + HTMLImageElement::FromNode(this)) { + imageElem->ClearForm(true); + } } } UnsetFlags(NODE_HAS_PROPERTIES); diff --git a/dom/html/HTMLButtonElement.h b/dom/html/HTMLButtonElement.h index 3f78f5c477e0..8831422a958d 100644 --- a/dom/html/HTMLButtonElement.h +++ b/dom/html/HTMLButtonElement.h @@ -100,8 +100,6 @@ class HTMLButtonElement final : public nsGenericHTMLFormControlElementWithState, void SetDisabled(bool aDisabled, ErrorResult& aError) { SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aError); } - // nsGenericHTMLFormElement::GetForm is fine. - using nsGenericHTMLFormElement::GetForm; // GetFormAction implemented in superclass void SetFormAction(const nsAString& aFormAction, ErrorResult& aRv) { SetHTMLAttr(nsGkAtoms::formaction, aFormAction, aRv); diff --git a/dom/html/HTMLFormControlsCollection.cpp b/dom/html/HTMLFormControlsCollection.cpp index c8c6d8abfe26..fe037e6a5e3f 100644 --- a/dom/html/HTMLFormControlsCollection.cpp +++ b/dom/html/HTMLFormControlsCollection.cpp @@ -8,11 +8,12 @@ #include "mozilla/FlushType.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Document.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLFormControlsCollectionBinding.h" #include "mozilla/dom/HTMLFormElement.h" #include "nsGenericHTMLElement.h" // nsGenericHTMLFormElement -#include "mozilla/dom/Document.h" +#include "nsQueryObject.h" #include "nsIFormControl.h" #include "RadioNodeList.h" #include "jsfriendapi.h" @@ -89,12 +90,16 @@ void HTMLFormControlsCollection::DropFormReference() { void HTMLFormControlsCollection::Clear() { // Null out childrens' pointer to me. No refcounting here for (int32_t i = mElements.Length() - 1; i >= 0; i--) { - mElements[i]->ClearForm(false, false); + nsCOMPtr formControl = do_QueryObject(mElements[i]); + MOZ_ASSERT(formControl); + formControl->ClearForm(false, false); } mElements.Clear(); for (int32_t i = mNotInElements.Length() - 1; i >= 0; i--) { - mNotInElements[i]->ClearForm(false, false); + nsCOMPtr formControl = do_QueryObject(mNotInElements[i]); + MOZ_ASSERT(formControl); + formControl->ClearForm(false, false); } mNotInElements.Clear(); @@ -138,27 +143,31 @@ nsISupports* HTMLFormControlsCollection::NamedItemInternal( nsresult HTMLFormControlsCollection::AddElementToTable( nsGenericHTMLFormElement* aChild, const nsAString& aName) { - if (!ShouldBeInElements(aChild)) { + nsCOMPtr formControl = do_QueryObject(aChild); + MOZ_ASSERT(formControl); + if (!ShouldBeInElements(formControl)) { return NS_OK; } return mForm->AddElementToTableInternal(mNameLookupTable, aChild, aName); } -nsresult HTMLFormControlsCollection::IndexOfControl(nsIFormControl* aControl, +nsresult HTMLFormControlsCollection::IndexOfContent(nsIContent* aContent, int32_t* aIndex) { // Note -- not a DOM method; callers should handle flushing themselves NS_ENSURE_ARG_POINTER(aIndex); - *aIndex = mElements.IndexOf(aControl); + *aIndex = mElements.IndexOf(aContent); return NS_OK; } nsresult HTMLFormControlsCollection::RemoveElementFromTable( nsGenericHTMLFormElement* aChild, const nsAString& aName) { - if (!ShouldBeInElements(aChild)) { + nsCOMPtr formControl = do_QueryObject(aChild); + MOZ_ASSERT(formControl); + if (!ShouldBeInElements(formControl)) { return NS_OK; } diff --git a/dom/html/HTMLFormControlsCollection.h b/dom/html/HTMLFormControlsCollection.h index 92bffbcf718f..a9f52a210dd5 100644 --- a/dom/html/HTMLFormControlsCollection.h +++ b/dom/html/HTMLFormControlsCollection.h @@ -13,6 +13,7 @@ #include "nsWrapperCache.h" class nsGenericHTMLFormElement; +class nsIContent; class nsIFormControl; template class RefPtr; @@ -56,7 +57,7 @@ class HTMLFormControlsCollection final : public nsIHTMLCollection, const nsAString& aName); nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild, const nsAString& aName); - nsresult IndexOfControl(nsIFormControl* aControl, int32_t* aIndex); + nsresult IndexOfContent(nsIContent* aContent, int32_t* aIndex); nsISupports* NamedItemInternal(const nsAString& aName); diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index bf7eecf2884a..148b38a34cf0 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -382,7 +382,9 @@ static void CollectOrphans(nsINode* aRemovalRoot, if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) { node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT); if (!node->IsInclusiveDescendantOf(aRemovalRoot)) { - node->ClearForm(true, false); + nsCOMPtr fc = do_QueryInterface(node); + MOZ_ASSERT(fc); + fc->ClearForm(true, false); // When a form control loses its form owner, its state can change. node->UpdateState(true); @@ -394,7 +396,9 @@ static void CollectOrphans(nsINode* aRemovalRoot, #ifdef DEBUG if (!removed) { - HTMLFormElement* form = node->GetForm(); + nsCOMPtr fc = do_QueryInterface(node); + MOZ_ASSERT(fc); + HTMLFormElement* form = fc->GetForm(); NS_ASSERTION(form == aThisForm, "How did that happen?"); } #endif /* DEBUG */ @@ -603,8 +607,8 @@ nsresult HTMLFormElement::DoReset() { uint32_t numElements = mControls->Length(); for (uint32_t elementX = 0; elementX < numElements; ++elementX) { // Hold strong ref in case the reset does something weird - nsCOMPtr controlNode = - mControls->mElements.SafeElementAt(elementX, nullptr); + nsCOMPtr controlNode = do_QueryInterface( + mControls->mElements.SafeElementAt(elementX, nullptr)); if (controlNode) { controlNode->Reset(); } @@ -1017,8 +1021,10 @@ nsresult HTMLFormElement::ConstructEntryList(FormData* aFormData) { // Walk the list of nodes and call SubmitNamesValues() on the controls // for (uint32_t i = 0; i < len; ++i) { + nsCOMPtr fc = do_QueryInterface(sortedControls[i]); + MOZ_ASSERT(fc); // Tell the control to submit its name/value pairs to the submission - sortedControls[i]->SubmitNamesValues(aFormData); + fc->SubmitNamesValues(aFormData); } FormDataEventInit init; @@ -1254,10 +1260,11 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild, NS_ASSERTION(aChild->HasAttr(kNameSpaceID_None, nsGkAtoms::form) || aChild->GetParent(), "Form control should have a parent"); - + nsCOMPtr fc = do_QueryObject(aChild); + MOZ_ASSERT(fc); // Determine whether to add the new element to the elements or // the not-in-elements list. - bool childInElements = HTMLFormControlsCollection::ShouldBeInElements(aChild); + bool childInElements = HTMLFormControlsCollection::ShouldBeInElements(fc); nsTArray& controlList = childInElements ? mControls->mElements : mControls->mNotInElements; @@ -1267,7 +1274,7 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild, AssertDocumentOrder(controlList, this); #endif - auto type = aChild->ControlType(); + auto type = fc->ControlType(); // If it is a password control, inform the password manager. if (type == FormControlType::InputPassword) { @@ -1280,7 +1287,7 @@ nsresult HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild, } // Default submit element handling - if (aChild->IsSubmitControl()) { + if (fc->IsSubmitControl()) { // Update mDefaultSubmitElement, mFirstSubmitInElements, // mFirstSubmitNotInElements. @@ -1359,14 +1366,16 @@ nsresult HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild, // Remove it from the radio group if it's a radio button // nsresult rv = NS_OK; - if (aChild->ControlType() == FormControlType::InputRadio) { + nsCOMPtr fc = do_QueryInterface(aChild); + MOZ_ASSERT(fc); + if (fc->ControlType() == FormControlType::InputRadio) { RefPtr radio = static_cast(aChild); radio->WillRemoveFromRadioGroup(); } // Determine whether to remove the child from the elements list // or the not in elements list. - bool childInElements = HTMLFormControlsCollection::ShouldBeInElements(aChild); + bool childInElements = HTMLFormControlsCollection::ShouldBeInElements(fc); nsTArray& controls = childInElements ? mControls->mElements : mControls->mNotInElements; @@ -1386,9 +1395,10 @@ nsresult HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild, // We are removing the first submit in this list, find the new first submit uint32_t length = controls.Length(); for (uint32_t i = index; i < length; ++i) { - nsGenericHTMLFormElement* currentControl = controls[i]; + nsCOMPtr currentControl = do_QueryInterface(controls[i]); + MOZ_ASSERT(currentControl); if (currentControl->IsSubmitControl()) { - *firstSubmitSlot = currentControl; + *firstSubmitSlot = controls[i]; break; } } @@ -1794,7 +1804,9 @@ bool HTMLFormElement::ImplicitSubmissionIsDisabled() const { uint32_t numDisablingControlsFound = 0; uint32_t length = mControls->mElements.Length(); for (uint32_t i = 0; i < length && numDisablingControlsFound < 2; ++i) { - if (mControls->mElements[i]->IsSingleLineTextControl(false)) { + nsCOMPtr fc = do_QueryInterface(mControls->mElements[i]); + MOZ_ASSERT(fc); + if (fc->IsSingleLineTextControl(false)) { numDisablingControlsFound++; } } @@ -1806,8 +1818,10 @@ bool HTMLFormElement::IsLastActiveElement( MOZ_ASSERT(aElement, "Unexpected call"); for (auto* element : Reversed(mControls->mElements)) { + nsCOMPtr fc = do_QueryInterface(element); + MOZ_ASSERT(fc); // XXX How about date/time control? - if (element->IsTextControl(false) && !element->IsDisabled()) { + if (fc->IsTextControl(false) && !element->IsDisabled()) { return element == aElement; } } @@ -2015,7 +2029,9 @@ void HTMLFormElement::UpdateValidity(bool aElementValidity) { // Inform submit controls that the form validity has changed. for (uint32_t i = 0, length = mControls->mElements.Length(); i < length; ++i) { - if (mControls->mElements[i]->IsSubmitControl()) { + nsCOMPtr fc = do_QueryInterface(mControls->mElements[i]); + MOZ_ASSERT(fc); + if (fc->IsSubmitControl()) { mControls->mElements[i]->UpdateState(true); } } @@ -2024,7 +2040,10 @@ void HTMLFormElement::UpdateValidity(bool aElementValidity) { // so we have to check for controls not in elements too. uint32_t length = mControls->mNotInElements.Length(); for (uint32_t i = 0; i < length; ++i) { - if (mControls->mNotInElements[i]->IsSubmitControl()) { + nsCOMPtr fc = + do_QueryInterface(mControls->mNotInElements[i]); + MOZ_ASSERT(fc); + if (fc->IsSubmitControl()) { mControls->mNotInElements[i]->UpdateState(true); } } @@ -2032,9 +2051,9 @@ void HTMLFormElement::UpdateValidity(bool aElementValidity) { UpdateState(true); } -int32_t HTMLFormElement::IndexOfControl(nsIFormControl* aControl) { +int32_t HTMLFormElement::IndexOfContent(nsIContent* aContent) { int32_t index = 0; - return mControls->IndexOfControl(aControl, &index) == NS_OK ? index : 0; + return mControls->IndexOfContent(aContent, &index) == NS_OK ? index : 0; } void HTMLFormElement::SetCurrentRadioButton(const nsAString& aName, diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index 45260c96eb12..a8e1c2c5973a 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -53,7 +53,7 @@ class HTMLFormElement final : public nsGenericHTMLElement, // nsISupports NS_DECL_ISUPPORTS_INHERITED - int32_t IndexOfControl(nsIFormControl* aControl); + int32_t IndexOfContent(nsIContent* aContent); nsGenericHTMLFormElement* GetDefaultSubmitElement() const; // nsIRadioGroupContainer diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index e2ffa737e532..ccae646bbb3f 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -1650,9 +1650,8 @@ bool nsGenericHTMLElement::IsFormControlDefaultFocusable( //---------------------------------------------------------------------- nsGenericHTMLFormElement::nsGenericHTMLFormElement( - already_AddRefed&& aNodeInfo, FormControlType aType) + already_AddRefed&& aNodeInfo) : nsGenericHTMLElement(std::move(aNodeInfo)), - nsIFormControl(aType), mForm(nullptr), mFieldSet(nullptr) { // We should add the NS_EVENT_STATE_ENABLED bit here as needed, but @@ -1669,31 +1668,6 @@ nsGenericHTMLFormElement::~nsGenericHTMLFormElement() { NS_ASSERTION(!mForm, "mForm should be null at this point!"); } -NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormElement, nsGenericHTMLElement, - nsIFormControl) - -bool nsGenericHTMLFormElement::IsNodeOfType(uint32_t aFlags) const { - return !(aFlags & ~eHTML_FORM_CONTROL); -} - -void nsGenericHTMLFormElement::SetForm(HTMLFormElement* aForm) { - MOZ_ASSERT(aForm, "Don't pass null here"); - NS_ASSERTION(!mForm, - "We don't support switching from one non-null form to another."); - - SetForm(aForm, false); -} - -void nsGenericHTMLFormElement::SetForm(HTMLFormElement* aForm, - bool aBindToTree) { - if (aForm) { - BeforeSetForm(aBindToTree); - } - - // keep a *weak* ref to the form here - mForm = aForm; -} - void nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete) { NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM), @@ -1725,20 +1699,11 @@ void nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm, AfterClearForm(aUnbindOrDelete); } -HTMLFieldSetElement* nsGenericHTMLFormElement::GetFieldSet() { - return mFieldSet; -} - nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext, nsINode& aParent) { nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent); NS_ENSURE_SUCCESS(rv, rv); - if (IsAutofocusable() && HasAttr(nsGkAtoms::autofocus) && - aContext.AllowsAutoFocus()) { - aContext.OwnerDoc().SetAutoFocusElement(this); - } - // If @form is set, the element *has* to be in a composed document, otherwise // it wouldn't be possible to find an element with the corresponding id. // If @form isn't set, the element *has* to have a parent, otherwise it @@ -1757,9 +1722,6 @@ nsresult nsGenericHTMLFormElement::BindToTree(BindContext& aContext, } void nsGenericHTMLFormElement::UnbindFromTree(bool aNullParent) { - // Save state before doing anything - SaveState(); - if (mForm) { // Might need to unset mForm if (aNullParent) { @@ -2026,7 +1988,7 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree, if (element && element->IsHTMLElement(nsGkAtoms::form) && nsContentUtils::IsInSameAnonymousTree(this, element)) { - SetForm(static_cast(element), aBindToTree); + SetFormInternal(static_cast(element), aBindToTree); } } } else { @@ -2036,7 +1998,7 @@ void nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree, // it to the right value. Also note that even if being bound here didn't // change our parent, we still need to search, since our parent chain // probably changed _somewhere_. - SetForm(FindAncestorForm(), aBindToTree); + SetFormInternal(FindAncestorForm(), aBindToTree); } } @@ -2438,14 +2400,21 @@ void nsGenericHTMLElement::ChangeEditableState(int32_t aChange) { nsGenericHTMLFormControlElement::nsGenericHTMLFormControlElement( already_AddRefed&& aNodeInfo, FormControlType aType) - : nsGenericHTMLFormElement(std::move(aNodeInfo), aType) {} + : nsGenericHTMLFormElement(std::move(aNodeInfo)), nsIFormControl(aType) {} nsGenericHTMLFormControlElement::~nsGenericHTMLFormControlElement() = default; +NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormControlElement, + nsGenericHTMLFormElement, nsIFormControl) + nsINode* nsGenericHTMLFormControlElement::GetScopeChainParent() const { return mForm ? mForm : nsGenericHTMLElement::GetScopeChainParent(); } +bool nsGenericHTMLFormControlElement::IsNodeOfType(uint32_t aFlags) const { + return !(aFlags & ~eHTML_FORM_CONTROL); +} + void nsGenericHTMLFormControlElement::SaveSubtreeState() { SaveState(); @@ -2465,6 +2434,26 @@ nsIContent::IMEState nsGenericHTMLFormControlElement::GetDesiredIMEState() { return state; } +nsresult nsGenericHTMLFormControlElement::BindToTree(BindContext& aContext, + nsINode& aParent) { + nsresult rv = nsGenericHTMLFormElement::BindToTree(aContext, aParent); + NS_ENSURE_SUCCESS(rv, rv); + + if (IsAutofocusable() && HasAttr(nsGkAtoms::autofocus) && + aContext.AllowsAutoFocus()) { + aContext.OwnerDoc().SetAutoFocusElement(this); + } + + return NS_OK; +} + +void nsGenericHTMLFormControlElement::UnbindFromTree(bool aNullParent) { + // Save state before doing anything + SaveState(); + + nsGenericHTMLFormElement::UnbindFromTree(aNullParent); +} + void nsGenericHTMLFormControlElement::GetAutocapitalize( nsAString& aValue) const { if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None, @@ -2530,6 +2519,23 @@ nsresult nsGenericHTMLFormControlElement::PreHandleEvent( return nsGenericHTMLFormElement::PreHandleEvent(aVisitor); } +HTMLFieldSetElement* nsGenericHTMLFormControlElement::GetFieldSet() { + return mFieldSet; +} + +void nsGenericHTMLFormControlElement::SetForm(HTMLFormElement* aForm) { + MOZ_ASSERT(aForm, "Don't pass null here"); + NS_ASSERTION(!mForm, + "We don't support switching from one non-null form to another."); + + SetFormInternal(aForm, false); +} + +void nsGenericHTMLFormControlElement::ClearForm(bool aRemoveFromForm, + bool aUnbindOrDelete) { + nsGenericHTMLFormElement::ClearForm(aRemoveFromForm, aUnbindOrDelete); +} + EventStates nsGenericHTMLFormControlElement::IntrinsicState() const { // 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 @@ -2610,6 +2616,16 @@ bool nsGenericHTMLFormControlElement::DoesReadOnlyApply() const { } } +void nsGenericHTMLFormControlElement::SetFormInternal(HTMLFormElement* aForm, + bool aBindToTree) { + if (aForm) { + BeforeSetForm(aBindToTree); + } + + // keep a *weak* ref to the form here + mForm = aForm; +} + void nsGenericHTMLFormControlElement::UpdateRequiredState(bool aIsRequired, bool aNotify) { #ifdef DEBUG diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h index b2304b489698..3680e01811fc 100644 --- a/dom/html/nsGenericHTMLElement.h +++ b/dom/html/nsGenericHTMLElement.h @@ -959,37 +959,15 @@ ASSERT_NODE_FLAGS_SPACE(HTML_ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 3); /** * A helper class for form elements that can contain children */ -class nsGenericHTMLFormElement : public nsGenericHTMLElement, - public nsIFormControl { +class nsGenericHTMLFormElement : public nsGenericHTMLElement { public: - nsGenericHTMLFormElement(already_AddRefed&& aNodeInfo, - FormControlType); - - NS_DECL_ISUPPORTS_INHERITED - - virtual bool IsNodeOfType(uint32_t aFlags) const override; - - // nsIFormControl - virtual mozilla::dom::HTMLFieldSetElement* GetFieldSet() override; - virtual mozilla::dom::HTMLFormElement* GetForm() const override { - return mForm; - } - virtual void SetForm(mozilla::dom::HTMLFormElement* aForm) override; - virtual void ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete) override; - - virtual bool AllowDrop() override { return true; } + nsGenericHTMLFormElement( + already_AddRefed&& aNodeInfo); // nsIContent virtual nsresult BindToTree(BindContext&, nsINode& aParent) override; virtual void UnbindFromTree(bool aNullParent = true) override; - /** - * Save to presentation state. The form control will determine whether it - * has anything to save and if so, create an entry in the layout history for - * its pres context. - */ - virtual void SaveState() {} - /** * This callback is called by a fieldest on all its elements whenever its * disabled attribute is changed so the element knows its disabled state @@ -1018,6 +996,8 @@ class nsGenericHTMLFormElement : public nsGenericHTMLElement, */ void ForgetFieldSet(nsIContent* aFieldset); + void ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete); + protected: virtual ~nsGenericHTMLFormElement(); @@ -1035,7 +1015,8 @@ class nsGenericHTMLFormElement : public nsGenericHTMLElement, virtual void AfterClearForm(bool aUnbindOrDelete) {} - void SetForm(mozilla::dom::HTMLFormElement* aForm, bool aBindToTree); + virtual void SetFormInternal(mozilla::dom::HTMLFormElement* aForm, + bool aBindToTree) {} /** * This method will update the form owner, using @form or looking to a parent. @@ -1097,17 +1078,26 @@ class nsGenericHTMLFormElement : public nsGenericHTMLElement, mozilla::dom::HTMLFieldSetElement* mFieldSet; }; -class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement { +class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement, + public nsIFormControl { public: nsGenericHTMLFormControlElement( already_AddRefed&& aNodeInfo, FormControlType); + NS_DECL_ISUPPORTS_INHERITED + + NS_IMPL_FROMNODE_HELPER(nsGenericHTMLFormControlElement, + IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) + // nsINode nsINode* GetScopeChainParent() const override; + virtual bool IsNodeOfType(uint32_t aFlags) const override; // nsIContent virtual void SaveSubtreeState() override; virtual IMEState GetDesiredIMEState() override; + virtual nsresult BindToTree(BindContext&, nsINode& aParent) override; + virtual void UnbindFromTree(bool aNullParent = true) override; // nsGenericHTMLElement // autocapitalize attribute support @@ -1120,6 +1110,15 @@ class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement { virtual nsresult PreHandleEvent( mozilla::EventChainVisitor& aVisitor) override; + // nsIFormControl + virtual mozilla::dom::HTMLFieldSetElement* GetFieldSet() override; + virtual mozilla::dom::HTMLFormElement* GetForm() const override { + return mForm; + } + virtual void SetForm(mozilla::dom::HTMLFormElement* aForm) override; + virtual void ClearForm(bool aRemoveFromForm, bool aUnbindOrDelete) override; + virtual bool AllowDrop() override { return true; } + protected: virtual ~nsGenericHTMLFormControlElement(); @@ -1130,6 +1129,8 @@ class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement { // nsGenericHTMLFormElement bool CanBeDisabled() const override; bool DoesReadOnlyApply() const override; + void SetFormInternal(mozilla::dom::HTMLFormElement* aForm, + bool aBindToTree) override; /** * Update our required/optional flags to match the given aIsRequired boolean. @@ -1137,6 +1138,13 @@ class nsGenericHTMLFormControlElement : public nsGenericHTMLFormElement { void UpdateRequiredState(bool aIsRequired, bool aNotify); bool IsAutocapitalizeInheriting() const; + + /** + * Save to presentation state. The form control will determine whether it + * has anything to save and if so, create an entry in the layout history for + * its pres context. + */ + virtual void SaveState() {} }; class nsGenericHTMLFormControlElementWithState