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
This commit is contained in:
Edgar Chen 2021-10-04 20:51:27 +00:00
Родитель 6be72297cc
Коммит 495e0b741d
9 изменённых файлов: 161 добавлений и 110 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<nsGenericHTMLFormElement*>(this)->ClearForm(true, true);
}
if (IsHTMLElement(nsGkAtoms::img) && HasFlag(ADDED_TO_FORM)) {
HTMLImageElement* imageElem = static_cast<HTMLImageElement*>(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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> formControl = do_QueryObject(aChild);
MOZ_ASSERT(formControl);
if (!ShouldBeInElements(formControl)) {
return NS_OK;
}

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsWrapperCache.h"
class nsGenericHTMLFormElement;
class nsIContent;
class nsIFormControl;
template <class T>
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);

Просмотреть файл

@ -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<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> controlNode =
mControls->mElements.SafeElementAt(elementX, nullptr);
nsCOMPtr<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> 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<nsGenericHTMLFormElement*>& 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<nsIFormControl> fc = do_QueryInterface(aChild);
MOZ_ASSERT(fc);
if (fc->ControlType() == FormControlType::InputRadio) {
RefPtr<HTMLInputElement> radio = static_cast<HTMLInputElement*>(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<nsGenericHTMLFormElement*>& 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<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> 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<nsIFormControl> 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,

Просмотреть файл

@ -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

Просмотреть файл

@ -1650,9 +1650,8 @@ bool nsGenericHTMLElement::IsFormControlDefaultFocusable(
//----------------------------------------------------------------------
nsGenericHTMLFormElement::nsGenericHTMLFormElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, FormControlType aType)
already_AddRefed<mozilla::dom::NodeInfo>&& 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<HTMLFormElement*>(element), aBindToTree);
SetFormInternal(static_cast<HTMLFormElement*>(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<mozilla::dom::NodeInfo>&& 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

Просмотреть файл

@ -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<mozilla::dom::NodeInfo>&& 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<mozilla::dom::NodeInfo>&& 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<mozilla::dom::NodeInfo>&& 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