Commit 784f74e8 authored by Kent Tamura's avatar Kent Tamura Committed by Commit Bot

Form-associated custom elements: Refactor 'disabled' state handling code

Move 'disabled' state handling code from HTMLFormControlElement to
ListedElement. This is a preparation to support 'disabledStateChangedCallback'
of form-associated custom elmeents.

This CL has no behavior changes.

Bug: 905922
Bug: https://github.com/w3c/webcomponents/issues/187
Change-Id: I34703dd7b167be13e4b19324b5e931bda224a866
Reviewed-on: https://chromium-review.googlesource.com/c/1353039
Commit-Queue: Kent Tamura <tkent@chromium.org>
Reviewed-by: default avatarHayato Ito <hayato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612032}
parent a324fc57
......@@ -34,7 +34,6 @@
#include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
#include "third_party/blink/renderer/core/html/forms/validity_state.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
......@@ -53,9 +52,7 @@ HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tag_name,
Document& document)
: LabelableElement(tag_name, document),
autofill_state_(WebAutofillState::kNotFilled),
ancestor_disabled_state_(kAncestorDisabledStateUnknown),
data_list_ancestor_state_(kUnknown),
may_have_field_set_ancestor_(true),
has_validation_message_(false),
will_validate_initialized_(false),
will_validate_(true),
......@@ -112,40 +109,6 @@ bool HTMLFormControlElement::FormNoValidate() const {
return FastHasAttribute(kFormnovalidateAttr);
}
void HTMLFormControlElement::UpdateAncestorDisabledState() const {
if (!may_have_field_set_ancestor_) {
ancestor_disabled_state_ = kAncestorDisabledStateEnabled;
return;
}
may_have_field_set_ancestor_ = false;
// <fieldset> element of which |disabled| attribute affects |this| element.
HTMLFieldSetElement* disabled_fieldset_ancestor = nullptr;
ContainerNode* last_legend_ancestor = nullptr;
for (HTMLElement* ancestor = Traversal<HTMLElement>::FirstAncestor(*this);
ancestor; ancestor = Traversal<HTMLElement>::FirstAncestor(*ancestor)) {
if (IsHTMLLegendElement(*ancestor))
last_legend_ancestor = ancestor;
if (IsHTMLFieldSetElement(*ancestor)) {
may_have_field_set_ancestor_ = true;
if (ancestor->IsDisabledFormControl()) {
auto* fieldset = ToHTMLFieldSetElement(ancestor);
if (last_legend_ancestor && last_legend_ancestor == fieldset->Legend())
continue;
disabled_fieldset_ancestor = fieldset;
break;
}
}
}
ancestor_disabled_state_ = disabled_fieldset_ancestor
? kAncestorDisabledStateDisabled
: kAncestorDisabledStateEnabled;
}
void HTMLFormControlElement::AncestorDisabledStateWasChanged() {
ancestor_disabled_state_ = kAncestorDisabledStateUnknown;
DisabledAttributeChanged();
}
void HTMLFormControlElement::Reset() {
SetAutofillState(WebAutofillState::kNotFilled);
ResetImpl();
......@@ -195,8 +158,7 @@ void HTMLFormControlElement::DisabledAttributeChanged() {
EventDispatchForbiddenScope event_forbidden;
SetNeedsWillValidateCheck();
PseudoStateChanged(CSSSelector::kPseudoDisabled);
PseudoStateChanged(CSSSelector::kPseudoEnabled);
ListedElement::DisabledAttributeChanged();
if (LayoutObject* o = GetLayoutObject())
o->InvalidateIfControlStateChanged(kEnabledControlState);
......@@ -299,13 +261,10 @@ void HTMLFormControlElement::DidMoveToNewDocument(Document& old_document) {
Node::InsertionNotificationRequest HTMLFormControlElement::InsertedInto(
ContainerNode& insertion_point) {
ancestor_disabled_state_ = kAncestorDisabledStateUnknown;
// Force traversal to find ancestor
may_have_field_set_ancestor_ = true;
data_list_ancestor_state_ = kUnknown;
SetNeedsWillValidateCheck();
HTMLElement::InsertedInto(insertion_point);
ListedElement::InsertedInto(insertion_point);
SetNeedsWillValidateCheck();
FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
// Trigger for elements outside of forms.
......@@ -319,11 +278,10 @@ void HTMLFormControlElement::RemovedFrom(ContainerNode& insertion_point) {
FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
HideVisibleValidationMessage();
has_validation_message_ = false;
ancestor_disabled_state_ = kAncestorDisabledStateUnknown;
data_list_ancestor_state_ = kUnknown;
SetNeedsWillValidateCheck();
HTMLElement::RemovedFrom(insertion_point);
ListedElement::RemovedFrom(insertion_point);
SetNeedsWillValidateCheck();
}
void HTMLFormControlElement::WillChangeForm() {
......@@ -371,18 +329,13 @@ HTMLFormElement* HTMLFormControlElement::formOwner() const {
}
bool HTMLFormControlElement::IsDisabledFormControl() const {
if (FastHasAttribute(kDisabledAttr))
return true;
// Since the MHTML is loaded in sandboxing mode with form submission and
// script execution disabled, we should gray out all form control elements
// to indicate that the form cannot be worked on.
if (GetDocument().Fetcher()->Archive())
return true;
if (ancestor_disabled_state_ == kAncestorDisabledStateUnknown)
UpdateAncestorDisabledState();
return ancestor_disabled_state_ == kAncestorDisabledStateDisabled;
return IsActuallyDisabled();
}
bool HTMLFormControlElement::MatchesEnabledPseudoClass() const {
......
......@@ -62,8 +62,6 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
void setFormMethod(const AtomicString&);
bool FormNoValidate() const;
void AncestorDisabledStateWasChanged();
void Reset();
void DispatchChangeEvent();
......@@ -162,7 +160,7 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
void AttributeChanged(const AttributeModificationParams&) override;
void ParseAttribute(const AttributeModificationParams&) override;
virtual void RequiredAttributeChanged();
virtual void DisabledAttributeChanged();
void DisabledAttributeChanged() override;
void AttachLayoutTree(AttachContext&) override;
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
......@@ -194,7 +192,6 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
bool IsValidElement() override;
bool MatchesValidityPseudoClasses() const override;
void UpdateAncestorDisabledState() const;
ValidationMessageClient* GetValidationMessageClient() const;
......@@ -208,16 +205,8 @@ class CORE_EXPORT HTMLFormControlElement : public LabelableElement,
WebString autofill_section_;
enum WebAutofillState autofill_state_;
enum AncestorDisabledState {
kAncestorDisabledStateUnknown,
kAncestorDisabledStateEnabled,
kAncestorDisabledStateDisabled
};
mutable AncestorDisabledState ancestor_disabled_state_;
enum DataListAncestorState { kUnknown, kInsideDataList, kNotInsideDataList };
mutable enum DataListAncestorState data_list_ancestor_state_;
mutable bool may_have_field_set_ancestor_ : 1;
bool has_validation_message_ : 1;
// The initial value of will_validate_ depends on the derived class. We can't
......
......@@ -24,11 +24,14 @@
#include "third_party/blink/renderer/core/html/forms/listed_element.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/id_target_observer.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
#include "third_party/blink/renderer/core/html/forms/validity_state.h"
#include "third_party/blink/renderer/core/html/html_object_element.h"
#include "third_party/blink/renderer/core/html_names.h"
......@@ -77,6 +80,10 @@ void ListedElement::DidMoveToNewDocument(Document& old_document) {
}
void ListedElement::InsertedInto(ContainerNode& insertion_point) {
ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
// Force traversal to find ancestor
may_have_field_set_ancestor_ = true;
if (!form_was_set_by_parser_ || !form_ ||
NodeTraversal::HighestAncestorOrSelf(insertion_point) !=
NodeTraversal::HighestAncestorOrSelf(*form_.Get()))
......@@ -91,6 +98,8 @@ void ListedElement::InsertedInto(ContainerNode& insertion_point) {
}
void ListedElement::RemovedFrom(ContainerNode& insertion_point) {
ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
HTMLElement* element = ToHTMLElement(this);
if (insertion_point.isConnected() && element->FastHasAttribute(kFormAttr)) {
SetFormAttributeTargetObserver(nullptr);
......@@ -251,6 +260,58 @@ void ListedElement::setCustomValidity(const String& error) {
custom_validation_message_ = error;
}
void ListedElement::DisabledAttributeChanged() {
HTMLElement& element = ToHTMLElement(*this);
element.PseudoStateChanged(CSSSelector::kPseudoDisabled);
element.PseudoStateChanged(CSSSelector::kPseudoEnabled);
}
void ListedElement::UpdateAncestorDisabledState() const {
if (!may_have_field_set_ancestor_) {
ancestor_disabled_state_ = AncestorDisabledState::kEnabled;
return;
}
may_have_field_set_ancestor_ = false;
// <fieldset> element of which |disabled| attribute affects the
// target element.
HTMLFieldSetElement* disabled_fieldset_ancestor = nullptr;
ContainerNode* last_legend_ancestor = nullptr;
for (HTMLElement* ancestor =
Traversal<HTMLElement>::FirstAncestor(ToHTMLElement(*this));
ancestor; ancestor = Traversal<HTMLElement>::FirstAncestor(*ancestor)) {
if (IsHTMLLegendElement(*ancestor)) {
last_legend_ancestor = ancestor;
continue;
}
if (!IsHTMLFieldSetElement(*ancestor))
continue;
may_have_field_set_ancestor_ = true;
if (ancestor->IsDisabledFormControl()) {
auto* fieldset = ToHTMLFieldSetElement(ancestor);
if (last_legend_ancestor && last_legend_ancestor == fieldset->Legend())
continue;
disabled_fieldset_ancestor = fieldset;
break;
}
}
ancestor_disabled_state_ = disabled_fieldset_ancestor
? AncestorDisabledState::kDisabled
: AncestorDisabledState::kEnabled;
}
void ListedElement::AncestorDisabledStateWasChanged() {
ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
DisabledAttributeChanged();
}
bool ListedElement::IsActuallyDisabled() const {
if (ToHTMLElement(*this).FastHasAttribute(html_names::kDisabledAttr))
return true;
if (ancestor_disabled_state_ == AncestorDisabledState::kUnknown)
UpdateAncestorDisabledState();
return ancestor_disabled_state_ == AncestorDisabledState::kDisabled;
}
void ListedElement::SetFormAttributeTargetObserver(
FormAttributeTargetObserver* new_observer) {
if (form_attribute_target_observer_)
......
......@@ -93,6 +93,10 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
void InsertedInto(ContainerNode&);
void RemovedFrom(ContainerNode&);
void DidMoveToNewDocument(Document& old_document);
void AncestorDisabledStateWasChanged();
// https://html.spec.whatwg.org/multipage/semantics-other.html#concept-element-disabled
bool IsActuallyDisabled() const;
typedef HeapVector<Member<ListedElement>> List;
......@@ -115,7 +119,15 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
String CustomValidationMessage() const;
virtual void DisabledAttributeChanged();
// False; There are no FIELDSET ancestors.
// True; There might be a FIELDSET ancestor, and thre might be no
// FIELDSET ancestors.
mutable bool may_have_field_set_ancestor_ = true;
private:
void UpdateAncestorDisabledState() const;
void SetFormAttributeTargetObserver(FormAttributeTargetObserver*);
void ResetFormAttributeTargetObserver();
......@@ -125,6 +137,10 @@ class CORE_EXPORT ListedElement : public GarbageCollectedMixin {
String custom_validation_message_;
// If form_was_set_by_parser_ is true, form_ is always non-null.
bool form_was_set_by_parser_;
enum class AncestorDisabledState { kUnknown, kEnabled, kDisabled };
mutable AncestorDisabledState ancestor_disabled_state_ =
AncestorDisabledState::kUnknown;
};
CORE_EXPORT HTMLElement* ToHTMLElement(ListedElement*);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment