diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc | 272 |
1 files changed, 18 insertions, 254 deletions
diff --git a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc index eab7f277272..25e03d1b887 100644 --- a/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc +++ b/chromium/third_party/blink/renderer/core/html/forms/html_form_control_element.cc @@ -24,24 +24,19 @@ #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h" -#include "third_party/blink/public/platform/task_type.h" +#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" #include "third_party/blink/renderer/core/dom/element_traversal.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h" #include "third_party/blink/renderer/core/frame/use_counter.h" -#include "third_party/blink/renderer/core/html/forms/html_data_list_element.h" -#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/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" #include "third_party/blink/renderer/core/layout/layout_object.h" -#include "third_party/blink/renderer/core/page/page.h" -#include "third_party/blink/renderer/core/page/validation_message_client.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" -#include "third_party/blink/renderer/platform/text/bidi_text_run.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { @@ -50,14 +45,8 @@ using namespace html_names; HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tag_name, Document& document) - : LabelableElement(tag_name, document), + : HTMLElement(tag_name, document), autofill_state_(WebAutofillState::kNotFilled), - data_list_ancestor_state_(kUnknown), - has_validation_message_(false), - will_validate_initialized_(false), - will_validate_(true), - is_valid_(true), - validity_is_dirty_(false), blocks_form_submission_(false) { SetHasCustomStyleCallbacks(); static unsigned next_free_unique_id = 0; @@ -66,20 +55,24 @@ HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tag_name, HTMLFormControlElement::~HTMLFormControlElement() = default; -void HTMLFormControlElement::Trace(blink::Visitor* visitor) { +void HTMLFormControlElement::Trace(Visitor* visitor) { ListedElement::Trace(visitor); - LabelableElement::Trace(visitor); + HTMLElement::Trace(visitor); } -String HTMLFormControlElement::formAction() const { +void HTMLFormControlElement::formAction(USVStringOrTrustedURL& result) const { const AtomicString& action = FastGetAttribute(kFormactionAttr); - if (action.IsEmpty()) - return GetDocument().Url(); - return GetDocument().CompleteURL(StripLeadingAndTrailingHTMLSpaces(action)); + if (action.IsEmpty()) { + result.SetUSVString(GetDocument().Url()); + return; + } + result.SetUSVString( + GetDocument().CompleteURL(StripLeadingAndTrailingHTMLSpaces(action))); } -void HTMLFormControlElement::setFormAction(const AtomicString& value) { - setAttribute(kFormactionAttr, value); +void HTMLFormControlElement::setFormAction(const USVStringOrTrustedURL& value, + ExceptionState& exception_state) { + setAttribute(kFormactionAttr, value, exception_state); } String HTMLFormControlElement::formEnctype() const { @@ -134,7 +127,7 @@ void HTMLFormControlElement::ParseAttribute( UseCounter::Count(GetDocument(), WebFeature::kFormAttribute); } else if (name == kReadonlyAttr) { if (params.old_value.IsNull() != params.new_value.IsNull()) { - SetNeedsWillValidateCheck(); + UpdateWillValidateCache(); PseudoStateChanged(CSSSelector::kPseudoReadOnly); PseudoStateChanged(CSSSelector::kPseudoReadWrite); if (LayoutObject* o = GetLayoutObject()) @@ -157,7 +150,6 @@ void HTMLFormControlElement::DisabledAttributeChanged() { // <fieldset> while tree traversal. EventDispatchForbiddenScope event_forbidden; - SetNeedsWillValidateCheck(); ListedElement::DisabledAttributeChanged(); if (LayoutObject* o = GetLayoutObject()) o->InvalidateIfControlStateChanged(kEnabledControlState); @@ -261,65 +253,28 @@ void HTMLFormControlElement::DidMoveToNewDocument(Document& old_document) { Node::InsertionNotificationRequest HTMLFormControlElement::InsertedInto( ContainerNode& insertion_point) { - data_list_ancestor_state_ = kUnknown; HTMLElement::InsertedInto(insertion_point); ListedElement::InsertedInto(insertion_point); - SetNeedsWillValidateCheck(); - FieldSetAncestorsSetNeedsValidityCheck(&insertion_point); - - // Trigger for elements outside of forms. - if (!formOwner() && insertion_point.isConnected()) - GetDocument().DidAssociateFormControl(this); - return kInsertionDone; } void HTMLFormControlElement::RemovedFrom(ContainerNode& insertion_point) { - FieldSetAncestorsSetNeedsValidityCheck(&insertion_point); - HideVisibleValidationMessage(); - has_validation_message_ = false; - data_list_ancestor_state_ = kUnknown; HTMLElement::RemovedFrom(insertion_point); ListedElement::RemovedFrom(insertion_point); - SetNeedsWillValidateCheck(); } void HTMLFormControlElement::WillChangeForm() { ListedElement::WillChangeForm(); - FormOwnerSetNeedsValidityCheck(); if (formOwner() && CanBeSuccessfulSubmitButton()) formOwner()->InvalidateDefaultButtonStyle(); } void HTMLFormControlElement::DidChangeForm() { ListedElement::DidChangeForm(); - FormOwnerSetNeedsValidityCheck(); if (formOwner() && isConnected() && CanBeSuccessfulSubmitButton()) formOwner()->InvalidateDefaultButtonStyle(); } -void HTMLFormControlElement::FormOwnerSetNeedsValidityCheck() { - if (HTMLFormElement* form = formOwner()) { - form->PseudoStateChanged(CSSSelector::kPseudoValid); - form->PseudoStateChanged(CSSSelector::kPseudoInvalid); - } -} - -void HTMLFormControlElement::FieldSetAncestorsSetNeedsValidityCheck( - Node* node) { - if (!node) - return; - if (!may_have_field_set_ancestor_) - return; - for (HTMLFieldSetElement* field_set = - Traversal<HTMLFieldSetElement>::FirstAncestorOrSelf(*node); - field_set; - field_set = Traversal<HTMLFieldSetElement>::FirstAncestor(*field_set)) { - field_set->PseudoStateChanged(CSSSelector::kPseudoValid); - field_set->PseudoStateChanged(CSSSelector::kPseudoInvalid); - } -} - void HTMLFormControlElement::DispatchChangeEvent() { DispatchScopedEvent(*Event::CreateBubble(event_type_names::kChange)); } @@ -378,164 +333,8 @@ int HTMLFormControlElement::tabIndex() const { return Element::tabIndex(); } -bool HTMLFormControlElement::RecalcWillValidate() const { - if (data_list_ancestor_state_ == kUnknown) { - if (Traversal<HTMLDataListElement>::FirstAncestor(*this)) - data_list_ancestor_state_ = kInsideDataList; - else - data_list_ancestor_state_ = kNotInsideDataList; - } - return data_list_ancestor_state_ == kNotInsideDataList && - !IsDisabledOrReadOnly(); -} - bool HTMLFormControlElement::willValidate() const { - if (!will_validate_initialized_ || data_list_ancestor_state_ == kUnknown) { - const_cast<HTMLFormControlElement*>(this)->SetNeedsWillValidateCheck(); - } else { - // If the following assertion fails, setNeedsWillValidateCheck() is not - // called correctly when something which changes recalcWillValidate() result - // is updated. - DCHECK_EQ(will_validate_, RecalcWillValidate()); - } - return will_validate_; -} - -void HTMLFormControlElement::SetNeedsWillValidateCheck() { - // We need to recalculate willValidate immediately because willValidate change - // can causes style change. - bool new_will_validate = RecalcWillValidate(); - if (will_validate_initialized_ && will_validate_ == new_will_validate) - return; - will_validate_initialized_ = true; - will_validate_ = new_will_validate; - // Needs to force SetNeedsValidityCheck() to invalidate validity state of - // FORM/FIELDSET. If this element updates willValidate twice and - // IsValidElement() is not called between them, the second call of this - // function still has validity_is_dirty_==true, which means - // SetNeedsValidityCheck() doesn't invalidate validity state of - // FORM/FIELDSET. - validity_is_dirty_ = false; - SetNeedsValidityCheck(); - // No need to trigger style recalculation here because - // SetNeedsValidityCheck() does it in the right away. This relies on - // the assumption that Valid() is always true if willValidate() is false. - - if (!will_validate_) - HideVisibleValidationMessage(); -} - -void HTMLFormControlElement::FindCustomValidationMessageTextDirection( - const String& message, - TextDirection& message_dir, - String& sub_message, - TextDirection& sub_message_dir) { - message_dir = DetermineDirectionality(message); - if (!sub_message.IsEmpty()) - sub_message_dir = GetLayoutObject()->Style()->Direction(); -} - -void HTMLFormControlElement::UpdateVisibleValidationMessage() { - Page* page = GetDocument().GetPage(); - if (!page || !page->IsPageVisible() || GetDocument().UnloadStarted()) - return; - if (page->Paused()) - return; - String message; - if (GetLayoutObject() && willValidate()) - message = validationMessage().StripWhiteSpace(); - - has_validation_message_ = true; - ValidationMessageClient* client = &page->GetValidationMessageClient(); - TextDirection message_dir = TextDirection::kLtr; - TextDirection sub_message_dir = TextDirection::kLtr; - String sub_message = ValidationSubMessage().StripWhiteSpace(); - if (message.IsEmpty()) { - client->HideValidationMessage(*this); - } else { - FindCustomValidationMessageTextDirection(message, message_dir, sub_message, - sub_message_dir); - } - client->ShowValidationMessage(*this, message, message_dir, sub_message, - sub_message_dir); -} - -void HTMLFormControlElement::HideVisibleValidationMessage() { - if (!has_validation_message_) - return; - - if (ValidationMessageClient* client = GetValidationMessageClient()) - client->HideValidationMessage(*this); -} - -bool HTMLFormControlElement::IsValidationMessageVisible() const { - if (!has_validation_message_) - return false; - - ValidationMessageClient* client = GetValidationMessageClient(); - if (!client) - return false; - - return client->IsValidationMessageVisible(*this); -} - -ValidationMessageClient* HTMLFormControlElement::GetValidationMessageClient() - const { - Page* page = GetDocument().GetPage(); - if (!page) - return nullptr; - - return &page->GetValidationMessageClient(); -} - -bool HTMLFormControlElement::checkValidity( - HeapVector<Member<HTMLFormControlElement>>* unhandled_invalid_controls, - CheckValidityEventBehavior event_behavior) { - if (!willValidate()) - return true; - if (IsValidElement()) - return true; - if (event_behavior != kCheckValidityDispatchInvalidEvent) - return false; - Document* original_document = &GetDocument(); - DispatchEventResult dispatch_result = - DispatchEvent(*Event::CreateCancelable(event_type_names::kInvalid)); - if (dispatch_result == DispatchEventResult::kNotCanceled && - unhandled_invalid_controls && isConnected() && - original_document == GetDocument()) - unhandled_invalid_controls->push_back(this); - return false; -} - -void HTMLFormControlElement::ShowValidationMessage() { - scrollIntoViewIfNeeded(false); - focus(); - UpdateVisibleValidationMessage(); -} - -bool HTMLFormControlElement::reportValidity() { - HeapVector<Member<HTMLFormControlElement>> unhandled_invalid_controls; - bool is_valid = checkValidity(&unhandled_invalid_controls, - kCheckValidityDispatchInvalidEvent); - if (is_valid || unhandled_invalid_controls.IsEmpty()) - return is_valid; - DCHECK_EQ(unhandled_invalid_controls.size(), 1u); - DCHECK_EQ(unhandled_invalid_controls[0].Get(), this); - // Update layout now before calling isFocusable(), which has - // !layoutObject()->needsLayout() assertion. - GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets(); - if (IsFocusable()) { - ShowValidationMessage(); - return false; - } - if (GetDocument().GetFrame()) { - String message( - "An invalid form control with name='%name' is not focusable."); - message.Replace("%name", GetName()); - GetDocument().AddConsoleMessage(ConsoleMessage::Create( - kRenderingMessageSource, kErrorMessageLevel, message)); - } - return false; + return ListedElement::WillValidate(); } bool HTMLFormControlElement::MatchesValidityPseudoClasses() const { @@ -543,42 +342,7 @@ bool HTMLFormControlElement::MatchesValidityPseudoClasses() const { } bool HTMLFormControlElement::IsValidElement() { - if (validity_is_dirty_) { - is_valid_ = !willValidate() || Valid(); - validity_is_dirty_ = false; - } else { - // If the following assertion fails, setNeedsValidityCheck() is not - // called correctly when something which changes validity is updated. - DCHECK_EQ(is_valid_, (!willValidate() || Valid())); - } - return is_valid_; -} - -void HTMLFormControlElement::SetNeedsValidityCheck() { - if (!validity_is_dirty_) { - validity_is_dirty_ = true; - FormOwnerSetNeedsValidityCheck(); - FieldSetAncestorsSetNeedsValidityCheck(parentNode()); - PseudoStateChanged(CSSSelector::kPseudoValid); - PseudoStateChanged(CSSSelector::kPseudoInvalid); - } - - // Updates only if this control already has a validation message. - if (IsValidationMessageVisible()) { - // Calls UpdateVisibleValidationMessage() even if is_valid_ is not - // changed because a validation message can be changed. - GetDocument() - .GetTaskRunner(TaskType::kDOMManipulation) - ->PostTask( - FROM_HERE, - WTF::Bind(&HTMLFormControlElement::UpdateVisibleValidationMessage, - WrapPersistent(this))); - } -} - -void HTMLFormControlElement::setCustomValidity(const String& error) { - ListedElement::setCustomValidity(error); - SetNeedsValidityCheck(); + return ListedElement::IsValidElement(); } void HTMLFormControlElement::DispatchBlurEvent( |