// Copyright 2014 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/browser/content_autofill_driver.h"

#include <concepts>
#include <functional>
#include <type_traits>
#include <utility>
#include <variant>

#include "base/barrier_callback.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "components/autofill/content/browser/bad_message.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/foundations/autofill_client.h"
#include "components/autofill/core/browser/foundations/autofill_driver_router.h"
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/autofill_debug_features.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "mojo/public/cpp/bindings/message.h"
#include "services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom-shared.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
#include "third_party/abseil-cpp/absl/functional/overload.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "url/origin.h"

namespace autofill {

// Allows the anonymous namespace to access selected members of
// ContentAutofillDriver.
struct ContentAutofillDriverAttorney {
 public:
  static const mojo::AssociatedRemote<mojom::AutofillAgent>& GetAutofillAgent(
      ContentAutofillDriver& driver) {
    return driver.GetAutofillAgent();
  }

  static AutofillManager::RendererEventPassKey autofill_manager_pass_key() {
    return ContentAutofillDriver::autofill_manager_pass_key();
  }
};

namespace {

template <typename T, typename... Ts>
concept AnyOf =
    (std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<Ts>> || ...);

// Lift() elevates data from the a renderer process to the browser process.
// Every data received from a renderer should immediately be lifted.
//
// Lifting includes, for example, setting security-critical data like frame
// tokens and origins of Form[Field]Data. Another example is transforming
// coordinates from the originating frame's space to the top-level frame.

// No-op: add types to the `requires` clause below as necessary.
template <typename T>
  requires(std::is_scalar_v<std::remove_cvref_t<T>> ||
           AnyOf<T,
                 bool,
                 AutofillDriverRouter::RoutedCallback<>,
                 FillId,
                 base::TimeTicks,
                 std::u16string>)
T&& Lift(ContentAutofillDriver& source, T&& x) {
  return std::forward<T>(x);
}

gfx::Rect Lift(ContentAutofillDriver& source, gfx::Rect r) {
  if (content::RenderWidgetHostView* view =
          source.render_frame_host()->GetView()) {
    r.set_origin(view->TransformPointToRootCoordSpace(r.origin()));
  }
  return r;
}

gfx::RectF Lift(ContentAutofillDriver& source, gfx::RectF r) {
  if (content::RenderWidgetHostView* view =
          source.render_frame_host()->GetView()) {
    r.set_origin(view->TransformPointToRootCoordSpaceF(r.origin()));
  }
  return r;
}

FormData Lift(ContentAutofillDriver& source, FormData form) {
  content::RenderFrameHost& rfh = *source.render_frame_host();
  form.set_host_frame(source.GetFrameToken());
  form.set_main_frame_origin(rfh.GetMainFrame()->GetLastCommittedOrigin());

  // GetLastCommittedURL() doesn't include URL updates due to
  // document.open() and so it might be about:blank or about:srcdoc. In this
  // case fallback to GetLastCommittedOrigin(). See crbug.com/1209270.
  GURL unstripped_url = rfh.GetLastCommittedURL();
  if (unstripped_url.SchemeIs(url::kAboutScheme)) {
    unstripped_url = rfh.GetLastCommittedOrigin().GetURL();
  }
  form.set_url(StripAuthAndParams(unstripped_url));
  form.set_full_url(StripAuth(unstripped_url));

  // The form signature must be calculated after setting FormData::url.
  FormSignature signature = CalculateFormSignature(form);
  std::vector<FormFieldData> fields = form.ExtractFields();
  for (FormFieldData& field : fields) {
    field.set_host_frame(form.host_frame());
    field.set_host_form_id(form.renderer_id());
    field.set_host_form_signature(signature);
    field.set_origin(rfh.GetLastCommittedOrigin());
    field.set_bounds(Lift(source, field.bounds()));
  }
  form.set_fields(std::move(fields));
  return form;
}

FormGlobalId Lift(ContentAutofillDriver& source, FormRendererId id) {
  return FormGlobalId(source.GetFrameToken(), id);
}

FieldGlobalId Lift(ContentAutofillDriver& source, FieldRendererId id) {
  return FieldGlobalId(source.GetFrameToken(), id);
}

JavaScriptFieldModification Lift(
    ContentAutofillDriver& source,
    const mojom::JavaScriptFieldModificationPtr& mod) {
  return JavaScriptFieldModification{
      .field_id = Lift(source, mod->field_id),
      .modification_type = mod->modification_type,
  };
}

PasswordSuggestionRequest Lift(ContentAutofillDriver& source,
                               PasswordSuggestionRequest request) {
  request.form_data = Lift(source, std::move(request.form_data));
  request.field.bounds = Lift(source, std::move(request.field.bounds));
  request.field.element_id = Lift(source, request.field.element_id.renderer_id);
  request.username_field_id =
      Lift(source, request.username_field_id.renderer_id);
  request.password_field_id =
      Lift(source, request.password_field_id.renderer_id);
  return request;
}

template <typename T>
std::optional<T> Lift(ContentAutofillDriver& source, std::optional<T> x) {
  std::optional<T> y;
  if (x) {
    y.emplace(Lift(source, *std::move(x)));
  }
  return y;
}

template <typename T>
auto Lift(ContentAutofillDriver& source, const std::vector<T>& xs) {
  std::vector<std::remove_cvref_t<decltype(Lift(source, xs.front()))>> ys;
  ys.reserve(xs.size());
  for (const auto& x : xs) {
    ys.push_back(Lift(source, x));
  }
  return ys;
}

template <typename... Args>
base::OnceCallback<void(Args...)> Lift(ContentAutofillDriver& source,
                                       base::OnceCallback<void(Args...)> cb) {
  return base::BindOnce(
      [](raw_ref<ContentAutofillDriver> source,
         base::OnceCallback<void(Args...)> cb, Args... args) {
        std::move(cb).Run(Lift(*source, std::forward<Args>(args))...);
      },
      raw_ref(source), std::move(cb));
}

// WithNewVersion() bumps the FormData::version of each form. This should be
// called for every browser form before it enters AutofillManager so that
// AutofillManager can distinguish newer and older forms.
//
// TODO(crbug.com/40144964): Remove once FormData objects aren't stored
// globally anymore.

// No-op: add types to the `requires` clause below as necessary.
template <typename T>
  requires(std::is_scalar_v<std::remove_cvref_t<T>> ||
           AnyOf<T,
                 bool,
                 FieldGlobalId,
                 FormGlobalId,
                 FillId,
                 base::TimeTicks,
                 gfx::Rect,
                 std::u16string,
                 std::vector<FormGlobalId>,
                 std::vector<FieldGlobalId>,
                 std::vector<JavaScriptFieldModification>>)
T&& WithNewVersion(T&& x) {
  return std::forward<T>(x);
}

auto& WithNewVersion(const FormData& browser_form) {
  static FormVersion version_counter;
  ++*version_counter;
  // This const_cast is a hack to avoid additional copies. It's OK because the
  // FormData is owned by AutofillDriverRouter, FormData::version is written
  // only here and read only in AutofillManager.
  const_cast<FormData&>(browser_form).set_version(version_counter);
  return browser_form;
}

auto& WithNewVersion(const std::optional<FormData>& browser_form) {
  if (browser_form) {
    WithNewVersion(*browser_form);
  }
  return browser_form;
}

std::vector<FormData> WithNewVersion(std::vector<FormData> browser_forms) {
  for (FormData& form : browser_forms) {
    WithNewVersion(form);
  }
  return browser_forms;
}

std::optional<PasswordSuggestionRequest> WithNewVersion(
    std::optional<PasswordSuggestionRequest> password_request) {
  if (password_request) {
    WithNewVersion(password_request->form_data);
  }
  return password_request;
}

template <typename... Args>
base::OnceCallback<void(Args...)> WithNewVersion(
    base::OnceCallback<void(Args...)> cb) {
  return base::BindOnce(
      [](base::OnceCallback<void(Args...)> cb, Args... args) {
        std::move(cb).Run(WithNewVersion(std::forward<Args>(args))...);
      },
      std::move(cb));
}

// Routes an event from the browser to one or multiple AutofillAgents.
//
// Routing converts values and types: for example, browser forms become renderer
// forms, and FieldGlobalIds become FieldRendererIds.
template <typename R,
          typename... RouterArgs,
          typename... AgentArgs,
          typename... ActualArgs>
R RouteToAgent(AutofillDriverRouter& router,
               R (AutofillDriverRouter::*router_fun)(
                   AutofillDriverRouter::RoutedCallback<AgentArgs...>,
                   RouterArgs...),
               void (mojom::AutofillAgent::*agent_fun)(AgentArgs...),
               ActualArgs&&... args) {
  return (router.*router_fun)(
      [&agent_fun](autofill::AutofillDriver& target, AgentArgs... args) {
        if (!target.IsActive()) {
          // We early-return rather than crashing or killing the renderer
          // because Autofill might want to communicate with a frame that just
          // became inactive due to race conditions. See crbug.com/345195973.
          LOG(WARNING) << "Skipped Autofill message for inactive frame";
          return;
        }
        mojom::AutofillAgent& agent =
            *ContentAutofillDriverAttorney::GetAutofillAgent(
                static_cast<ContentAutofillDriver&>(target));
        (agent.*agent_fun)(std::forward<AgentArgs>(args)...);
      },
      std::forward<ActualArgs>(args)...);
}

// Routes an event from the renderer to one or multiple AutofillManagers.
//
// Routing converts values and types: for example, renderer forms become browser
// forms, and FieldRendererIds become FieldGlobalIds. Additionally, this
// function takes care of some necessary pre- and postprocessing: for example,
// it sets FormData::frame_token and transforms graphical coordinates, and bumps
// the browser form's FormData::version.
template <typename... RouterArgs,
          typename... ManagerArgs,
          typename... ActualArgs>
void RouteToManager(
    ContentAutofillDriver& source,
    AutofillDriverRouter& router,
    void (AutofillDriverRouter::*router_fun)(
        AutofillDriverRouter::RoutedCallback<ManagerArgs...>,
        autofill::AutofillDriver& source,
        RouterArgs...),
    void (AutofillManager::*manager_fun)(ManagerArgs...,
                                         AutofillManager::RendererEventPassKey),
    ActualArgs&&... args) {
  if (!bad_message::CheckArgs(args...) ||
      !bad_message::CheckFrameNotPrerendering(source.render_frame_host())) {
    return;
  }
  return (router.*router_fun)(
      [&manager_fun](autofill::AutofillDriver& target, ManagerArgs... args) {
        AutofillManager& manager = target.GetAutofillManager();
        (manager.*manager_fun)(
            WithNewVersion(std::forward<ManagerArgs>(args))...,
            ContentAutofillDriverAttorney::autofill_manager_pass_key());
      },
      source, Lift(source, std::forward<ActualArgs>(args))...);
}

}  // namespace

ContentAutofillDriver::ContentAutofillDriver(
    content::RenderFrameHost* render_frame_host,
    ContentAutofillDriverFactory* owner)
    : render_frame_host_(*render_frame_host), owner_(*owner) {
  autofill_manager_ = GetAutofillClient().CreateManager(/*pass_key=*/{}, *this);
}

ContentAutofillDriver::~ContentAutofillDriver() {
  owner_->router().UnregisterDriver(*this, /*driver_is_dying=*/true);
}

void ContentAutofillDriver::Reset(ContentAutofillDriverFactoryPassKey) {
  owner_->router().UnregisterDriver(*this, /*driver_is_dying=*/false);
}

void ContentAutofillDriver::TriggerFormExtractionInDriverFrame(
    AutofillDriverRouterAndFormForestPassKey pass_key) {
  if (!IsActive()) {
    LOG(WARNING) << "Skipped Autofill message for inactive frame";
    return;
  }
  GetAutofillAgent()->TriggerFormExtraction();
}

void ContentAutofillDriver::TriggerFormExtractionInAllFrames(
    base::OnceCallback<void(bool success)> form_extraction_finished_callback) {
  std::vector<ContentAutofillDriver*> drivers;
  render_frame_host()->GetMainFrame()->ForEachRenderFrameHost(
      [&drivers](content::RenderFrameHost* rfh) {
        if (rfh->IsActive()) {
          if (auto* driver = GetForRenderFrameHost(rfh)) {
            drivers.push_back(driver);
          }
        }
      });
  auto barrier_callback = base::BarrierCallback<bool>(
      drivers.size(),
      base::BindOnce(
          [](base::OnceCallback<void(bool success)>
                 form_extraction_finished_callback,
             const std::vector<bool>& successes) {
            std::move(form_extraction_finished_callback)
                .Run(std::ranges::all_of(successes, std::identity()));
          },
          std::move(form_extraction_finished_callback)));
  for (ContentAutofillDriver* driver : drivers) {
    driver->GetAutofillAgent()->TriggerFormExtractionWithResponse(
        barrier_callback);
  }
}

void ContentAutofillDriver::ClearFormCacheInAllFrames() {
  render_frame_host()->GetMainFrame()->ForEachRenderFrameHost(
      [](content::RenderFrameHost* rfh) {
        if (rfh->IsActive()) {
          if (auto* driver = GetForRenderFrameHost(rfh)) {
            driver->GetAutofillAgent()->ClearFormCache();
          }
        }
      });
}

void ContentAutofillDriver::ObserveFieldVisibility(
    const FieldGlobalId& field_id,
    mojo::PendingRemote<mojom::AutofillVisibilityObserver> observer) {
  RouteToAgent(router(), &AutofillDriverRouter::ObserveFieldVisibility,
               &mojom::AutofillAgent::ObserveFieldVisibility, field_id,
               std::move(observer));
}

void ContentAutofillDriver::GetFourDigitCombinationsFromDom(
    base::OnceCallback<void(const std::vector<std::string>&)>
        potential_matches) {
  if (!IsActive()) {
    LOG(WARNING) << "Skipped Autofill message for inactive frame";
    std::move(potential_matches).Run({});
    return;
  }
  content::RenderFrameHost* main_rfh = render_frame_host_->GetMainFrame();
  if (auto* main_driver = GetForRenderFrameHost(main_rfh)) {
    main_driver->GetAutofillAgent()
        ->GetPotentialLastFourCombinationsForStandaloneCvc(
            std::move(potential_matches));
  }
}

void ContentAutofillDriver::ExtractLabeledTextNodeValue(
    const std::u16string& value_regex,
    const std::u16string& label_regex,
    uint32_t number_of_ancestor_levels_to_search,
    base::OnceCallback<void(const std::string& amount)> response_callback) {
  if (!IsActive()) {
    LOG(WARNING) << "Skipped Autofill message for inactive frame";
    std::move(response_callback).Run(std::string());
    return;
  }
  content::RenderFrameHost* main_rfh = render_frame_host_->GetMainFrame();
  if (auto* main_driver = GetForRenderFrameHost(main_rfh)) {
    main_driver->GetAutofillAgent()->ExtractLabeledTextNodeValue(
        value_regex, label_regex, number_of_ancestor_levels_to_search,
        std::move(response_callback));
  }
}

// static
ContentAutofillDriver* ContentAutofillDriver::GetForRenderFrameHost(
    content::RenderFrameHost* render_frame_host) {
  ContentAutofillDriverFactory* factory =
      ContentAutofillDriverFactory::FromWebContents(
          content::WebContents::FromRenderFrameHost(render_frame_host));
  return factory
             ? factory->DriverForFrame(render_frame_host,
                                       base::PassKey<ContentAutofillDriver>())
             : nullptr;
}

void ContentAutofillDriver::BindPendingReceiver(
    mojo::PendingAssociatedReceiver<mojom::AutofillDriver> pending_receiver,
    base::PassKey<ContentAutofillDriverFactory> pass_key) {
  receiver_.Bind(std::move(pending_receiver));
}

LocalFrameToken ContentAutofillDriver::GetFrameToken() const {
  return LocalFrameToken(render_frame_host_->GetFrameToken().value());
}

ContentAutofillDriver* ContentAutofillDriver::GetParent() {
  content::RenderFrameHost* parent_rfh = render_frame_host_->GetParent();
  if (!parent_rfh) {
    return nullptr;
  }
  return GetForRenderFrameHost(parent_rfh);
}

bool ContentAutofillDriver::IsActive() const {
  return render_frame_host_->IsActive();
}

bool ContentAutofillDriver::IsEmbedded() const {
  return render_frame_host_->GetMainFrame() !=
         render_frame_host_->GetOutermostMainFrameOrEmbedder();
}

ContentAutofillClient& ContentAutofillDriver::GetAutofillClient() {
  return owner_->client();
}

AutofillManager& ContentAutofillDriver::GetAutofillManager() {
  return *autofill_manager_;
}

std::optional<LocalFrameToken> ContentAutofillDriver::Resolve(
    FrameToken query) {
  content::RenderProcessHost* rph = render_frame_host_->GetProcess();
  content::RenderFrameHost* rfh = std::visit(
      absl::Overload{[&](const LocalFrameToken& token) {
                       return content::RenderFrameHost::FromFrameToken(
                           content::GlobalRenderFrameHostToken(
                               rph->GetDeprecatedID(),
                               blink::LocalFrameToken(token.value())));
                     },
                     [&](const RemoteFrameToken& token) {
                       return content::RenderFrameHost::FromPlaceholderToken(
                           rph->GetDeprecatedID(),
                           blink::RemoteFrameToken(token.value()));
                     }},
      query);
  if (!rfh || rfh->GetParent() != &*render_frame_host_) {
    return std::nullopt;
  }
  return LocalFrameToken(rfh->GetFrameToken().value());
}

ukm::SourceId ContentAutofillDriver::GetPageUkmSourceId() const {
  CHECK(!render_frame_host_->IsInLifecycleState(
          content::RenderFrameHost::LifecycleState::kPrerendering));
  return render_frame_host_->GetPageUkmSourceId();
}

bool ContentAutofillDriver::IsPolicyControlledFeatureAutofillEnabled() const {
  const url::Origin& origin = render_frame_host_->GetLastCommittedOrigin();
  const url::Origin& main_origin =
      render_frame_host_->GetMainFrame()->GetLastCommittedOrigin();
  // We intentionally force-enable the policy on the main frame (and descendant
  // frames that share the main frame's origin).
  return origin.IsSameOriginWith(main_origin) ||
         render_frame_host_->IsFeatureEnabled(
             network::mojom::PermissionsPolicyFeature::kAutofill);
}

bool ContentAutofillDriver::IsPolicyControlledFeatureManualTextEnabled() const {
  return render_frame_host_->IsFeatureEnabled(
      network::mojom::PermissionsPolicyFeature::kManualText);
}

bool ContentAutofillDriver::CanShowAutofillUi() const {
  // Don't show AutofillUi for inactive RenderFrameHost. Here it is safe to
  // ignore the calls from inactive RFH as the renderer is not expecting a reply
  // and it doesn't lead to browser-renderer consistency issues.
  return render_frame_host_->IsActive();
}

std::optional<net::IsolationInfo> ContentAutofillDriver::GetIsolationInfo() {
  return render_frame_host_->GetIsolationInfoForSubresources();
}

base::flat_set<FieldGlobalId> ContentAutofillDriver::ApplyFormAction(
    mojom::FormActionType action_type,
    mojom::ActionPersistence action_persistence,
    base::span<const FormFieldData> data,
    const FillId& fill_id,
    bool supports_refill,
    const url::Origin& triggered_origin,
    const absl::flat_hash_map<FieldGlobalId, FieldType>& field_type_map) {
  // If this driver is active, then its main frame is identical to the main
  // frame at the time the form was received from a renderer and their origins
  // are the same.
  url::Origin main_origin = [&] {
    if (auto* main_rfh = render_frame_host_->GetMainFrame();
        main_rfh->IsInPrimaryMainFrame()) {
      return main_rfh->GetLastCommittedOrigin();
    } else {
      return url::Origin();
    }
  }();
  return RouteToAgent(router(), &AutofillDriverRouter::ApplyFormAction,
                      &mojom::AutofillAgent::ApplyFieldsAction, action_type,
                      action_persistence, data, fill_id, supports_refill,
                      main_origin, triggered_origin, field_type_map);
}

void ContentAutofillDriver::ApplyFieldAction(
    mojom::FieldActionType action_type,
    mojom::ActionPersistence action_persistence,
    const FieldGlobalId& field_id,
    const std::u16string& value) {
  RouteToAgent(router(), &AutofillDriverRouter::ApplyFieldAction,
               &mojom::AutofillAgent::ApplyFieldAction, action_type,
               action_persistence, field_id, value);
}

void ContentAutofillDriver::ExtractFormWithField(
    FieldGlobalId field_id,
    BrowserFormHandler final_handler) {
  if (!IsActive()) {
    LOG(WARNING) << "Skipped Autofill message for inactive frame";
    std::move(final_handler).Run(nullptr, std::nullopt);
    return;
  }
  router().ExtractFormWithField(
      [](autofill::AutofillDriver& request_target, FieldRendererId field_id,
         AutofillDriverRouter::RendererFormHandler route_response) {
        auto& source = static_cast<ContentAutofillDriver&>(request_target);
        source.GetAutofillAgent()->ExtractFormWithField(
            field_id, Lift(source, std::move(route_response)));
      },
      field_id, WithNewVersion(std::move(final_handler)));
}

void ContentAutofillDriver::ExposeDomNodeIdsInAllFrames() {
  RouteToAgent(router(), &AutofillDriverRouter::ExposeDomNodeIdsInAllFrames,
               &mojom::AutofillAgent::ExposeDomNodeIds);
}

void ContentAutofillDriver::SendTypePredictionsToRenderer(
    const FormStructure& form) {
  CHECK(base::FeatureList::IsEnabled(
      features::debug::kAutofillShowTypePredictions));
  RouteToAgent(router(), &AutofillDriverRouter::SendTypePredictionsToRenderer,
               &mojom::AutofillAgent::FieldTypePredictionsAvailable,
               form.GetFieldTypePredictions());
}

void ContentAutofillDriver::ScrollFieldIntoView(FieldGlobalId field_id) {
  RouteToAgent(router(), &AutofillDriverRouter::ScrollFieldIntoView,
               &mojom::AutofillAgent::ScrollFieldIntoView, field_id);
}

void ContentAutofillDriver::RendererShouldAcceptDataListSuggestion(
    const FieldGlobalId& field_id,
    const std::u16string& value) {
  RouteToAgent(
      router(), &AutofillDriverRouter::RendererShouldAcceptDataListSuggestion,
      &mojom::AutofillAgent::AcceptDataListSuggestion, field_id, value);
}

void ContentAutofillDriver::RendererShouldClearPreviewedForm() {
  RouteToAgent(router(),
               &AutofillDriverRouter::RendererShouldClearPreviewedForm,
               &mojom::AutofillAgent::ClearPreviewedForm);
}

void ContentAutofillDriver::RendererShouldTriggerSuggestions(
    const FieldGlobalId& field_id,
    AutofillSuggestionTriggerSource trigger_source) {
  RouteToAgent(
      router(), &AutofillDriverRouter::RendererShouldTriggerSuggestions,
      &mojom::AutofillAgent::TriggerSuggestions, field_id, trigger_source);
}

void ContentAutofillDriver::RendererShouldSetSuggestionAvailability(
    const FieldGlobalId& field_id,
    mojom::AutofillSuggestionAvailability suggestion_availability) {
  RouteToAgent(router(),
               &AutofillDriverRouter::RendererShouldSetSuggestionAvailability,
               &mojom::AutofillAgent::SetSuggestionAvailability, field_id,
               suggestion_availability);
}

void ContentAutofillDriver::GetNonceForEmailVerification(
    FieldGlobalId email_field_id,
    base::OnceCallback<void(const std::optional<std::string>&)> callback) {
  RouteToAgent(router(), &AutofillDriverRouter::GetNonceForEmailVerification,
               &mojom::AutofillAgent::GetNonceForEmailVerification,
               email_field_id, std::move(callback));
}

void ContentAutofillDriver::SendEmailVerificationToken(
    FieldGlobalId email_field_id,
    const std::string& email,
    const std::string& token) {
  RouteToAgent(router(), &AutofillDriverRouter::SendEmailVerificationToken,
               &mojom::AutofillAgent::SendEmailVerificationToken,
               email_field_id, email, token);
}

void ContentAutofillDriver::UpdateEmailVerificationState(
    const FieldGlobalId& email_field_id,
    mojom::EmailVerificationState state) {
  RouteToAgent(router(), &AutofillDriverRouter::UpdateEmailVerificationState,
               &mojom::AutofillAgent::UpdateEmailVerificationState,
               email_field_id, state);
}

void ContentAutofillDriver::FormsSeen(
    const std::vector<FormData>& updated_forms,
    const std::vector<FormRendererId>& removed_forms) {
  RouteToManager(*this, router(), &AutofillDriverRouter::FormsSeen,
                 &AutofillManager::OnFormsSeen, updated_forms, removed_forms);
}

void ContentAutofillDriver::FormSubmitted(
    const FormData& form,
    mojom::SubmissionSource submission_source) {
  RouteToManager(*this, router(), &AutofillDriverRouter::FormSubmitted,
                 &AutofillManager::OnFormSubmitted, form, submission_source);
}

void ContentAutofillDriver::CaretMovedInFormField(
    const FormData& form,
    FieldRendererId field_id,
    const gfx::Rect& caret_bounds) {
  RouteToManager(*this, router(), &AutofillDriverRouter::CaretMovedInFormField,
                 &AutofillManager::OnCaretMovedInFormField, form, field_id,
                 caret_bounds);
}

void ContentAutofillDriver::TextFieldValueChanged(const FormData& form,
                                                  FieldRendererId field_id,
                                                  base::TimeTicks timestamp) {
  RouteToManager(*this, router(), &AutofillDriverRouter::TextFieldValueChanged,
                 &AutofillManager::OnTextFieldValueChanged, form, field_id,
                 timestamp);
}

void ContentAutofillDriver::TextFieldDidScroll(const FormData& form,
                                               FieldRendererId field_id) {
  RouteToManager(*this, router(), &AutofillDriverRouter::TextFieldDidScroll,
                 &AutofillManager::OnTextFieldDidScroll, form, field_id);
}

void ContentAutofillDriver::SelectControlSelectionChanged(
    const FormData& form,
    FieldRendererId field_id) {
  RouteToManager(
      *this, router(), &AutofillDriverRouter::SelectControlSelectionChanged,
      &AutofillManager::OnSelectControlSelectionChanged, form, field_id);
}

void ContentAutofillDriver::AskForValuesToFill(
    const FormData& form,
    FieldRendererId field_id,
    const gfx::Rect& caret_bounds,
    AutofillSuggestionTriggerSource trigger_source,
    const std::optional<PasswordSuggestionRequest>& password_request) {
  RouteToManager(*this, router(), &AutofillDriverRouter::AskForValuesToFill,
                 &AutofillManager::OnAskForValuesToFill, form, field_id,
                 caret_bounds, trigger_source, password_request);
}

void ContentAutofillDriver::HidePopup() {
  RouteToManager(*this, router(), &AutofillDriverRouter::HidePopup,
                 &AutofillManager::OnHidePopup);
}

void ContentAutofillDriver::FocusOnNonFormField() {
  RouteToManager(*this, router(), &AutofillDriverRouter::FocusOnNonFormField,
                 &AutofillManager::OnFocusOnNonFormField);
}

void ContentAutofillDriver::SuppressAutomaticRefills(const FillId& fill_id) {
  RouteToManager(*this, router(),
                 &AutofillDriverRouter::SuppressAutomaticRefills,
                 &AutofillManager::SuppressAutomaticRefills, fill_id);
}

void ContentAutofillDriver::RequestRefill(const FillId& fill_id) {
  RouteToManager(*this, router(), &AutofillDriverRouter::RequestRefill,
                 &AutofillManager::RequestRefill, fill_id);
}

void ContentAutofillDriver::FocusOnFormField(const FormData& form,
                                             FieldRendererId field_id) {
  auto focus_no_longer_on_form = [](autofill::AutofillDriver& target) {
    target.GetAutofillManager().OnFocusOnNonFormField(
        /*pass_key=*/{});
  };
  RouteToManager(
      *this, router(), &AutofillDriverRouter::FocusOnFormField,
      &AutofillManager::OnFocusOnFormField, form, field_id,
      AutofillDriverRouter::RoutedCallback<>(focus_no_longer_on_form));
}

void ContentAutofillDriver::DidAutofillForm(const FormData& form) {
  RouteToManager(*this, router(), &AutofillDriverRouter::DidAutofillForm,
                 &AutofillManager::OnDidAutofillForm, form);
}

void ContentAutofillDriver::DidEndTextFieldEditing() {
  RouteToManager(*this, router(), &AutofillDriverRouter::DidEndTextFieldEditing,
                 &AutofillManager::OnDidEndTextFieldEditing);
}

void ContentAutofillDriver::SelectFieldOptionsDidChange(
    const FormData& form,
    FieldRendererId field_id) {
  RouteToManager(
      *this, router(), &AutofillDriverRouter::SelectFieldOptionsDidChange,
      &AutofillManager::OnSelectFieldOptionsDidChange, form, field_id);
}

void ContentAutofillDriver::JavaScriptChangedAutofilledValue(
    const FormData& form,
    FieldRendererId field_id,
    const std::u16string& old_value) {
  RouteToManager(*this, router(),
                 &AutofillDriverRouter::JavaScriptChangedAutofilledValue,
                 &AutofillManager::OnJavaScriptChangedAutofilledValue, form,
                 field_id, old_value);
}

void ContentAutofillDriver::FormWithEmailVerificationTokenSubmitted(
    const FormData& form,
    FieldRendererId email_field_id) {
  RouteToManager(*this, router(),
                 &AutofillDriverRouter::FormWithEmailVerificationTokenSubmitted,
                 &AutofillManager::OnFormWithEmailVerificationTokenSubmitted,
                 form, email_field_id);
}

void ContentAutofillDriver::DidDetectJavaScriptAutofill(
    const FormData& form,
    FieldRendererId trigger_field_id,
    std::vector<mojom::JavaScriptFieldModificationPtr> field_modifications) {
  RouteToManager(*this, router(),
                 &AutofillDriverRouter::DidDetectJavaScriptAutofill,
                 &AutofillManager::OnDidDetectJavaScriptAutofill, form,
                 trigger_field_id, field_modifications);
}

const mojo::AssociatedRemote<mojom::AutofillAgent>&
ContentAutofillDriver::GetAutofillAgent() {
  // Here is a lazy binding, and will not reconnect after connection error.
  if (!autofill_agent_) {
    render_frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(
        &autofill_agent_);
  }
  return autofill_agent_;
}

bool ContentAutofillDriver::IsSafeToFill(
    const FormFieldData& field,
    FieldType filled_type,
    const url::Origin& main_origin,
    const url::Origin& trigger_origin) const {
  return router().IsSafeToFill(field, filled_type, main_origin, trigger_origin);
}

void ContentAutofillDriver::LiftForTest(FormData& form) {
  form = Lift(*this, form);
}

}  // namespace autofill
