// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/autofill/content/renderer/password_autofill_agent.h"

#include <stddef.h>

#include <algorithm>
#include <iterator>
#include <memory>
#include <optional>
#include <ranges>
#include <string>
#include <utility>
#include <vector>

#include "base/check.h"
#include "base/check_deref.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/to_string.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "components/autofill/content/common/mojom/autofill_driver.mojom.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
#include "components/autofill/content/renderer/prefilled_values_detector.h"
#include "components/autofill/content/renderer/renderer_save_password_progress_logger.h"
#include "components/autofill/content/renderer/suggestion_properties.h"
#include "components/autofill/content/renderer/synchronous_form_cache.h"
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_debug_features.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/password_manager/core/common/password_manager_constants.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_util.h"
#include "components/safe_browsing/buildflags.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "content/public/renderer/render_frame.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/web/web_autofill_client.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_view.h"
#include "ui/base/page_transition_types.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "url/gurl.h"

using blink::WebAutofillState;
using blink::WebDocument;
using blink::WebDocumentLoader;
using blink::WebElement;
using blink::WebElementCollection;
using blink::WebFormControlElement;
using blink::WebFormElement;
using blink::WebFrame;
using blink::WebInputElement;
using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebSecurityOrigin;
using blink::WebString;
using blink::WebURL;
using blink::WebView;

using password_manager::util::IsRendererRecognizedCredentialForm;

namespace autofill {

namespace {

using form_util::GetFieldRendererId;
using form_util::GetFormByRendererId;
using form_util::GetFormControlByRendererId;
using form_util::GetFormRendererId;
using form_util::IsElementEditable;

using mojom::SubmissionIndicatorEvent;
using mojom::SubmissionSource;

constexpr auto kInputPassword = blink::mojom::FormControlType::kInputPassword;

// The size above which we stop triggering autocomplete.
const size_t kMaximumTextSizeForAutocomplete = 1000;

constexpr char kSubmissionSourceHistogram[] =
    "Autofill.SubmissionDetectionSource.PasswordAutofillAgent";

// Names of HTML attributes to show form and field signatures for debugging.
const char kDebugAttributeForFormSignature[] = "form_signature";
const char kDebugAttributeForAlternativeFormSignature[] =
    "alternative_form_signature";
const char kDebugAttributeForFieldSignature[] = "field_signature";
const char kDebugAttributeForParserAnnotations[] = "pm_parser_annotation";
const char kDebugAttributeForVisibility[] = "visibility_annotation";
// Name of HTML attribute that stores the copy of autofill tooltip for
// debugging.
constexpr char kDebugAttributeForAutofill[] = "autofill-information";

// HTML attribute that is used as a tooltip if
// `kAutofillShowTypePredictions` is on.
constexpr char kHtmlAttributeForAutofillTooltip[] = "title";

// Maps element names to the actual elements to simplify form filling.
typedef std::map<std::u16string, WebInputElement> FormInputElementMap;

// Use the shorter name when referencing SavePasswordProgressLogger::StringID
// values to spare line breaks. The code provides enough context for that
// already.
typedef SavePasswordProgressLogger Logger;

typedef std::vector<FormInputElementMap> FormElementsList;

bool DoUsernamesMatch(const std::u16string& potential_suggestion,
                      const std::u16string& current_username,
                      bool exact_match) {
  if (potential_suggestion == current_username)
    return true;
  return !exact_match && IsPrefixOfEmailEndingWithAtSign(current_username,
                                                         potential_suggestion);
}

// Returns whether the `username_element` is allowed to be autofilled.
//
// Note that if the user interacts with the `password_field` and the
// `username_element` is user-defined (i.e., non-empty and non-autofilled), then
// this function returns false. This is a precaution, to not override the field
// if it has been classified as username by accident.
bool IsUsernameAmendable(const WebInputElement& username_element,
                         bool is_password_field_selected) {
  return username_element && IsElementEditable(username_element) &&
         (!is_password_field_selected || username_element.IsAutofilled() ||
          username_element.IsPreviewed() || username_element.Value().IsEmpty());
}

// Log `message` if `logger` is not null.
void LogMessage(Logger* logger, Logger::StringID message) {
  if (logger)
    logger->LogMessage(message);
}

// Log `message` and `value` if `logger` is not null.
void LogBoolean(Logger* logger, Logger::StringID message, bool value) {
  if (logger)
    logger->LogBoolean(message, value);
}

// Log a message including the name, method and action of |form|.
void LogHTMLForm(Logger* logger,
                 Logger::StringID message_id,
                 const WebFormElement& form) {
  if (logger) {
    logger->LogHTMLForm(message_id, form.GetName().Utf8(),
                        GURL(form.Action().Utf8()));
  }
}

// Returns true if there are any suggestions to be derived from `fill_data`.
// Only considers suggestions with usernames having `typed_username` as prefix.
bool CanShowUsernameSuggestion(const PasswordFormFillData& fill_data,
                               const std::u16string& typed_username) {
  std::u16string typed_username_lower = base::i18n::ToLower(typed_username);
  if (base::StartsWith(
          base::i18n::ToLower(fill_data.preferred_login.username_value),
          typed_username_lower, base::CompareCase::SENSITIVE)) {
    return true;
  }

  for (const auto& login : fill_data.additional_logins) {
    if (base::StartsWith(base::i18n::ToLower(login.username_value),
                         typed_username_lower, base::CompareCase::SENSITIVE)) {
      return true;
    }
  }

  return false;
}

// This function attempts to find the matching credentials for the
// `current_username` by scanning `fill_data`. The result is written in
// `username` and `password` parameters.
void FindMatchesByUsername(const PasswordFormFillData& fill_data,
                           const std::u16string& current_username,
                           bool exact_username_match,
                           RendererSavePasswordProgressLogger* logger,
                           std::u16string* username,
                           std::u16string* password) {
  // Look for any suitable matches to current field text.
  if (DoUsernamesMatch(fill_data.preferred_login.username_value,
                       current_username, exact_username_match)) {
    *username = fill_data.preferred_login.username_value;
    *password = fill_data.preferred_login.password_value;
    LogMessage(logger, Logger::STRING_USERNAMES_MATCH);
  } else {
    // Scan additional logins for a match.
    for (const auto& it : fill_data.additional_logins) {
      if (!it.realm.empty()) {
        // Non-empty realm means PSL match. Do not autofill PSL matched
        // credentials. The reason for this is that PSL matched sites are
        // different sites, so a password for a PSL matched site should be never
        // filled without explicit user selection.
        continue;
      }
      if (DoUsernamesMatch(it.username_value, current_username,
                           exact_username_match)) {
        *username = it.username_value;
        *password = it.password_value;
        break;
      }
    }
    LogBoolean(logger, Logger::STRING_MATCH_IN_ADDITIONAL,
               !(username->empty() && password->empty()));
  }
}

// TODO(crbug.com/40447274): This duplicates code from
// components/password_manager/core/browser/password_store/psl_matching_helper.h.
// The logic using this code should ultimately end up in
// components/password_manager/core/browser, at which point it can use the
// original code directly.
std::string GetRegistryControlledDomain(const GURL& signon_realm) {
  return net::registry_controlled_domains::GetDomainAndRegistry(
      signon_realm,
      net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
}

// TODO(crbug.com/40447274): This duplicates code from
// components/password_manager/core/browser/password_store/psl_matching_helper.h.
// The logic using this code should ultimately end up in
// components/password_manager/core/browser, at which point it can use the
// original code directly.
bool IsPublicSuffixDomainMatch(const std::string& url1,
                               const std::string& url2) {
  GURL gurl1(url1);
  GURL gurl2(url2);

  if (!gurl1.is_valid() || !gurl2.is_valid())
    return false;

  if (gurl1 == gurl2)
    return true;

  std::string domain1(GetRegistryControlledDomain(gurl1));
  std::string domain2(GetRegistryControlledDomain(gurl2));

  if (domain1.empty() || domain2.empty())
    return false;

  return gurl1.GetScheme() == gurl2.GetScheme() && domain1 == domain2 &&
         gurl1.GetPort() == gurl2.GetPort();
}

// Helper function that calculates form signature for `form_data` and returns it
// as a string.
std::string GetFormSignatureAsString(const FormData& form_data) {
  return base::NumberToString(CalculateFormSignature(form_data).value());
}
// Similar to `GetFormSignatureAsString` but returns alternative form signature
// as a string.
std::string GetAlternativeFormSignatureAsString(const FormData& form_data) {
  return base::NumberToString(
      CalculateAlternativeFormSignature(form_data).value());
}

// Sets the specified attribute of `target` to the given value. This must not
// happen while ScriptForbiddenScope is active (e.g. during
// blink::FrameLoader::FinishedParsing(), see crbug.com/1219852). Therefore,
// this function should be called asynchronously via SetAttributeAsync.
void SetAttributeInternal(WebElement target,
                          const std::string& attribute_utf8,
                          const std::string& value_utf8) {
  target.SetAttribute(WebString::FromUtf8(attribute_utf8),
                      WebString::FromUtf8(value_utf8));
}

// Posts an async task to call SetAttributeInternal.
void SetAttributeAsync(WebElement target,
                       const std::string& attribute_utf8,
                       const std::string& value_utf8) {
  if (!target) {
    return;
  }
  target.GetDocument()
      .GetFrame()
      ->GetTaskRunner(blink::TaskType::kInternalDefault)
      ->PostTask(FROM_HERE, base::BindOnce(&SetAttributeInternal, target,
                                           attribute_utf8, value_utf8));
}

// Annotate `fields` with field signatures, form signature and visibility state
// as HTML attributes.
void AnnotateFieldsWithSignatures(
    base::span<const WebFormControlElement> fields,
    const std::string& form_signature,
    const std::string& alternative_form_signature) {
  for (const WebFormControlElement& control_element : fields) {
    std::optional<FormControlType> type =
        form_util::GetAutofillFormControlType(control_element);
    if (!type) {
      continue;
    }
    FieldSignature field_signature = CalculateFieldSignatureByNameAndType(
        control_element.NameForAutofill().Utf16(), *type);
    SetAttributeAsync(control_element, kDebugAttributeForFieldSignature,
                      base::NumberToString(field_signature.value()));
    SetAttributeAsync(control_element, kDebugAttributeForFormSignature,
                      form_signature);
    SetAttributeAsync(control_element,
                      kDebugAttributeForAlternativeFormSignature,
                      alternative_form_signature);
    SetAttributeAsync(control_element, kDebugAttributeForVisibility,
                      base::ToString(control_element.IsFocusable()));
  }
}

// Returns true iff there is a password field in `frame`.
// We don't have to iterate through the whole DOM to find password fields.
// Instead, we can iterate through the fields of the forms and the unowned
// fields, both of which are cached in the Document.
bool HasPasswordField(const WebLocalFrame& frame) {
  auto ContainsPasswordField = [&](const auto& fields) {
    return std::ranges::contains(
        fields, blink::mojom::FormControlType::kInputPassword,
        &WebFormControlElement::FormControlTypeForAutofill);
  };

  WebDocument doc = frame.GetDocument();
  return std::ranges::any_of(doc.GetOutermostForms(), ContainsPasswordField,
                             &WebFormElement::GetFormControlElements) ||
         ContainsPasswordField(doc.UnassociatedFormControls());
}

// Returns the closest visible autocompletable non-password text element
// preceding the `password_element` either in a form, if it belongs to one, or
// in the `frame`.
WebInputElement FindUsernameElementPrecedingPasswordElement(
    WebLocalFrame* frame,
    const WebInputElement& password_element) {
  DCHECK(password_element);

  std::vector<WebFormControlElement> elements =
      form_util::GetOwnedAutofillableFormControls(
          frame->GetDocument(), password_element.GetOwningFormForAutofill());

  auto iter = std::ranges::find(elements, password_element);
  if (iter == elements.end())
    return WebInputElement();

  for (auto begin = elements.begin(); iter != begin;) {
    --iter;
    const WebInputElement input = iter->DynamicTo<WebInputElement>();
    if (input && input.IsTextField() &&
        input.FormControlTypeForAutofill() != kInputPassword &&
        IsElementEditable(input) && input.IsFocusable()) {
      return input;
    }
  }

  return WebInputElement();
}

// Returns true if `element`'s frame origin is not PSL matched with the origin
// of any parent frame.
bool IsInCrossOriginIframeOrEmbeddedFrame(const WebInputElement& element) {
  WebFrame* cur_frame = element.GetDocument().GetFrame();
  WebString bottom_frame_origin = cur_frame->GetSecurityOrigin().ToString();

  DCHECK(cur_frame);

  while (cur_frame->Parent()) {
    cur_frame = cur_frame->Parent();
    if (!IsPublicSuffixDomainMatch(
            bottom_frame_origin.Utf8(),
            cur_frame->GetSecurityOrigin().ToString().Utf8())) {
      return true;
    }
  }
  // In MPArch, if we haven't reached the primary main frame, it means
  // we are in a nested frame tree. Fenced Frames are always considered
  // cross origin so we should return true here. Adding NOTREACHED for now
  // for future nested inner frame trees.
  if (!cur_frame->IsOutermostMainFrame()) {
    if (element.GetDocument().GetFrame()->IsInFencedFrameTree()) {
      return true;
    } else {
      NOTREACHED();
    }
  }
  return false;
}

void AnnotateFieldWithParsingResult(
    FieldRendererId renderer_id,
    const std::string& password_managers_annotation) {
  if (renderer_id.is_null())
    return;
  auto element = GetFormControlByRendererId(renderer_id);
  if (!element) {
    return;
  }
  // Calling SetAttribute synchronously here is safe because
  // AnnotateFieldWithParsingResult is triggered via a call from the the
  // browser. This means that we should not be in a ScriptForbiddenScope.
  element.SetAttribute(
      WebString::FromAscii(kDebugAttributeForParserAnnotations),
      WebString::FromAscii(password_managers_annotation));

  if (!base::FeatureList::IsEnabled(
          features::debug::kAutofillShowTypePredictions)) {
    return;
  }

  if (!element.HasAttribute(kDebugAttributeForAutofill)) {
    // No autofill tooltip yet, don't fill anything.
    return;
  }

  std::string autofill_tooltip =
      element.GetAttribute(kDebugAttributeForAutofill).Utf8();

  element.SetAttribute(
      kHtmlAttributeForAutofillTooltip,
      WebString::FromUtf8(
          base::StrCat({element.GetAttribute(kDebugAttributeForAutofill).Utf8(),
                        "\n", kDebugAttributeForParserAnnotations, ": ",
                        password_managers_annotation})));
}

bool HasDocumentWithValidFrame(const WebInputElement& element) {
  WebFrame* frame = element.GetDocument().GetFrame();
  return frame && frame->View();
}

// This method tries to fix `fields` with empty typed or filled properties by
// matching them against previously filled or typed in fields with the same
// value and copying their filled or typed mask.
//
// This helps against websites where submitted fields differ from fields that
// had previously been autofilled or typed into.
[[nodiscard]] std::vector<FormFieldData> FillNonTypedOrFilledPropertiesMasks(
    std::vector<FormFieldData> fields,
    const FieldDataManager& manager) {
  static constexpr FieldPropertiesMask kFilledOrTyped =
      FieldPropertiesFlags::kAutofilled | FieldPropertiesFlags::kUserTyped;

  for (auto& field : fields) {
    if (field.properties_mask() & kFilledOrTyped) {
      continue;
    }

    for (const auto& [field_id, field_data] : manager.field_data_map()) {
      const std::optional<std::u16string>& value = field_data.first;
      FieldPropertiesMask properties = field_data.second;
      if ((properties & kFilledOrTyped) && value == field.value()) {
        field.set_properties_mask(field.properties_mask() |
                                  (properties & kFilledOrTyped));
        break;
      }
    }
  }
  return fields;
}

bool HasTextInputs(const FormData& form_data) {
  return std::ranges::any_of(form_data.fields(),
                             &FormFieldData::IsTextInputElement);
}

#if BUILDFLAG(IS_ANDROID)
bool IsWebAuthnForm(base::optional_ref<const FormData> form_data) {
  auto has_webauthn_attribute = [](const FormFieldData& field) {
    return field.parsed_autocomplete() && field.parsed_autocomplete()->webauthn;
  };
  return form_data &&
         std::ranges::any_of(form_data->fields(), has_webauthn_attribute);
}
#endif  // BUILDFLAG(IS_ANDROID)

FieldPropertiesFlags GetFieldFlags(AutofillSuggestionTriggerSource source) {
  return source == AutofillSuggestionTriggerSource::kManualFallbackPasswords
             ? FieldPropertiesFlags::
                   kAutofilledPasswordFormFilledViaManualFallback
             : FieldPropertiesFlags::kAutofilledOnUserTrigger;
}

}  // namespace

// During prerendering, we do not want the renderer to send messages to the
// corresponding driver. Since we use a channel associated interface, we still
// need to set up the mojo connection as before (i.e., we can't defer binding
// the interface). Instead, we enqueue our messages here as post-activation
// tasks. See post-prerendering activation steps here:
// https://wicg.github.io/nav-speculation/prerendering.html#prerendering-bcs-subsection
class PasswordAutofillAgent::DeferringPasswordManagerDriver
    : public mojom::PasswordManagerDriver {
 public:
  explicit DeferringPasswordManagerDriver(PasswordAutofillAgent* agent)
      : agent_(agent) {}
  ~DeferringPasswordManagerDriver() override = default;

 private:
  template <typename F, typename... Args>
  void SendMsg(F fn, Args&&... args) {
    if (auto* driver = agent_->unsafe_driver()) {
      DCHECK(!agent_->IsPrerendering());
      DCHECK_NE(driver, this);
      (driver->*fn)(std::forward<Args>(args)...);
    }
  }
  template <typename F, typename... Args>
  void DeferMsg(F fn, Args... args) {
    if (auto* render_frame = agent_->unsafe_render_frame()) {
      DCHECK(agent_->IsPrerendering());
      render_frame->GetWebFrame()
          ->GetDocument()
          .AddPostPrerenderingActivationStep(base::BindOnce(
              &DeferringPasswordManagerDriver::SendMsg<F, Args...>,
              weak_ptr_factory_.GetWeakPtr(), fn, std::forward<Args>(args)...));
    }
  }
  void PasswordFormsParsed(const std::vector<FormData>& forms_data) override {
    DeferMsg(&mojom::PasswordManagerDriver::PasswordFormsParsed, forms_data);
  }
  void PasswordFormsRendered(
      const std::vector<FormData>& visible_forms_data) override {
    DeferMsg(&mojom::PasswordManagerDriver::PasswordFormsRendered,
             visible_forms_data);
  }
  void PasswordFormSubmitted(const FormData& form_data) override {
    DeferMsg(&mojom::PasswordManagerDriver::PasswordFormSubmitted, form_data);
  }
  void InformAboutUserInput(const FormData& form_data) override {
    DeferMsg(&mojom::PasswordManagerDriver::InformAboutUserInput, form_data);
  }
  void DynamicFormSubmission(
      mojom::SubmissionIndicatorEvent submission_indication_event) override {
    DeferMsg(&mojom::PasswordManagerDriver::DynamicFormSubmission,
             submission_indication_event);
  }
  void PasswordFormCleared(const FormData& form_data) override {
    DeferMsg(&mojom::PasswordManagerDriver::PasswordFormCleared, form_data);
  }
  void RecordSavePasswordProgress(const std::string& log) override {
    DeferMsg(&mojom::PasswordManagerDriver::RecordSavePasswordProgress, log);
  }
  void UserModifiedPasswordField() override {
    DeferMsg(&mojom::PasswordManagerDriver::UserModifiedPasswordField);
  }
  void UserModifiedNonPasswordField(FieldRendererId renderer_id,
                                    const std::u16string& value,
                                    bool autocomplete_attribute_has_username,
                                    bool is_likely_otp) override {
    DeferMsg(&mojom::PasswordManagerDriver::UserModifiedNonPasswordField,
             renderer_id, value, autocomplete_attribute_has_username,
             is_likely_otp);
  }
  void CheckSafeBrowsingReputation(const GURL& form_action,
                                   const GURL& frame_url) override {
    DeferMsg(&mojom::PasswordManagerDriver::CheckSafeBrowsingReputation,
             form_action, frame_url);
  }
  void FocusedInputChanged(
      FieldRendererId focused_field_id,
      mojom::FocusedFieldType focused_field_type) override {
    DeferMsg(&mojom::PasswordManagerDriver::FocusedInputChanged,
             focused_field_id, focused_field_type);
  }
  void LogFirstFillingResult(FormRendererId form_renderer_id,
                             int32_t result) override {
    DeferMsg(&mojom::PasswordManagerDriver::LogFirstFillingResult,
             form_renderer_id, result);
  }

  raw_ptr<PasswordAutofillAgent> agent_ = nullptr;
  base::WeakPtrFactory<DeferringPasswordManagerDriver> weak_ptr_factory_{this};
};

PasswordAutofillAgent::FocusStateNotifier::FocusStateNotifier(
    PasswordAutofillAgent* agent)
    : agent_(CHECK_DEREF(agent)) {}

PasswordAutofillAgent::FocusStateNotifier::~FocusStateNotifier() = default;

void PasswordAutofillAgent::FocusStateNotifier::FocusedElementChanged(
    const WebElement& element) {
  auto field_info = GetFocusedFieldInfo(element);
  NotifyIfChanged(field_info.first, field_info.second);
}

std::pair<mojom::FocusedFieldType, FieldRendererId>
PasswordAutofillAgent::FocusStateNotifier::GetFocusedFieldInfo(
    const WebElement& element) {
  if (auto form_control_element = element.DynamicTo<WebFormControlElement>()) {
    return {GetFieldType(form_control_element),
            form_util::GetFieldRendererId(form_control_element)};
  }
  // Contenteditable focus notifications are only needed on Android to show
  // the Keyboard Accessory via `ManualFillingController` and
  // `ChromePasswordManagerClient::FocusedInputChanged`.
  // On Desktop, contenteditable focus and suggestions are driven entirely by
  // `AutofillAgent`.
#if BUILDFLAG(IS_ANDROID)
  if (base::FeatureList::IsEnabled(
          features::kAutofillAtMemorySupportContenteditableOnAndroid) &&
      element && element.IsContentEditable()) {
    if (std::optional<FormData> form =
            form_util::FindFormForContentEditable(element)) {
      CHECK_EQ(form->fields().size(), 1u);
      return {mojom::FocusedFieldType::kContenteditableField,
              form->fields().front().renderer_id()};
    }
  }
#endif
  return {mojom::FocusedFieldType::kUnknown, FieldRendererId()};
}

mojom::FocusedFieldType PasswordAutofillAgent::FocusStateNotifier::GetFieldType(
    const WebFormControlElement& node) {
  auto form_control_type = node.FormControlTypeForAutofill();
  if (form_control_type == blink::mojom::FormControlType::kTextArea) {
    return mojom::FocusedFieldType::kFillableTextArea;
  }

  WebInputElement input_element = node.DynamicTo<WebInputElement>();
  if (!input_element || !input_element.IsTextField() ||
      !form_util::IsElementEditable(input_element)) {
    return mojom::FocusedFieldType::kUnfillableElement;
  }

  if (form_control_type == blink::mojom::FormControlType::kInputSearch) {
    return mojom::FocusedFieldType::kFillableSearchField;
  }
  if (form_control_type == blink::mojom::FormControlType::kInputPassword) {
    return mojom::FocusedFieldType::kFillablePasswordField;
  }
  if (agent_->IsUsernameInputField(input_element)) {
    return mojom::FocusedFieldType::kFillableUsernameField;
  }
  if (form_util::IsWebauthnTaggedElement(node)) {
    return mojom::FocusedFieldType::kFillableWebauthnTaggedField;
  }
  return mojom::FocusedFieldType::kFillableNonSearchField;
}

void PasswordAutofillAgent::FocusStateNotifier::NotifyIfChanged(
    mojom::FocusedFieldType new_focused_field_type,
    FieldRendererId new_focused_field_id) {
  // Forward the request if the focused field is different from the previous
  // one.
  if (focused_field_id_ == new_focused_field_id &&
      focused_field_type_ == new_focused_field_type) {
    return;
  }

  if (auto* driver = agent_->unsafe_driver()) {
    driver->FocusedInputChanged(new_focused_field_id, new_focused_field_type);
  }

  focused_field_type_ = new_focused_field_type;
  focused_field_id_ = new_focused_field_id;
}

PasswordAutofillAgent::PasswordAutofillAgent(
    content::RenderFrame* render_frame,
    blink::AssociatedInterfaceRegistry* registry)
    : content::RenderFrameObserver(render_frame) {
  registry->AddInterface<mojom::PasswordAutofillAgent>(base::BindRepeating(
      &PasswordAutofillAgent::BindPendingReceiver, base::Unretained(this)));
}

PasswordAutofillAgent::~PasswordAutofillAgent() = default;

void PasswordAutofillAgent::Init(AutofillAgent* autofill_agent) {
  autofill_agent_ = autofill_agent;
}

void PasswordAutofillAgent::BindPendingReceiver(
    mojo::PendingAssociatedReceiver<mojom::PasswordAutofillAgent>
        pending_receiver) {
  receiver_.Bind(std::move(pending_receiver));
}

void PasswordAutofillAgent::SetPasswordGenerationAgent(
    PasswordGenerationAgent* generation_agent) {
  password_generation_agent_ = generation_agent;
}

PasswordAutofillAgent::FormStructureInfo::FormStructureInfo() = default;

PasswordAutofillAgent::FormStructureInfo::FormStructureInfo(
    const FormStructureInfo& other) = default;

PasswordAutofillAgent::FormStructureInfo&
PasswordAutofillAgent::FormStructureInfo::operator=(
    const PasswordAutofillAgent::FormStructureInfo& other) = default;

PasswordAutofillAgent::FormStructureInfo::FormStructureInfo(
    FormStructureInfo&& other) = default;

PasswordAutofillAgent::FormStructureInfo&
PasswordAutofillAgent::FormStructureInfo::operator=(
    PasswordAutofillAgent::FormStructureInfo&& other) = default;

PasswordAutofillAgent::FormStructureInfo::~FormStructureInfo() = default;

PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
    : was_user_gesture_seen_(false) {}

PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() =
    default;

void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement(
    WebInputElement element) {
  CHECK(element);
  if (was_user_gesture_seen_) {
    ShowValue(element);
  } else {
    element_ids_.push_back(GetFieldRendererId(element));
  }
}

void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() {
  if (was_user_gesture_seen_) {
    return;
  }
  was_user_gesture_seen_ = true;
  for (FieldRendererId element : element_ids_) {
    if (WebInputElement input_element =
            GetFormControlByRendererId(element).DynamicTo<WebInputElement>()) {
      ShowValue(input_element);
    }
  }
  element_ids_.clear();
}

void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() {
  was_user_gesture_seen_ = false;
  element_ids_.clear();
}

void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
    WebInputElement element) {
  if (element && !element.SuggestedValue().IsEmpty()) {
    element.SetAutofillValue(element.SuggestedValue());
  }
  // WARNING: SetAutofillValue can trigger JS that detaches the frame.
  // Do not add code here that assumes the frame is still valid without
  // checking.
}

std::optional<PasswordSuggestionRequest>
PasswordAutofillAgent::CreateRequestForChangeInTextField(
    const WebInputElement& element,
    const SynchronousFormCache& form_cache) {
  CHECK(element);
  return CreateRequestForDomain(
      element, AutofillSuggestionTriggerSource::kTextFieldValueChanged,
      form_cache);
}

// LINT.IfChange

void PasswordAutofillAgent::NotifyPasswordManagerAboutUserFieldModification(
    const WebInputElement& element,
    FieldModificationType modification_type) {
  // No need to post a notification if the frame has already detached.
  if (!unsafe_render_frame()) {
    return;
  }
  if (element.FormControlTypeForAutofill() == kInputPassword) {
    auto iter = password_to_username_.find(GetFieldRendererId(element));
    if ((iter != password_to_username_.end()) &&
        (modification_type == FieldModificationType::kManualTyping)) {
      // Note that the suggested value of `mutable_element` was reset when its
      // value changed.
      // TODO(crbug.com/41132785): Do this through const WebInputElement.
      WebInputElement mutable_element = element;  // We need a non-const.
      mutable_element.SetAutofillState(WebAutofillState::kNotFilled);
    }
    if (auto* driver = unsafe_driver()) {
      driver->UserModifiedPasswordField();
    }
    return;
  }

  const std::u16string element_value = element.Value().Utf16();
  static base::NoDestructor<WebString> kAutocomplete("autocomplete");
  std::string autocomplete_attribute =
      element.GetAttribute(*kAutocomplete).Utf8();
  static base::NoDestructor<WebString> kName("name");
  std::u16string name_attribute = element.GetAttribute(*kName).Utf16();
  std::u16string id_attribute = element.GetIdAttribute().Utf16();
  static base::NoDestructor<WebString> kLabel("label");
  std::u16string label_attribute = element.GetAttribute(*kLabel).Utf16();
  std::optional<mojom::FormControlType> type_attribute =
      form_util::GetAutofillFormControlType(element);

  if (!password_manager::util::CanFieldBeConsideredAsSingleUsername(
          name_attribute, id_attribute, label_attribute, type_attribute) ||
      !password_manager::util::CanValueBeConsideredAsSingleUsername(
          element_value)) {
    return;
  }

  bool is_likely_otp = password_manager::util::IsLikelyOtp(
      name_attribute, id_attribute, autocomplete_attribute);

  if (auto* driver = unsafe_driver()) {
    driver->UserModifiedNonPasswordField(
        GetFieldRendererId(element), element_value,
        autocomplete_attribute.contains(
            password_manager::constants::kAutocompleteUsername),
        is_likely_otp);
  }
}

void PasswordAutofillAgent::UpdatePasswordStateForTextChange(
    const WebInputElement& element,
    const SynchronousFormCache& form_cache) {
  NotifyPasswordManagerAboutUserFieldModification(
      element, FieldModificationType::kManualTyping);

  InformBrowserAboutUserInput(element.GetOwningFormForAutofill(), element,
                              form_cache);
}

// LINT.ThenChange(//components/password_manager/core/browser/password_manager.cc:update_password_state_for_text_change)

void PasswordAutofillAgent::TrackAutofilledElement(
    const WebFormControlElement& element) {
  autofill_agent_->TrackAutofilledElement(
      form_util::GetFieldRendererId(element));
}

void PasswordAutofillAgent::FillPasswordSuggestion(
    const std::u16string& username,
    const std::u16string& password,
    base::OnceCallback<void(bool)> callback) {
  auto focused_element = last_queried_element().DynamicTo<WebInputElement>();
  if (!focused_element || !IsElementEditable(focused_element)) {
    std::move(callback).Run(/*success=*/false);
    return;
  }
  WebInputElement username_element;
  WebInputElement password_element;
  PasswordInfo* password_info = nullptr;
  if (!HasElementsToFill(focused_element, UseFallbackData(true),
                         &username_element, &password_element,
                         &password_info)) {
    std::move(callback).Run(/*success=*/false);
    return;
  }
  if (focused_element.FormControlTypeForAutofill() == kInputPassword) {
    CHECK(password_element);
    password_info->password_field_suggestion_was_accepted = true;
    password_info->password_field_id = GetFieldRendererId(password_element);
  }
  bool success = FillUsernameAndPasswordElements(
      username_element, password_element, username, password,
      AutofillSuggestionTriggerSource::kFormControlElementClicked);
  std::move(callback).Run(success);
}

void PasswordAutofillAgent::FillPasswordSuggestionById(
    FieldRendererId username_element_id,
    FieldRendererId password_element_id,
    const std::u16string& username,
    const std::u16string& password,
    AutofillSuggestionTriggerSource suggestion_source) {
  if (!last_queried_element()) {
    return;
  }
  FillUsernameAndPasswordElements(
      GetFormControlByRendererId(username_element_id)
          .DynamicTo<WebInputElement>(),
      GetFormControlByRendererId(password_element_id)
          .DynamicTo<WebInputElement>(),
      username, password, suggestion_source);
}

bool PasswordAutofillAgent::FillUsernameAndPasswordElements(
    blink::WebInputElement username_element,
    blink::WebInputElement password_element,
    const std::u16string& username,
    const std::u16string& password,
    AutofillSuggestionTriggerSource suggestion_source) {
  ClearPreviewedForm();
  // TODO(crbug.com/341995827): Remove dependency on `focused_element`. Username
  // filling condition could be made similar to the password one and selection
  // range setting could be skipped.
  WebFormControlElement focused_element = last_queried_element();
  if (!focused_element) {
    return false;
  }
  // Call OnFieldAutofilled before WebInputElement::SetAutofillState which may
  // cause frame closing.
  if (password_element && password_generation_agent_) {
    password_generation_agent_->OnFieldAutofilled(password_element);
  }
  bool is_password_field_focused = password_element == focused_element;
  if (IsUsernameAmendable(username_element, is_password_field_focused) &&
      !(username.empty() && is_password_field_focused) &&
      username_element.Value().Utf16() != username) {
    DoFillField(username_element, username, GetFieldFlags(suggestion_source));
  }
  if (password_element && IsElementEditable(password_element)) {
    FillPasswordFieldAndSave(password_element, password, suggestion_source);
    // TODO(crbug.com/40223173): As Touch-To-Fill and auto-submission don't
    // currently support filling single username fields, the code below is
    // within `password_element`. Support such fields too and move the
    // code out the condition.
    // If the `username_element` is visible/focusable and the `password_element`
    // is not, trigger submission on the former as the latter unlikely has an
    // Enter listener.
    if (username_element && username_element.IsFocusable() &&
        !password_element.IsFocusable()) {
      field_renderer_id_to_submit_ = GetFieldRendererId(username_element);
    } else {
      field_renderer_id_to_submit_ = GetFieldRendererId(password_element);
    }
  }
  auto length = base::checked_cast<unsigned>(focused_element.Value().length());
  focused_element.SetSelectionRange(length, length);

  // Returns whether the fields were filled with the requested values
  // successfully.
  return (!username_element || username_element.Value().Utf16() == username) &&
         (!password_element || password_element.Value().Utf16() == password);
}

void PasswordAutofillAgent::FillIntoFocusedField(
    bool is_password,
    const std::u16string& credential) {
  auto focused_input = last_queried_element().DynamicTo<WebInputElement>();
  if (!focused_input || focused_input.IsReadOnly()) {
    return;
  }
  if (!is_password) {
    DoFillField(focused_input, credential,
                FieldPropertiesFlags::kAutofilledOnUserTrigger);
  }
  if (focused_input.FormControlTypeForAutofill() != kInputPassword) {
    return;
  }
  FillPasswordFieldAndSave(focused_input, credential,
                           AutofillSuggestionTriggerSource::kUnspecified);
}

void PasswordAutofillAgent::PreviewField(FieldRendererId field_id,
                                         const std::u16string& value) {
  WebInputElement input = form_util::GetFormControlByRendererId(field_id)
                              .DynamicTo<WebInputElement>();
  if (!input || !IsElementEditable(input)) {
    return;
  }
  DoPreviewField(
      input, value,
      /*is_password=*/input.FormControlTypeForAutofill() == kInputPassword);
}

void PasswordAutofillAgent::FillField(
    FieldRendererId field_id,
    const std::u16string& value,
    FieldPropertiesMask field_properties,
    base::OnceCallback<void(bool)> success_callback) {
  WebFormControlElement form_control =
      form_util::GetFormControlByRendererId(field_id);
  WebInputElement input_element = form_control.DynamicTo<WebInputElement>();
  if (!input_element || input_element.IsReadOnly()) {
    std::move(success_callback).Run(false);
    // Early return for non-input fields such as textarea.
    return;
  }
  DoFillField(input_element, value, field_properties);
  if (base::FeatureList::IsEnabled(
          password_manager::features::kActorLoginTreatFillingAsUserInput)) {
    InformBrowserAboutUserInput(input_element.GetOwningFormForAutofill(),
                                input_element, /*form_cache=*/{});
  }
  std::move(success_callback).Run(true);
}

void PasswordAutofillAgent::FillChangePasswordForm(
    FieldRendererId password_element_id,
    FieldRendererId new_password_element_id,
    FieldRendererId confirm_password_element_id,
    const std::u16string& old_password,
    const std::u16string& new_password,
    FillChangePasswordFormCallback callback) {
  WebInputElement last_element;

  auto filling_tasks = {
      std::make_pair(password_element_id, old_password),
      std::make_pair(new_password_element_id, new_password),
      std::make_pair(confirm_password_element_id, new_password)};
  for (const auto& task : filling_tasks) {
    WebFormControlElement form_control =
        form_util::GetFormControlByRendererId(task.first);
    WebInputElement input_element = form_control.DynamicTo<WebInputElement>();
    if (!input_element) {
      continue;
    }

    DoFillField(input_element, task.second,
                FieldPropertiesFlags::kAutofilledChangePasswordFormOnPageLoad);
    last_element = input_element;
  }

  if (!last_element) {
    std::move(callback).Run(std::nullopt);
    return;
  }

  const WebFormElement& form = last_element.GetOwningFormForAutofill();
  std::optional<FormData> form_data =
      form ? GetFormDataFromWebForm(form, /*form_cache=*/{})
           : GetFormDataFromUnownedInputElements(/*form_cache=*/{});
  if (!form_data) {
    std::move(callback).Run(std::nullopt);
    return;
  }

  std::move(callback).Run(*form_data);
}

void PasswordAutofillAgent::DoPreviewField(WebInputElement input,
                                           const std::u16string& credential,
                                           bool is_password) {
  CHECK(input);
  previewed_elements_.emplace_back(PreviewInfo{
      .field_id = form_util::GetFieldRendererId(input),
      .autofill_state = input.GetAutofillState(),
      .is_password = is_password,
  });
  input.SetSuggestedValue(WebString::FromUtf16(credential));
}

void PasswordAutofillAgent::DoFillField(WebInputElement input,
                                        const std::u16string& credential,
                                        FieldPropertiesMask field_properties) {
  CHECK(input);
  input.SetAutofillValue(WebString::FromUtf16(credential));
  // No need to process changes if the frame has detached upon filling
  // completion.
  if (!unsafe_render_frame()) {
    return;
  }
  field_data_manager().UpdateFieldDataMap(form_util::GetFieldRendererId(input),
                                          credential, field_properties);

  if ((field_properties & kAutofilledOnUserTrigger) ||
      (field_properties & kAutofilledPasswordFormFilledViaManualFallback)) {
    // Notify password manager when the user is modifying field values by
    // manually filling the form.
    NotifyPasswordManagerAboutUserFieldModification(
        input, FieldModificationType::kFillingOnUserTrigger);
  }
  TrackAutofilledElement(input);
}

void PasswordAutofillAgent::FillPasswordFieldAndSave(
    WebInputElement password_input,
    const std::u16string& credential,
    AutofillSuggestionTriggerSource suggestion_source) {
  CHECK(password_input.FormControlTypeForAutofill() == kInputPassword);
  DoFillField(password_input, credential, GetFieldFlags(suggestion_source));
  InformBrowserAboutUserInput(password_input.GetOwningFormForAutofill(),
                              password_input, /*form_cache=*/{});
}

void PasswordAutofillAgent::PreviewSuggestion(
    const WebFormControlElement& control_element,
    const std::u16string& username,
    const std::u16string& password) {
  // The element in context of the suggestion popup.
  const WebInputElement element = control_element.DynamicTo<WebInputElement>();
  if (!element || !IsElementEditable(element)) {
    return;
  }
  WebInputElement username_element;
  WebInputElement password_element;
  PasswordInfo* password_info;
  if (!HasElementsToFill(element, UseFallbackData(true), &username_element,
                         &password_element, &password_info)) {
    return;
  }
  PreviewUsernameAndPasswordElements(username_element, password_element,
                                     username, password);
}

void PasswordAutofillAgent::PreviewPasswordSuggestionById(
    FieldRendererId username_element_id,
    FieldRendererId password_element_id,
    const std::u16string& username,
    const std::u16string& password) {
  if (!last_queried_element()) {
    return;
  }
  PreviewUsernameAndPasswordElements(
      GetFormControlByRendererId(username_element_id)
          .DynamicTo<WebInputElement>(),
      GetFormControlByRendererId(password_element_id)
          .DynamicTo<WebInputElement>(),
      username, password);
}

void PasswordAutofillAgent::PreviewUsernameAndPasswordElements(
    blink::WebInputElement username_element,
    blink::WebInputElement password_element,
    const std::u16string& username,
    const std::u16string& password) {
  // TODO(crbug.com/341995827): Remove dependency on `focused_element` when
  // similar dependency is removed from
  // `PasswordAutofillAgent::FillUsernameAndPasswordElements`.
  WebFormControlElement focused_element = last_queried_element();
  if (!focused_element) {
    return;
  }
  if (IsUsernameAmendable(username_element,
                          password_element == focused_element)) {
    DoPreviewField(username_element, username, /*is_password=*/false);
  }
  if (password_element && IsElementEditable(password_element)) {
    DoPreviewField(password_element, password, /*is_password=*/true);
  }
}

void PasswordAutofillAgent::ClearPreviewedForm() {
  for (const PreviewInfo& preview_info : previewed_elements_) {
    WebInputElement element =
        form_util::GetFormControlByRendererId(preview_info.field_id)
            .DynamicTo<WebInputElement>();
    if (!element) {
      continue;
    }
    element.SetSuggestedValue(WebString());
    element.SetAutofillState(preview_info.autofill_state);
  }
  previewed_elements_.clear();
}

std::optional<PasswordSuggestionRequest>
PasswordAutofillAgent::CreateSuggestionRequest(
    const std::u16string& typed_username,
    const WebInputElement& user_input,
    AutofillSuggestionTriggerSource trigger_source,
    const SynchronousFormCache& form_cache) {
  if (!unsafe_render_frame()) {
    return std::nullopt;
  }
  base::UmaHistogramEnumeration("PasswordManager.SuggestionPopupTriggerSource",
                                trigger_source);
  // TODO(crbug.com/408843433): Don't extract the data here but pass it in from
  // the caller who needs it anyways for autofill requests.
  std::optional<form_util::FormAndField> form_and_field =
      form_util::FindFormAndFieldForFormControlElement(
          user_input, field_data_manager(),
          autofill_agent_->GetCallTimerState(
              CallTimerState::CallSite::kShowSuggestionPopup),
          autofill_agent_->button_titles_cache(), form_cache);
  if (!form_and_field) {
    return std::nullopt;
  }

  // TODO(crbug.com/408843433): Don't find this data again. Pass it from caller.
  WebInputElement username_element;
  WebInputElement password_element;
  PasswordInfo* password_info = nullptr;

  // If false, neither info nor fields were found. Continue for fallback data.
  FindPasswordInfoForElement(user_input, UseFallbackData(false),
                             &username_element, &password_element,
                             &password_info);

  return PasswordSuggestionRequest(
      TriggeringField(form_and_field->field, trigger_source, typed_username,
                      gfx::RectF(unsafe_render_frame()->ConvertViewportToWindow(
                          user_input.BoundsInWidget()))),
      std::move(form_and_field->form),
      {.frame_token = {},
       .renderer_id = username_element ? GetFieldRendererId(username_element)
                                       : FieldRendererId()},
      {.frame_token = {},
       .renderer_id = password_element ? GetFieldRendererId(password_element)
                                       : FieldRendererId()});
}

bool PasswordAutofillAgent::FindPasswordInfoForElement(
    const WebInputElement& element,
    UseFallbackData use_fallback_data,
    WebInputElement* username_element,
    WebInputElement* password_element,
    PasswordInfo** password_info) {
  DCHECK(username_element && password_element && password_info);
  username_element->Reset();
  password_element->Reset();
  if (!element || !unsafe_render_frame()) {
    return false;
  }
  if (suggestion_banned_fields_.contains(GetFieldRendererId(element))) {
    // No suggestion for `element` since there is a reliable signal that
    // `element` is a non-credential field.
    return false;
  }
  if (element.FormControlTypeForAutofill() != kInputPassword) {
    *username_element = element;
  } else {
    *password_element = element;

    // If there is a password field, but a request to the store hasn't been sent
    // yet, then do fetch saved credentials now.
    if (!sent_request_to_store_) {
      SendPasswordForms(/*only_visible=*/false, /*form_cache=*/{});
      return false;
    }

    auto iter = web_input_to_password_info_.find(GetFieldRendererId(element));
    if (iter == web_input_to_password_info_.end()) {
      auto password_iter =
          password_to_username_.find(GetFieldRendererId(element));
      if (password_iter == password_to_username_.end()) {
        if (!use_fallback_data || web_input_to_password_info_.empty()) {
          return false;
        }
        iter = last_supplied_password_info_iter_;
      } else {
        *username_element = GetFormControlByRendererId(password_iter->second)
                                .DynamicTo<WebInputElement>();
      }
    }

    if (auto* frame = unsafe_render_frame();
        frame && iter != web_input_to_password_info_.end()) {
      // It's a password field without corresponding username field. Try to find
      // the username field based on visibility.
      *username_element = FindUsernameElementPrecedingPasswordElement(
          frame->GetWebFrame(), *password_element);
      *password_info = &iter->second;
      return true;
    }
  }

  if (username_element == nullptr || username_element->IsNull()) {
    return false;
  }
  auto iter =
      web_input_to_password_info_.find(GetFieldRendererId(*username_element));
  if (iter == web_input_to_password_info_.end()) {
    return false;
  }
  *password_info = &iter->second;
  if (password_element->IsNull()) {
    if (WebInputElement password_input =
            GetFormControlByRendererId((*password_info)->password_field_id)
                .DynamicTo<WebInputElement>()) {
      *password_element = password_input;
    }
  }
  return true;
}

bool PasswordAutofillAgent::IsUsernameOrPasswordFillable(
    const WebInputElement& username_element,
    const WebInputElement& password_element,
    PasswordInfo* password_info) {
  if (username_element && IsElementEditable(username_element) &&
      !password_element) {
    return true;
  }
  if (password_element && IsElementEditable(password_element)) {
    return true;
  }
  // Password field might be disabled before entering valid username.
  // For such cases, check that the password field is under <form> tag.
  // Otherwise, username and password element might not be related.
  return username_element && IsElementEditable(username_element) &&
         (password_info != nullptr &&
          !password_info->fill_data.form_renderer_id.is_null());
}

bool PasswordAutofillAgent::HasElementsToFill(
    const WebInputElement& trigger_element,
    UseFallbackData use_fallback_data,
    WebInputElement* username_element,
    WebInputElement* password_element,
    PasswordInfo** password_info) {
  if (!FindPasswordInfoForElement(trigger_element, use_fallback_data,
                                  username_element, password_element,
                                  password_info)) {
    return false;
  }
  return IsUsernameOrPasswordFillable(*username_element, *password_element,
                                      *password_info);
}

void PasswordAutofillAgent::MaybeCheckSafeBrowsingReputation(
    const WebInputElement& element) {
  // Enabled on desktop and Android
#if BUILDFLAG(FULL_SAFE_BROWSING) || BUILDFLAG(SAFE_BROWSING_DB_REMOTE)
  // Note: A site may use a Password field to collect a CVV or a Credit Card
  // number, but showing a slightly misleading warning here is better than
  // showing no warning at all.
  if (element.FormControlTypeForAutofill() != kInputPassword) {
    return;
  }
  if (checked_safe_browsing_reputation_)
    return;

  checked_safe_browsing_reputation_ = true;
  if (!unsafe_render_frame()) {
    return;
  }
  WebLocalFrame* frame = unsafe_render_frame()->GetWebFrame();
  GURL frame_url = GURL(frame->GetDocument().Url());
  WebFormElement form_element = element.GetOwningFormForAutofill();
  GURL action_url = form_element
                        ? form_util::GetCanonicalActionForForm(form_element)
                        : GURL();
  if (auto* driver = unsafe_driver()) {
    driver->CheckSafeBrowsingReputation(action_url, frame_url);
  }
#endif
}

bool PasswordAutofillAgent::FrameCanAccessPasswordManager() {
  if (!unsafe_render_frame()) {
    return false;
  }
  // about:blank or about:srcdoc frames should not be allowed to use password
  // manager.  See https://crbug.com/756587.
  WebLocalFrame* frame = unsafe_render_frame()->GetWebFrame();
  WebURL url = frame->GetDocument().Url();
  if (!url.ProtocolIs(url::kHttpScheme) && !url.ProtocolIs(url::kHttpsScheme))
    return false;
  return frame->GetSecurityOrigin().CanAccessPasswordManager();
}

void PasswordAutofillAgent::OnDynamicFormsSeen(
    const SynchronousFormCache& form_cache) {
  SendPasswordForms(/*only_visible=*/false, form_cache);
}

void PasswordAutofillAgent::UserGestureObserved() {
  autofilled_elements_cache_.clear();

  gatekeeper_.OnUserGesture();
}

void PasswordAutofillAgent::AnnotateFormsAndFieldsWithSignatures(
    std::vector<WebFormElement>& forms,
    const SynchronousFormCache& form_cache) {
  if (!unsafe_render_frame()) {
    return;
  }
  WebDocument document = unsafe_render_frame()->GetWebFrame()->GetDocument();
  for (const WebFormElement& form : forms) {
    std::optional<FormData> form_data =
        GetFormDataFromWebForm(form, form_cache);
    std::string form_signature;
    std::string alternative_form_signature;
    if (form_data) {
      // GetAlternativeFormSignatureAsString() require the FormData::url.
      form_data->set_url(document.Url());
      form_signature = GetFormSignatureAsString(*form_data);
      alternative_form_signature =
          GetAlternativeFormSignatureAsString(*form_data);
      SetAttributeAsync(form, kDebugAttributeForFormSignature, form_signature);
      SetAttributeAsync(form, kDebugAttributeForAlternativeFormSignature,
                        alternative_form_signature);
    }
    AnnotateFieldsWithSignatures(
        form_util::GetOwnedAutofillableFormControls(document, form),
        form_signature, alternative_form_signature);
  }

  std::optional<FormData> form_data =
      GetFormDataFromUnownedInputElements(form_cache);
  std::string form_signature;
  std::string alternative_form_signature;
  if (form_data && unsafe_render_frame()) {
    // GetFormSignatureAsString() may require the FormData::url.
    form_data->set_url(
        unsafe_render_frame()->GetWebFrame()->GetDocument().Url());
    form_signature = GetFormSignatureAsString(*form_data);
    alternative_form_signature =
        GetAlternativeFormSignatureAsString(*form_data);
  }
  AnnotateFieldsWithSignatures(
      form_util::GetOwnedAutofillableFormControls(document, WebFormElement()),
      form_signature, alternative_form_signature);
}

void PasswordAutofillAgent::SendPasswordForms(
    bool only_visible,
    const SynchronousFormCache& form_cache) {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_ && unsafe_driver()) {
    logger =
        std::make_unique<RendererSavePasswordProgressLogger>(unsafe_driver());
    logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD);
    logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible);
  }

  if (!unsafe_render_frame()) {
    return;
  }
  WebLocalFrame* frame = unsafe_render_frame()->GetWebFrame();

  // Make sure that this security origin is allowed to use password manager.
  WebDocument doc = frame->GetDocument();
  WebSecurityOrigin origin = doc.GetSecurityOrigin();
  if (logger) {
    logger->LogURL(Logger::STRING_SECURITY_ORIGIN,
                   GURL(origin.ToString().Utf8()));
  }
  if (!FrameCanAccessPasswordManager()) {
    LogMessage(logger.get(), Logger::STRING_SECURITY_ORIGIN_FAILURE);
    return;
  }

  // Checks whether the webpage is a redirect page or an empty page.
  if (form_util::IsWebpageEmpty(frame)) {
    LogMessage(logger.get(), Logger::STRING_WEBPAGE_EMPTY);
    return;
  }

  std::vector<WebFormElement> forms = doc.GetOutermostForms();

  if (IsShowAutofillSignaturesEnabled())
    AnnotateFormsAndFieldsWithSignatures(forms, form_cache);
  if (logger)
    logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size());

  size_t num_fields_seen = 0;
  std::vector<FormData> password_forms_data;
  for (const WebFormElement& form_element : forms) {
    if (only_visible) {
      bool is_form_visible =
          std::ranges::any_of(form_element.GetFormControlElements(),  // nocheck
                              &WebElement::IsFocusable);
      LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE,
                  form_element);
      LogBoolean(logger.get(), Logger::STRING_FORM_IS_VISIBLE, is_form_visible);

      // If requested, ignore non-rendered forms, e.g., those styled with
      // display:none.
      if (!is_form_visible)
        continue;
    }

    std::optional<FormData> form_data(
        GetFormDataFromWebForm(form_element, form_cache));
    if (!form_data || !IsRendererRecognizedCredentialForm(*form_data)) {
      continue;
    }
    if (num_fields_seen + form_data->fields().size() > kMaxExtractableFields) {
      break;
    }
    num_fields_seen += form_data->fields().size();

    FormStructureInfo form_structure_info =
        ExtractFormStructureInfo(*form_data);
    if (only_visible || WasFormStructureChanged(form_structure_info)) {
      forms_structure_cache_[form_structure_info.renderer_id] =
          std::move(form_structure_info);

      password_forms_data.push_back(std::move(*form_data));
      continue;
    }

    std::vector<WebFormControlElement> control_elements =
        form_element.GetFormControlElements();  // nocheck
    // Sometimes JS can change autofilled forms. In this case we try to restore
    // values for the changed elements.
    TryFixAutofilledForm(control_elements);
  }

  // See if there are any unassociated input elements that could be used for
  // password submission.
  // TODO(crbug.com/41422255): Consider using TryFixAutofilledForm for the cases
  // when there is no form tag.
  bool add_unowned_inputs = true;
  if (only_visible) {
    std::vector<WebFormControlElement> control_elements =
        form_util::GetOwnedAutofillableFormControls(doc, WebFormElement());
    add_unowned_inputs =
        std::ranges::any_of(control_elements, &WebElement::IsFocusable);
    LogBoolean(logger.get(), Logger::STRING_UNOWNED_INPUTS_VISIBLE,
               add_unowned_inputs);
  }

  if (add_unowned_inputs) {
    std::optional<FormData> form_data(
        GetFormDataFromUnownedInputElements(form_cache));
    if (form_data && IsRendererRecognizedCredentialForm(*form_data) &&
        num_fields_seen + form_data->fields().size() <= kMaxExtractableFields) {
      password_forms_data.push_back(std::move(*form_data));
    }
  }

  if (only_visible) {
    // Send the PasswordFormsRendered message regardless of whether
    // `password_forms_data` is empty. The empty `password_forms_data` are a
    // possible signal to the browser that a pending login attempt succeeded.
    if (unsafe_driver()) {
      unsafe_driver()->PasswordFormsRendered(password_forms_data);
    }
  } else {
    // If there is a password field, but the list of password forms is empty for
    // some reason, add a dummy form to the list. It will cause a request to the
    // store. Therefore, saved passwords will be available for filling on click.
    if (!sent_request_to_store_ && password_forms_data.empty() &&
        HasPasswordField(*frame)) {
      // Set everything that `FormDigest` needs.
      password_forms_data.emplace_back();
    }
    if (!password_forms_data.empty()) {
      sent_request_to_store_ = true;
      if (unsafe_driver()) {
        unsafe_driver()->PasswordFormsParsed(password_forms_data);
      }
    }
  }

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  // Provide warnings about the accessibility of password forms on the page.
  if (!password_forms_data.empty() &&
      (doc.Url().ProtocolIs(url::kHttpScheme) ||
       doc.Url().ProtocolIs(url::kHttpsScheme))) {
    page_passwords_analyser_.AnalyseDocumentDOM(frame);
  }
#endif
}

void PasswordAutofillAgent::DispatchedDOMContentLoadedEvent(
    const SynchronousFormCache& form_cache) {
  SendPasswordForms(/*only_visible=*/false, form_cache);
}

void PasswordAutofillAgent::DidFinishLoad() {
  // The `frame` contents have been rendered.  Let the PasswordManager know
  // which of the loaded frames are actually visible to the user.  This also
  // triggers the "Save password?" infobar if the user just submitted a password
  // form.
  SendPasswordForms(/*only_visible=*/true, /*form_cache=*/{});
}

void PasswordAutofillAgent::DidCommitProvisionalLoad(
    ui::PageTransition transition) {
  checked_safe_browsing_reputation_ = false;
  recorded_first_filling_result_ = false;
}

void PasswordAutofillAgent::OnDestruct() {
  receiver_.reset();
}

bool PasswordAutofillAgent::IsPrerendering() const {
  auto* frame = unsafe_render_frame();
  return frame && frame->GetWebFrame()->GetDocument().IsPrerendering();
}

bool PasswordAutofillAgent::IsUsernameInputField(
    const WebInputElement& input_element) const {
  return input_element &&
         input_element.FormControlTypeForAutofill() != kInputPassword &&
         web_input_to_password_info_.contains(
             GetFieldRendererId(input_element));
}

void PasswordAutofillAgent::ReadyToCommitNavigation(
    WebDocumentLoader* document_loader) {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_ && unsafe_driver()) {
    logger =
        std::make_unique<RendererSavePasswordProgressLogger>(unsafe_driver());
    logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD);
  }

  auto* frame = unsafe_render_frame();
  if (!frame) {
    return;
  }
  if (frame->GetWebFrame()->IsOutermostMainFrame()) {
    // This is a new navigation, so require a new user gesture before filling in
    // passwords.
    gatekeeper_.Reset();
  } else {
    LogMessage(logger.get(), Logger::STRING_FRAME_NOT_MAIN_FRAME);
  }

  CleanupOnDocumentShutdown();
}

// mojom::PasswordAutofillAgent:
void PasswordAutofillAgent::ApplyFillDataOnParsingCompletion(
    const PasswordFormFillData& form_data) {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_ && unsafe_driver()) {
    logger =
        std::make_unique<RendererSavePasswordProgressLogger>(unsafe_driver());
    logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD);
  }
  suggestion_banned_fields_ = form_data.suggestion_banned_fields;

  bool username_password_fields_not_set =
      form_data.username_element_renderer_id.is_null() &&
      form_data.password_element_renderer_id.is_null();
  if (username_password_fields_not_set) {
    // No fields for filling were found during parsing, which means filling
    // fallback case. So save data for fallback filling.
    MaybeStoreFallbackData(form_data);
    return;
  }

  WebInputElement username_element, password_element;
  std::tie(username_element, password_element) =
      FindUsernamePasswordElements(form_data);
  bool is_single_username_fill =
      form_data.password_element_renderer_id.is_null();
  WebElement main_element =
      is_single_username_fill ? username_element : password_element;
  if (!main_element) {
    MaybeStoreFallbackData(form_data);
    // TODO(crbug.com/40626063): Fix logging for single username.
    LogFirstFillingResult(form_data, FillingResult::kNoPasswordElement);
    return;
  }

  times_received_fill_data_[form_data.form_renderer_id]++;
  StoreDataForFillOnAccountSelect(form_data, username_element,
                                  password_element);

  // If wait_for_username is true, we don't want to initially fill the form
  // until the user types in a valid username.
  if (form_data.wait_for_username) {
    LogFirstFillingResult(form_data, FillingResult::kWaitForUsername);
    MaybeTriggerSuggestionsOnFocusedElement(username_element, password_element);
    return;
  }
  FillCredentialsAutomatically(username_element, password_element, form_data,
                               logger.get());
}

void PasswordAutofillAgent::SetLoggingState(bool active) {
  logging_state_active_ = active;
}

void PasswordAutofillAgent::AnnotateFieldsWithParsingResult(
    const ParsingResult& parsing_result) {
  AnnotateFieldWithParsingResult(parsing_result.username_renderer_id,
                                 "username_element");
  AnnotateFieldWithParsingResult(parsing_result.password_renderer_id,
                                 "password_element");
  AnnotateFieldWithParsingResult(parsing_result.new_password_renderer_id,
                                 "new_password_element");
  AnnotateFieldWithParsingResult(parsing_result.confirm_password_renderer_id,
                                 "confirmation_password_element");
}

void PasswordAutofillAgent::InformNoSavedCredentials(
    bool should_show_popup_without_passwords) {
  autofilled_elements_cache_.clear();

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
  should_show_popup_without_passwords_ = should_show_popup_without_passwords;
#endif

  // Clear the actual field values.
  std::vector<WebFormControlElement> elements;
  elements.reserve(all_autofilled_elements_.size());
  for (FieldRendererId id : all_autofilled_elements_) {
    elements.push_back(form_util::GetFormControlByRendererId(id));
  }

  for (WebFormControlElement element : elements) {
    if (!element) {
      continue;
    }
    // Don't clear the actual value of fields that the user has edited manually
    // (which changes the autofill state back to kNotFilled).
    if (element.IsAutofilled()) {
      element.SetValue(WebString());
    }
    element.SetSuggestedValue(WebString());
  }
  all_autofilled_elements_.clear();

  field_data_manager().ClearData();
}

void PasswordAutofillAgent::CheckViewAreaVisible(
    FieldRendererId field_id,
    CheckViewAreaVisibleCallback callback) {
  WebFormControlElement element =
      form_util::GetFormControlByRendererId(field_id);
  if (!element) {
    std::move(callback).Run(false);
    return;
  }

  element.ScrollIntoViewIfNeeded();

  std::move(callback).Run(!element.VisibleBoundsInWidget().IsEmpty());
}

#if BUILDFLAG(IS_ANDROID)
void PasswordAutofillAgent::TriggerFormSubmission() {
  // Find the last interacted element to simulate an enter keystroke at.
  WebFormControlElement form_control =
      GetFormControlByRendererId(field_renderer_id_to_submit_);
  if (!form_control) {
    // The target field doesn't exist anymore. Don't try to submit it.
    return;
  }

  // `form_control` can only be `WebInputElement`, not `WebSelectElement`.
  WebInputElement input = form_control.To<WebInputElement>();
  input.DispatchSimulatedEnter();
  field_renderer_id_to_submit_ = FieldRendererId();
}
#endif

std::optional<FormData> PasswordAutofillAgent::GetFormDataFromWebForm(
    const WebFormElement& web_form,
    const SynchronousFormCache& form_cache) {
  return CreateFormDataFromWebForm(
      web_form, field_data_manager(), &username_detector_cache_,
      autofill_agent_->button_titles_cache(),
      autofill_agent_->GetCallTimerState(
          CallTimerState::CallSite::kGetFormDataFromWebForm),
      form_cache);
}

std::optional<FormData>
PasswordAutofillAgent::GetFormDataFromUnownedInputElements(
    const SynchronousFormCache& form_cache) {
  // The element's frame might have been detached in the meantime (see
  // http://crbug.com/585363, comments 5 and 6), in which case `frame` will
  // be null. This was hardly caused by form submission (unless the user is
  // supernaturally quick), so it is OK to drop the ball here.
  content::RenderFrame* frame = unsafe_render_frame();
  if (!frame)
    return std::nullopt;
  WebLocalFrame* web_frame = frame->GetWebFrame();
  if (!web_frame)
    return std::nullopt;
  return CreateFormDataFromUnownedInputElements(
      *web_frame, field_data_manager(), &username_detector_cache_,
      autofill_agent_->GetCallTimerState(
          CallTimerState::CallSite::kGetFormDataFromUnownedInputElements),
      autofill_agent_->button_titles_cache(), form_cache);
}

void PasswordAutofillAgent::InformAboutFormClearing(
    const WebFormElement& form) {
  if (!FrameCanAccessPasswordManager())
    return;
  for (const auto& element : form.GetFormControlElements()) {
    // Notify PasswordManager if `form` has password fields that have user typed
    // input or input autofilled on user trigger.
    if (IsPasswordFieldFilledByUser(element)) {
      NotifyPasswordManagerAboutClearedForm(form);
      return;
    }
  }
}

void PasswordAutofillAgent::InformAboutFieldClearing(
    const WebInputElement& cleared_element) {
  if (!FrameCanAccessPasswordManager())
    return;
  DCHECK(cleared_element.Value().IsEmpty());
  FieldRendererId field_id = form_util::GetFieldRendererId(cleared_element);
  // Ignore fields that had no user input or autofill on user trigger.
  if (!field_data_manager().DidUserType(field_id) &&
      !field_data_manager().WasAutofilledOnUserTrigger(field_id)) {
    return;
  }

  WebFormElement form = cleared_element.GetOwningFormForAutofill();
  if (!form) {
    // Process password field clearing for fields outside the <form> tag.
    if (std::optional<FormData> unowned_form_data =
            GetFormDataFromUnownedInputElements(/*form_cache=*/{})) {
      if (unsafe_driver()) {
        unsafe_driver()->PasswordFormCleared(*unowned_form_data);
      }
    }
    return;
  }
  // Process field clearing for a form under a <form> tag.
  // Only notify PasswordManager in case all user filled password fields were
  // cleared.
  bool cleared_all_password_fields = std::ranges::all_of(
      form.GetFormControlElements(), [this](const auto& el) {
        return !IsPasswordFieldFilledByUser(el) || el.Value().IsEmpty();
      });
  if (cleared_all_password_fields)
    NotifyPasswordManagerAboutClearedForm(form);
}

std::optional<PasswordSuggestionRequest>
PasswordAutofillAgent::CreateRequestForDomain(
    const WebInputElement& element,
    AutofillSuggestionTriggerSource trigger_source,
    const SynchronousFormCache& form_cache) {
  WebInputElement username_element;
  WebInputElement password_element;
  PasswordInfo* password_info = nullptr;
  FindPasswordInfoForElement(element, UseFallbackData(true), &username_element,
                             &password_element, &password_info);

  if (!password_info) {
    MaybeCheckSafeBrowsingReputation(element);
    if (!CanShowPopupWithoutPasswords(password_element)) {
      return std::nullopt;
    }
  }

  if (!element.IsTextField() || !IsElementEditable(element)) {
    return std::nullopt;
  }
  // Check that at least one fillable element is editable.
  if (!IsUsernameOrPasswordFillable(username_element, password_element,
                                    password_info)) {
    return std::nullopt;
  }

  // Don't attempt to autofill with values that are too large.
  if (element.Value().length() > kMaximumTextSizeForAutocomplete) {
    return std::nullopt;
  }

  if (!HasDocumentWithValidFrame(element)) {
    return std::nullopt;
  }

  // If a username element is focused, show suggestions unless all possible
  // usernames are filtered.
  if (element.FormControlTypeForAutofill() != kInputPassword) {
    std::u16string username_prefix;
    if (!ShouldShowFullSuggestionListForPasswordManager(trigger_source,
                                                        element) &&
        !base::FeatureList::IsEnabled(
            password_manager::features::kNoPasswordSuggestionFiltering)) {
      if (!password_info ||
          !CanShowUsernameSuggestion(password_info->fill_data,
                                     element.Value().Utf16())) {
        return std::nullopt;
      }
      username_prefix = element.Value().Utf16();
    }
    return CreateSuggestionRequest(username_prefix, element, trigger_source,
                                   form_cache);
  }

  // If the element is a password field, do not to show a popup if the user has
  // already accepted a password suggestion on another password field.
  if (HasAcceptedSuggestionOnOtherField(element)) {
    return std::nullopt;
  }

  return CreateSuggestionRequest(std::u16string(), element, trigger_source,
                                 form_cache);
}

std::optional<PasswordSuggestionRequest>
PasswordAutofillAgent::CreateManualFallbackRequest(
    const WebInputElement& element,
    const SynchronousFormCache& form_cache) {
  WebInputElement username_element;
  WebInputElement password_element;
  PasswordInfo* password_info = nullptr;
  if (!FindPasswordInfoForElement(element, UseFallbackData(false),
                                  &username_element, &password_element,
                                  &password_info)) {
    // Perform this action only if there's no passwords saved for the triggering
    // field. Manual fallback suggestions can be shown on any field.
    MaybeCheckSafeBrowsingReputation(element);
  }

  if (!FrameCanAccessPasswordManager()) {
    return std::nullopt;
  }

  if (!HasDocumentWithValidFrame(element)) {
    return std::nullopt;
  }

  return CreateSuggestionRequest(
      std::u16string(), element,
      AutofillSuggestionTriggerSource::kManualFallbackPasswords, form_cache);
}

bool PasswordAutofillAgent::HasAcceptedSuggestionOnOtherField(
    const WebInputElement& element) {
  WebInputElement username_element;
  WebInputElement password_element;
  PasswordInfo* password_info = nullptr;
  FindPasswordInfoForElement(element, UseFallbackData(true), &username_element,
                             &password_element, &password_info);
  return password_info &&
         password_info->password_field_suggestion_was_accepted &&
         GetFieldRendererId(element) != password_info->password_field_id;
}

void PasswordAutofillAgent::CleanupOnDocumentShutdown() {
  web_input_to_password_info_.clear();
  password_to_username_.clear();
  last_supplied_password_info_iter_ = web_input_to_password_info_.end();
  field_data_manager().ClearData();
  previewed_elements_.clear();
  sent_request_to_store_ = false;
  checked_safe_browsing_reputation_ = false;
  username_detector_cache_.clear();
  forms_structure_cache_.clear();
  autofilled_elements_cache_.clear();
  all_autofilled_elements_.clear();
  field_renderer_id_to_submit_ = FieldRendererId();
  suggestion_banned_fields_.clear();
  times_received_fill_data_.clear();
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
  page_passwords_analyser_.Reset();
#endif
}

void PasswordAutofillAgent::InformBrowserAboutUserInput(
    const WebFormElement& form,
    const WebInputElement& element,
    const SynchronousFormCache& form_cache) {
  DCHECK(form || element);
  if (!FrameCanAccessPasswordManager())
    return;
  std::optional<FormData> form_data =
      form ? GetFormDataFromWebForm(form, form_cache)
           : GetFormDataFromUnownedInputElements(form_cache);
  if (!form_data) {
    return;
  }
  // Notify the browser about user inputs if `form` is recognized as a
  // credential form in the renderer, or if the browser has parsed `element` as
  // password-related and provided filling data for it.
  if (IsRendererRecognizedCredentialForm(*form_data) ||
      (element &&
       web_input_to_password_info_.contains(GetFieldRendererId(element)))) {
    if (unsafe_driver()) {
      unsafe_driver()->InformAboutUserInput(*form_data);
    }
  }
}

bool PasswordAutofillAgent::FillCredentialsAutomatically(
    WebInputElement username_element,
    WebInputElement password_element,
    const PasswordFormFillData& fill_data,
    RendererSavePasswordProgressLogger* logger) {
  LogMessage(logger, Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD);

  bool is_single_username_fill = !password_element;
  WebInputElement main_element =
      is_single_username_fill ? username_element : password_element;

  if (IsInCrossOriginIframeOrEmbeddedFrame(main_element)) {
    LogMessage(logger, Logger::STRING_FAILED_TO_FILL_INTO_IFRAME);
    LogFirstFillingResult(fill_data, FillingResult::kBlockedByFrameHierarchy);
    return false;
  }

  // Don't fill username if password can't be set.
  if (!IsElementEditable(main_element)) {
    LogMessage(logger,
               Logger::STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT);
    LogFirstFillingResult(fill_data,
                          FillingResult::kPasswordElementIsNotAutocompleteable);
    return false;
  }

  // `current_username` is the username for credentials that are going to be
  // autofilled. It is selected according to the algorithm:
  // 1. If the page already contains a non-empty value in `username_element`
  // that is not found in the list of values known to be used as placeholders,
  // this is adopted and not overridden.
  // 2. Default username from `fill_data` if the username field is
  // autocompletable.
  // 3. Empty if username field doesn't exist or if username field is empty and
  // not autocompletable (no username case).
  std::u16string current_username;

  // Whether the username element was prefilled with content that was on a
  // list of known placeholder texts that should be overridden (e.g. "username
  // or email" or there is a server hint that it is just a placeholder).
  bool prefilled_placeholder_username = false;

  if (username_element) {
    // This is a heuristic guess. If the credential is stored for
    // www.example.com, the username may be prefilled with "@example.com".
    std::string possible_email_domain =
        GetRegistryControlledDomain(fill_data.url);

    prefilled_placeholder_username =
        !username_element.Value().IsEmpty() &&
        PossiblePrefilledUsernameValue(username_element.Value().Utf8(),
                                       possible_email_domain);

    if (!username_element.Value().IsEmpty() &&
        username_element.GetAutofillState() == WebAutofillState::kNotFilled &&
        !prefilled_placeholder_username) {
      // Username is filled with content that was not on a list of known
      // placeholder texts (e.g. "username or email") nor there is server-side
      // data that this value is placeholder.
      current_username = username_element.Value().Utf16();
    } else if (IsElementEditable(username_element)) {
      current_username = fill_data.preferred_login.username_value;
    }
  }

  // `username` and `password` will contain the match found if any.
  std::u16string username;
  std::u16string password;

  bool exact_username_match =
      !username_element || IsElementEditable(username_element);

  FindMatchesByUsername(fill_data, current_username, exact_username_match,
                        logger, &username, &password);

  if (password.empty() && !is_single_username_fill) {
    if (username_element && !username_element.Value().IsEmpty() &&
        !prefilled_placeholder_username) {
      LogMessage(logger, Logger::STRING_FAILED_TO_FILL_PREFILLED_USERNAME);
      LogFirstFillingResult(
          fill_data, FillingResult::kUsernamePrefilledWithIncompatibleValue);
      return false;
    }
    LogMessage(logger,
               Logger::STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME);
    LogFirstFillingResult(fill_data,
                          FillingResult::kFoundNoPasswordForUsername);
    return false;
  }

  // Call OnFieldAutofilled before WebInputElement::SetAutofillState which may
  // cause frame closing.
  if (password_generation_agent_ && !is_single_username_fill)
    password_generation_agent_->OnFieldAutofilled(password_element);

  // Input matches the username, fill in required values.
  if (username_element && IsElementEditable(username_element)) {
    if (!username.empty() &&
        (username_element.Value().IsEmpty() ||
         username_element.GetAutofillState() != WebAutofillState::kNotFilled ||
         prefilled_placeholder_username)) {
      FillFieldAutomatically(username, username_element);
    }
    if (logger)
      logger->LogElementName(Logger::STRING_USERNAME_FILLED, username_element);
  }

  if (!is_single_username_fill) {
    FillFieldAutomatically(password, password_element);
    if (logger)
      logger->LogElementName(Logger::STRING_PASSWORD_FILLED, password_element);
  }

  LogFirstFillingResult(fill_data, FillingResult::kSuccess);
  return true;
}

void PasswordAutofillAgent::FireHostSubmitEvent(
    FormRendererId form_id,
    base::optional_ref<const FormData> submitted_form,
    mojom::SubmissionSource source) {
  switch (source) {
    case mojom::SubmissionSource::NONE:
      NOTREACHED();
    case mojom::SubmissionSource::FORM_SUBMISSION:
      CHECK(submitted_form.has_value());
      OnFormSubmitted(*submitted_form);
      return;
    case mojom::SubmissionSource::PROBABLY_FORM_SUBMITTED:
      return;
    case mojom::SubmissionSource::SAME_DOCUMENT_NAVIGATION:
    case mojom::SubmissionSource::XHR_SUCCEEDED:
    case mojom::SubmissionSource::FRAME_DETACHED:
    case mojom::SubmissionSource::DOM_MUTATION_AFTER_AUTOFILL:
      if (auto* driver = unsafe_driver();
          driver && FrameCanAccessPasswordManager()) {
        base::UmaHistogramEnumeration(kSubmissionSourceHistogram, source);
        driver->DynamicFormSubmission(ToSubmissionIndicatorEvent(source));
      }
      return;
  }
  NOTREACHED();
}

void PasswordAutofillAgent::OnFormSubmitted(const FormData& submitted_form) {
  const WebFormElement form_element =
      GetFormByRendererId(submitted_form.renderer_id());
  if (!form_element) {
    return;
  }
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_ && unsafe_driver()) {
    logger =
        std::make_unique<RendererSavePasswordProgressLogger>(unsafe_driver());
    LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT,
                form_element);
  }

  if (!FrameCanAccessPasswordManager()) {
    LogMessage(logger.get(), Logger::STRING_SECURITY_ORIGIN_FAILURE);
    return;
  }

  std::optional<FormData> processed_submitted_form = GetFormDataFromWebForm(
      form_element, SynchronousFormCache(submitted_form));

  if (!processed_submitted_form || !HasTextInputs(*processed_submitted_form)) {
    return;
  }

  processed_submitted_form->set_submission_event(
      SubmissionIndicatorEvent::HTML_FORM_SUBMISSION);

  processed_submitted_form->set_fields(FillNonTypedOrFilledPropertiesMasks(
      processed_submitted_form->ExtractFields(), field_data_manager()));

  base::UmaHistogramEnumeration(kSubmissionSourceHistogram,
                                mojom::SubmissionSource::FORM_SUBMISSION);
  if (auto* driver = unsafe_driver()) {
    driver->PasswordFormSubmitted(*processed_submitted_form);
  }
}

void PasswordAutofillAgent::HidePopup() {
  if (autofill_agent_->unsafe_autofill_driver()) {
    autofill_agent_->unsafe_autofill_driver()->HidePopup();
  }
}

bool PasswordAutofillAgent::CanShowPopupWithoutPasswords(
    const WebInputElement& password_element) const {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
  return password_element && IsElementEditable(password_element) &&
         should_show_popup_without_passwords_;
#else
  return false;
#endif
}

mojom::PasswordManagerDriver* PasswordAutofillAgent::unsafe_driver() {
  if (IsPrerendering()) {
    if (!deferring_password_manager_driver_) {
      deferring_password_manager_driver_ =
          std::make_unique<DeferringPasswordManagerDriver>(this);
    }
    return deferring_password_manager_driver_.get();
  }

  // Lazily bind this interface.
  if (auto* frame = unsafe_render_frame(); frame && !password_manager_driver_) {
    frame->GetRemoteAssociatedInterfaces()->GetInterface(
        &password_manager_driver_);
  }

  return password_manager_driver_.get();
}

std::pair<WebInputElement, WebInputElement>
PasswordAutofillAgent::FindUsernamePasswordElements(
    const PasswordFormFillData& form_data) {
  const FieldRendererId username_renderer_id =
      form_data.username_element_renderer_id;
  const FieldRendererId password_renderer_id =
      form_data.password_element_renderer_id;
  const bool is_username_present = !username_renderer_id.is_null();
  const bool is_password_present = !password_renderer_id.is_null();

  std::vector<FieldRendererId> element_ids;
  if (is_password_present)
    element_ids.push_back(password_renderer_id);
  if (is_username_present)
    element_ids.push_back(username_renderer_id);

  std::vector<WebFormControlElement> elements;
  elements.reserve(element_ids.size());
  for (FieldRendererId id : element_ids) {
    elements.push_back(form_util::GetFormControlByRendererId(id));
  }

  // Set password element.
  WebInputElement password_field;
  size_t current_index = 0;
  if (is_password_present)
    password_field = elements[current_index++].DynamicTo<WebInputElement>();

  // Set username element.
  WebInputElement username_field;
  if (is_username_present)
    username_field = elements[current_index++].DynamicTo<WebInputElement>();

  return std::make_pair(username_field, password_field);
}

void PasswordAutofillAgent::StoreDataForFillOnAccountSelect(
    const PasswordFormFillData& form_data,
    WebInputElement username_element,
    WebInputElement password_element) {
  WebInputElement main_element =
      username_element ? username_element : password_element;

  PasswordInfo password_info;
  password_info.fill_data = form_data;
  if (password_element) {
    password_info.password_field_id = GetFieldRendererId(password_element);
  }
  if (main_element) {
    web_input_to_password_info_[GetFieldRendererId(main_element)] =
        password_info;
    last_supplied_password_info_iter_ =
        web_input_to_password_info_.find(GetFieldRendererId(main_element));
    if (main_element.FormControlTypeForAutofill() != kInputPassword &&
        password_element && username_element) {
      password_to_username_[GetFieldRendererId(password_element)] =
          GetFieldRendererId(username_element);
    }
  }
}

void PasswordAutofillAgent::MaybeStoreFallbackData(
    const PasswordFormFillData& form_data) {
  if (!web_input_to_password_info_.empty())
    return;
  // If for some reasons elements for filling were not found (for example
  // because they were renamed by JavaScript) then add fill data for
  // `web_input_to_password_info_`. When the user clicks on a password field
  // which is not a key in `web_input_to_password_info_`, the first element from
  // `web_input_to_password_info_` will be used in
  // PasswordAutofillAgent::FindPasswordInfoForElement to propose to fill.
  PasswordInfo password_info;
  password_info.fill_data = form_data;
  web_input_to_password_info_[FieldRendererId()] = password_info;
  last_supplied_password_info_iter_ = web_input_to_password_info_.begin();
}

void PasswordAutofillAgent::LogFirstFillingResult(
    const PasswordFormFillData& form_data,
    FillingResult result) {
  if (recorded_first_filling_result_) {
    return;
  }
  UMA_HISTOGRAM_ENUMERATION("PasswordManager.FirstRendererFillingResult",
                            result);
  if (auto* driver = unsafe_driver()) {
    driver->LogFirstFillingResult(form_data.form_renderer_id,
                                  base::strict_cast<int32_t>(result));
  }
  recorded_first_filling_result_ = true;
}

PasswordAutofillAgent::FormStructureInfo
PasswordAutofillAgent::ExtractFormStructureInfo(const FormData& form_data) {
  FormStructureInfo result;
  result.renderer_id = form_data.renderer_id();
  result.fields.resize(form_data.fields().size());

  for (auto [form_field, field_info] :
       std::views::zip(form_data.fields(), result.fields)) {
    field_info.renderer_id = form_field.renderer_id();
    field_info.form_control_type = form_field.form_control_type();
    field_info.autocomplete_attribute = form_field.autocomplete_attribute();
    field_info.is_focusable = form_field.is_focusable();
  }

  return result;
}

bool PasswordAutofillAgent::WasFormStructureChanged(
    const FormStructureInfo& form_info) const {
  if (form_info.renderer_id.is_null()) {
    return true;
  }

  auto cached_form = forms_structure_cache_.find(form_info.renderer_id);
  if (cached_form == forms_structure_cache_.end())
    return true;

  const FormStructureInfo& cached_form_info = cached_form->second;

  if (form_info.fields.size() != cached_form_info.fields.size())
    return true;

  for (auto [form_field, cached_form_field] :
       std::views::zip(form_info.fields, cached_form_info.fields)) {
    if (form_field.renderer_id != cached_form_field.renderer_id) {
      return true;
    }

    if (form_field.form_control_type != cached_form_field.form_control_type)
      return true;

    if (form_field.autocomplete_attribute !=
        cached_form_field.autocomplete_attribute) {
      return true;
    }

    if (form_field.is_focusable != cached_form_field.is_focusable)
      return true;
  }
  return false;
}

void PasswordAutofillAgent::TryFixAutofilledForm(
    std::vector<WebFormControlElement>& control_elements) const {
  for (WebFormControlElement& control_element : control_elements) {
    auto cached_element = autofilled_elements_cache_.find(
        form_util::GetFieldRendererId(control_element));
    if (cached_element == autofilled_elements_cache_.end()) {
      continue;
    }
    // autofilled_elements_cache_ stores values filled at page load time and
    // gets wiped when we observe a user gesture. During this time, the
    // username/password fields can be in preview state and we restore this
    // state if JavaScript modifies the field's value.
    const WebString& cached_value = cached_element->second;
    if (cached_value != control_element.SuggestedValue()) {
      control_element.SetSuggestedValue(cached_value);
    }
  }
}

void PasswordAutofillAgent::FillFieldAutomatically(const std::u16string& value,
                                                   WebInputElement field) {
  CHECK(field);
  // Do not autofill on load fields that have any user typed input.
  const FieldRendererId field_id = form_util::GetFieldRendererId(field);
  if (field_data_manager().DidUserType(field_id)) {
    return;
  }
  if (field.Value().Utf16() == value) {
    return;
  }
  field.SetSuggestedValue(WebString::FromUtf16(value));
  field.SetAutofillState(WebAutofillState::kAutofilled);
  // Wait to fill until a user gesture occurs. This is to make sure that we do
  // not fill in the DOM with a password until we believe the user is
  // intentionally interacting with the page.
  gatekeeper_.RegisterElement(field);
  field_data_manager().UpdateFieldDataMap(
      field_id, value, FieldPropertiesFlags::kAutofilledOnPageLoad);
  autofilled_elements_cache_.emplace(field_id, WebString::FromUtf16(value));
  all_autofilled_elements_.insert(field_id);
}

bool PasswordAutofillAgent::IsPasswordFieldFilledByUser(
    const WebFormControlElement& element) const {
  FieldRendererId element_id = form_util::GetFieldRendererId(element);
  return element.FormControlTypeForAutofill() ==
             blink::mojom::FormControlType::kInputPassword &&
         (field_data_manager().DidUserType(element_id) ||
          field_data_manager().WasAutofilledOnUserTrigger(element_id));
}

void PasswordAutofillAgent::NotifyPasswordManagerAboutClearedForm(
    const WebFormElement& cleared_form) {
  CHECK(cleared_form);
  if (std::optional<FormData> form_data = form_util::ExtractFormData(
          cleared_form.GetDocument(), cleared_form, field_data_manager(),
          autofill_agent_->GetCallTimerState(
              CallTimerState::CallSite::kNotifyPasswordManagerAboutClearedForm),
          autofill_agent_->button_titles_cache())) {
    if (auto* driver = unsafe_driver()) {
      driver->PasswordFormCleared(*form_data);
    }
  }
}

void PasswordAutofillAgent::MaybeTriggerSuggestionsOnFocusedElement(
    const WebInputElement& username_element,
    const WebInputElement& password_element) {
  WebInputElement focused_element;
  if (username_element && username_element.Focused()) {
    focused_element = username_element;
  } else if (password_element && password_element.Focused()) {
    focused_element = password_element;
  } else {
    return;
  }

  std::optional<FormData> form_data = GetFormDataFromWebForm(
      focused_element.GetOwningFormForAutofill(), /*form_cache=*/{});
  if (form_data && (times_received_fill_data_[form_data->renderer_id()] == 1) &&
#if BUILDFLAG(IS_ANDROID)
      // Limit showing suggestions on autofocus to WebAuthn forms only, since
      // Android suggestion UI (TTF) can be much more intrusive.
      IsWebAuthnForm(form_data) &&
#endif  // BUILDFLAG(IS_ANDROID)
      base::FeatureList::IsEnabled(
          password_manager::features::kShowSuggestionsOnAutofocus)) {
    // Updating the focused field in the `FocusStateNotifier` to the currently
    // focused field is typically a no-op, but this isn't set for an
    // autofocused field. Setting it here allows a notification to proceed
    // when the initially-focused field is blurred.
    std::tie(focus_state_notifier_.focused_field_type_,
             focus_state_notifier_.focused_field_id_) =
        focus_state_notifier_.GetFocusedFieldInfo(focused_element);
    autofill_agent_->TriggerSuggestions(
        form_util::GetFieldRendererId(focused_element),
        AutofillSuggestionTriggerSource::kPasswordManagerProcessedFocusedField);
  }
}

}  // namespace autofill
