/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2001 Dirk Mueller (mueller@kde.org)
 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#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/events/event.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/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/html/custom/element_internals.h"
#include "third_party/blink/renderer/core/html/forms/form_controller.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_control_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.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"
#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/heap/heap.h"
#include "third_party/blink/renderer/platform/text/bidi_text_run.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"

namespace blink {

class FormAttributeTargetObserver : public IdTargetObserver {
 public:
  FormAttributeTargetObserver(const AtomicString& id, ListedElement*);

  void Trace(Visitor*) const override;
  void IdTargetChanged() override;

 private:
  Member<ListedElement> element_;
};

ListedElement::ListedElement()
    : has_validation_message_(false),
      form_was_set_by_parser_(false),
      will_validate_initialized_(false),
      will_validate_(true),
      is_valid_(true),
      validity_is_dirty_(false) {}

ListedElement::~ListedElement() {
  // We can't call setForm here because it contains virtual calls.
}

void ListedElement::Trace(Visitor* visitor) const {
  visitor->Trace(form_attribute_target_observer_);
  visitor->Trace(form_);
  visitor->Trace(validity_state_);
}

ValidityState* ListedElement::validity() {
  if (!validity_state_)
    validity_state_ = MakeGarbageCollected<ValidityState>(this);

  return validity_state_.Get();
}

void ListedElement::DidMoveToNewDocument(Document& old_document) {
  if (ToHTMLElement().FastHasAttribute(html_names::kFormAttr))
    SetFormAttributeTargetObserver(nullptr);
}

void ListedElement::InsertedInto(ContainerNode& insertion_point) {
  ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
  // Force traversal to find ancestor
  may_have_field_set_ancestor_ = true;
  data_list_ancestor_state_ = DataListAncestorState::kUnknown;
  UpdateWillValidateCache();

  if (!form_was_set_by_parser_ || !form_ ||
      NodeTraversal::HighestAncestorOrSelf(insertion_point) !=
          NodeTraversal::HighestAncestorOrSelf(*form_.Get()))
    ResetFormOwner();

  HTMLElement& element = ToHTMLElement();
  if (insertion_point.isConnected()) {
    if (element.FastHasAttribute(html_names::kFormAttr))
      ResetFormAttributeTargetObserver();
  }

  FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
  DisabledStateMightBeChanged();

  if (ClassSupportsStateRestore() && insertion_point.isConnected() &&
      !element.ContainingShadowRoot()) {
    element.GetDocument()
        .GetFormController()
        .InvalidateStatefulFormControlList();
  }

  // Trigger for elements outside of forms.
  if (!form_ && insertion_point.isConnected())
    element.GetDocument().DidAssociateFormControl(&element);
}

void ListedElement::RemovedFrom(ContainerNode& insertion_point) {
  FieldSetAncestorsSetNeedsValidityCheck(&insertion_point);
  HideVisibleValidationMessage();
  has_validation_message_ = false;
  ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
  data_list_ancestor_state_ = DataListAncestorState::kUnknown;
  UpdateWillValidateCache();

  HTMLElement& element = ToHTMLElement();
  if (insertion_point.isConnected() &&
      element.FastHasAttribute(html_names::kFormAttr)) {
    SetFormAttributeTargetObserver(nullptr);
    ResetFormOwner();
  } else {
    // If the form and element are both in the same tree, preserve the
    // connection to the form.  Otherwise, null out our form and remove
    // ourselves from the form's list of elements.
    if (form_ && NodeTraversal::HighestAncestorOrSelf(element) !=
                     NodeTraversal::HighestAncestorOrSelf(*form_.Get()))
      ResetFormOwner();
  }

  DisabledStateMightBeChanged();

  if (ClassSupportsStateRestore() && insertion_point.isConnected() &&
      !element.ContainingShadowRoot() &&
      !insertion_point.ContainingShadowRoot()) {
    element.GetDocument()
        .GetFormController()
        .InvalidateStatefulFormControlList();
  }
}

HTMLFormElement* ListedElement::FindAssociatedForm(
    const HTMLElement* element,
    const AtomicString& form_id,
    HTMLFormElement* form_ancestor) {
  // 3. If the element is reassociateable, has a form content attribute, and
  // is itself in a Document, then run these substeps:
  if (!form_id.IsNull() && element->isConnected()) {
    // 3.1. If the first element in the Document to have an ID that is
    // case-sensitively equal to the element's form content attribute's
    // value is a form element, then associate the form-associated element
    // with that form element.
    // 3.2. Abort the "reset the form owner" steps.
    Element* new_form_candidate =
        element->GetTreeScope().getElementById(form_id);
    return DynamicTo<HTMLFormElement>(new_form_candidate);
  }
  // 4. Otherwise, if the form-associated element in question has an ancestor
  // form element, then associate the form-associated element with the nearest
  // such ancestor form element.
  return form_ancestor;
}

void ListedElement::FormRemovedFromTree(const Node& form_root) {
  DCHECK(form_);
  if (NodeTraversal::HighestAncestorOrSelf(ToHTMLElement()) == form_root)
    return;
  ResetFormOwner();
}

void ListedElement::AssociateByParser(HTMLFormElement* form) {
  if (form && form->isConnected()) {
    form_was_set_by_parser_ = true;
    SetForm(form);
    form->DidAssociateByParser();
  }
}

void ListedElement::SetForm(HTMLFormElement* new_form) {
  if (form_.Get() == new_form)
    return;
  WillChangeForm();
  if (form_)
    form_->Disassociate(*this);
  if (new_form) {
    form_ = new_form;
    form_->Associate(*this);
  } else {
    form_ = nullptr;
  }
  DidChangeForm();
}

void ListedElement::WillChangeForm() {
  FormOwnerSetNeedsValidityCheck();
}

void ListedElement::DidChangeForm() {
  if (!form_was_set_by_parser_ && form_ && form_->isConnected()) {
    auto& element = ToHTMLElement();
    element.GetDocument().DidAssociateFormControl(&element);
  }
  FormOwnerSetNeedsValidityCheck();
}

void ListedElement::FormOwnerSetNeedsValidityCheck() {
  if (HTMLFormElement* form = Form()) {
    form->PseudoStateChanged(CSSSelector::kPseudoValid);
    form->PseudoStateChanged(CSSSelector::kPseudoInvalid);
  }
}

void ListedElement::FieldSetAncestorsSetNeedsValidityCheck(Node* node) {
  if (!node)
    return;
  if (!may_have_field_set_ancestor_)
    return;
  for (auto* 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 ListedElement::ResetFormOwner() {
  form_was_set_by_parser_ = false;
  HTMLElement& element = ToHTMLElement();
  const AtomicString& form_id(element.FastGetAttribute(html_names::kFormAttr));
  HTMLFormElement* nearest_form = element.FindFormAncestor();
  // 1. If the element's form owner is not null, and either the element is not
  // reassociateable or its form content attribute is not present, and the
  // element's form owner is its nearest form element ancestor after the
  // change to the ancestor chain, then do nothing, and abort these steps.
  if (form_ && form_id.IsNull() && form_.Get() == nearest_form)
    return;

  SetForm(FindAssociatedForm(&element, form_id, nearest_form));
}

void ListedElement::FormAttributeChanged() {
  ResetFormOwner();
  ResetFormAttributeTargetObserver();
}

bool ListedElement::RecalcWillValidate() const {
  const HTMLElement& element = ToHTMLElement();
  if (data_list_ancestor_state_ == DataListAncestorState::kUnknown) {
    if (Traversal<HTMLDataListElement>::FirstAncestor(element))
      data_list_ancestor_state_ = DataListAncestorState::kInsideDataList;
    else
      data_list_ancestor_state_ = DataListAncestorState::kNotInsideDataList;
  }
  return data_list_ancestor_state_ ==
             DataListAncestorState::kNotInsideDataList &&
         !element.IsDisabledFormControl() &&
         !element.FastHasAttribute(html_names::kReadonlyAttr);
}

bool ListedElement::WillValidate() const {
  if (!will_validate_initialized_ ||
      data_list_ancestor_state_ == DataListAncestorState::kUnknown) {
    const_cast<ListedElement*>(this)->UpdateWillValidateCache();
  } else {
    // If the following assertion fails, UpdateWillValidateCache() is not
    // called correctly when something which changes RecalcWillValidate() result
    // is updated.
    DCHECK_EQ(will_validate_, RecalcWillValidate());
  }
  return will_validate_;
}

void ListedElement::UpdateWillValidateCache() {
  // 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();
}

bool ListedElement::CustomError() const {
  return !custom_validation_message_.IsEmpty();
}

bool ListedElement::HasBadInput() const {
  return false;
}

bool ListedElement::PatternMismatch() const {
  return false;
}

bool ListedElement::RangeOverflow() const {
  return false;
}

bool ListedElement::RangeUnderflow() const {
  return false;
}

bool ListedElement::StepMismatch() const {
  return false;
}

bool ListedElement::TooLong() const {
  return false;
}

bool ListedElement::TooShort() const {
  return false;
}

bool ListedElement::TypeMismatch() const {
  return false;
}

bool ListedElement::Valid() const {
  bool some_error = TypeMismatch() || StepMismatch() || RangeUnderflow() ||
                    RangeOverflow() || TooLong() || TooShort() ||
                    PatternMismatch() || ValueMissing() || HasBadInput() ||
                    CustomError();
  return !some_error;
}

bool ListedElement::ValueMissing() const {
  return false;
}

String ListedElement::CustomValidationMessage() const {
  return custom_validation_message_;
}

void ListedElement::SetCustomValidationMessage(const String& message) {
  custom_validation_message_ = message;
}

String ListedElement::validationMessage() const {
  return ToHTMLElement().willValidate() && CustomError()
             ? custom_validation_message_
             : String();
}

String ListedElement::ValidationSubMessage() const {
  return String();
}

void ListedElement::setCustomValidity(const String& error) {
  SetCustomValidationMessage(error);
  SetNeedsValidityCheck();
}

void ListedElement::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 = ToHTMLElement().GetLayoutObject()->Style()->Direction();
  }
}

void ListedElement::UpdateVisibleValidationMessage() {
  const Element& element = ValidationAnchor();
  Page* page = element.GetDocument().GetPage();
  if (!page || !page->IsPageVisible() || element.GetDocument().UnloadStarted())
    return;
  if (page->Paused())
    return;
  String message;
  if (element.GetLayoutObject() && WillValidate() &&
      ToHTMLElement().IsShadowIncludingInclusiveAncestorOf(element))
    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(element);
  } else {
    FindCustomValidationMessageTextDirection(message, message_dir, sub_message,
                                             sub_message_dir);
  }
  client->ShowValidationMessage(element, message, message_dir, sub_message,
                                sub_message_dir);
}

void ListedElement::HideVisibleValidationMessage() {
  if (!has_validation_message_)
    return;

  if (auto* client = GetValidationMessageClient())
    client->HideValidationMessage(ValidationAnchor());
}

bool ListedElement::IsValidationMessageVisible() const {
  if (!has_validation_message_)
    return false;

  if (auto* client = GetValidationMessageClient()) {
    return client->IsValidationMessageVisible(ValidationAnchor());
  }
  return false;
}

ValidationMessageClient* ListedElement::GetValidationMessageClient() const {
  if (Page* page = ToHTMLElement().GetDocument().GetPage())
    return &page->GetValidationMessageClient();
  return nullptr;
}

Element& ListedElement::ValidationAnchor() const {
  return const_cast<HTMLElement&>(ToHTMLElement());
}

bool ListedElement::ValidationAnchorOrHostIsFocusable() const {
  const Element& anchor = ValidationAnchor();
  const HTMLElement& host = ToHTMLElement();
  if (anchor.IsFocusable())
    return true;
  if (&anchor == &host)
    return false;
  return host.IsFocusable();
}

bool ListedElement::checkValidity(List* unhandled_invalid_controls) {
  if (IsNotCandidateOrValid())
    return true;
  HTMLElement& element = ToHTMLElement();
  Document* original_document = &element.GetDocument();
  DispatchEventResult dispatch_result = element.DispatchEvent(
      *Event::CreateCancelable(event_type_names::kInvalid));
  if (dispatch_result == DispatchEventResult::kNotCanceled &&
      unhandled_invalid_controls && element.isConnected() &&
      original_document == element.GetDocument())
    unhandled_invalid_controls->push_back(this);
  return false;
}

void ListedElement::ShowValidationMessage() {
  Element& element = ValidationAnchor();
  element.scrollIntoViewIfNeeded(false);
  if (element.IsFocusable())
    element.focus();
  else
    ToHTMLElement().focus();
  UpdateVisibleValidationMessage();
}

bool ListedElement::reportValidity() {
  List unhandled_invalid_controls;
  bool is_valid = checkValidity(&unhandled_invalid_controls);
  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.
  HTMLElement& element = ToHTMLElement();
  element.GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kForm);
  if (element.IsFocusable()) {
    ShowValidationMessage();
    return false;
  }
  if (element.GetDocument().GetFrame()) {
    String message(
        "An invalid form control with name='%name' is not focusable.");
    message.Replace("%name", GetName());
    element.GetDocument().AddConsoleMessage(
        MakeGarbageCollected<ConsoleMessage>(
            mojom::ConsoleMessageSource::kRendering,
            mojom::ConsoleMessageLevel::kError, message));
  }
  return false;
}

bool ListedElement::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_;
}

bool ListedElement::IsNotCandidateOrValid() {
  // Apply Element::willValidate(), not ListedElement::WillValidate(), because
  // some elements override willValidate().
  return !ToHTMLElement().willValidate() || IsValidElement();
}

void ListedElement::SetNeedsValidityCheck() {
  HTMLElement& element = ToHTMLElement();
  if (!validity_is_dirty_) {
    validity_is_dirty_ = true;
    FormOwnerSetNeedsValidityCheck();
    FieldSetAncestorsSetNeedsValidityCheck(element.parentNode());
    element.PseudoStateChanged(CSSSelector::kPseudoValid);
    element.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.
    element.GetDocument()
        .GetTaskRunner(TaskType::kDOMManipulation)
        ->PostTask(FROM_HERE,
                   WTF::Bind(&ListedElement::UpdateVisibleValidationMessage,
                             WrapPersistent(this)));
  }
}

void ListedElement::DisabledAttributeChanged() {
  UpdateWillValidateCache();
  HTMLElement& element = ToHTMLElement();
  element.PseudoStateChanged(CSSSelector::kPseudoDisabled);
  element.PseudoStateChanged(CSSSelector::kPseudoEnabled);
  DisabledStateMightBeChanged();
}

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 (auto* ancestor = Traversal<HTMLElement>::FirstAncestor(ToHTMLElement());
       ancestor; ancestor = Traversal<HTMLElement>::FirstAncestor(*ancestor)) {
    if (IsA<HTMLLegendElement>(*ancestor)) {
      last_legend_ancestor = ancestor;
      continue;
    }
    if (!IsA<HTMLFieldSetElement>(*ancestor))
      continue;
    may_have_field_set_ancestor_ = true;
    if (ancestor->IsDisabledFormControl()) {
      auto* fieldset = To<HTMLFieldSetElement>(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().FastHasAttribute(html_names::kDisabledAttr))
    return true;
  if (ancestor_disabled_state_ == AncestorDisabledState::kUnknown)
    UpdateAncestorDisabledState();
  return ancestor_disabled_state_ == AncestorDisabledState::kDisabled;
}

bool ListedElement::ClassSupportsStateRestore() const {
  return false;
}

bool ListedElement::ShouldSaveAndRestoreFormControlState() const {
  return false;
}

FormControlState ListedElement::SaveFormControlState() const {
  return FormControlState();
}

void ListedElement::RestoreFormControlState(const FormControlState& state) {}

void ListedElement::NotifyFormStateChanged() {
  Document& doc = ToHTMLElement().GetDocument();
  // This can be called during fragment parsing as a result of option
  // selection before the document is active (or even in a frame).
  if (!doc.IsActive())
    return;
  doc.GetFrame()->Client()->DidUpdateCurrentHistoryItem();
}

void ListedElement::TakeStateAndRestore() {
  if (ClassSupportsStateRestore()) {
    ToHTMLElement().GetDocument().GetFormController().RestoreControlStateFor(
        *this);
  }
}

void ListedElement::SetFormAttributeTargetObserver(
    FormAttributeTargetObserver* new_observer) {
  if (form_attribute_target_observer_)
    form_attribute_target_observer_->Unregister();
  form_attribute_target_observer_ = new_observer;
}

void ListedElement::ResetFormAttributeTargetObserver() {
  HTMLElement& element = ToHTMLElement();
  const AtomicString& form_id(element.FastGetAttribute(html_names::kFormAttr));
  if (!form_id.IsNull() && element.isConnected()) {
    SetFormAttributeTargetObserver(
        MakeGarbageCollected<FormAttributeTargetObserver>(form_id, this));
  } else {
    SetFormAttributeTargetObserver(nullptr);
  }
}

void ListedElement::FormAttributeTargetChanged() {
  ResetFormOwner();
}

const AtomicString& ListedElement::GetName() const {
  const AtomicString& name = ToHTMLElement().GetNameAttribute();
  return name.IsNull() ? g_empty_atom : name;
}

bool ListedElement::IsFormControlElementWithState() const {
  return false;
}

bool ListedElement::IsElementInternals() const {
  return false;
}

ListedElement* ListedElement::From(Element& element) {
  auto* html_element = DynamicTo<HTMLElement>(element);
  if (!html_element)
    return nullptr;
  if (auto* form_control_element = DynamicTo<HTMLFormControlElement>(element))
    return form_control_element;
  if (html_element->IsFormAssociatedCustomElement())
    return &element.EnsureElementInternals();
  if (auto* object = DynamicTo<HTMLObjectElement>(html_element))
    return object;
  return nullptr;
}

const HTMLElement& ListedElement::ToHTMLElement() const {
  if (auto* form_control_element = DynamicTo<HTMLFormControlElement>(this))
    return *form_control_element;
  if (IsElementInternals())
    return To<ElementInternals>(*this).Target();
  return ToHTMLObjectElementFromListedElement(*this);
}

HTMLElement& ListedElement::ToHTMLElement() {
  return const_cast<HTMLElement&>(
      static_cast<const ListedElement&>(*this).ToHTMLElement());
}

FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id,
                                                         ListedElement* element)
    : IdTargetObserver(
          element->ToHTMLElement().GetTreeScope().GetIdTargetObserverRegistry(),
          id),
      element_(element) {}

void FormAttributeTargetObserver::Trace(Visitor* visitor) const {
  visitor->Trace(element_);
  IdTargetObserver::Trace(visitor);
}

void FormAttributeTargetObserver::IdTargetChanged() {
  element_->FormAttributeTargetChanged();
}

}  // namespace blink
