// Copyright 2021 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/core/browser/foundations/autofill_driver_router.h"

#include <stddef.h>

#include <algorithm>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <ranges>
#include <string>
#include <utility>
#include <vector>

#include "base/check.h"
#include "base/check_deref.h"
#include "base/check_op.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/containers/to_vector.h"
#include "base/debug/crash_logging.h"
#include "base/functional/bind.h"
#include "base/functional/function_ref.h"
#include "base/memory/raw_ref.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "build/buildflag.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/foundations/autofill_driver.h"
#include "components/autofill/core/browser/foundations/form_forest.h"
#include "components/autofill/core/common/aliases.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data_predictions.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.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 "third_party/abseil-cpp/absl/container/flat_hash_map.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
#include "ui/gfx/geometry/rect.h"
#include "url/origin.h"

namespace autofill {

namespace {

// Calls |fun| for all drivers in |form_forest|.
void ForEachFrame(internal::FormForest& form_forest,
                  base::FunctionRef<void(AutofillDriver&)> fun) {
  for (const std::unique_ptr<internal::FormForest::FrameData>& some_frame :
       form_forest.frame_datas()) {
    if (some_frame->driver) {
      std::invoke(fun, *some_frame->driver);
    }
  }
}

}  // namespace

AutofillDriverRouter::AutofillDriverRouter() = default;
AutofillDriverRouter::~AutofillDriverRouter() {
  base::UmaHistogramCounts1000("Autofill.NumberOfFramesPerFormForest",
                               max_frame_datas_);
}

AutofillDriver* AutofillDriverRouter::DriverOfFrame(
    LocalFrameToken frame) const {
  const auto& frames = form_forest_.frame_datas();
  max_frame_datas_ = std::max(max_frame_datas_, frames.size());
  auto it = frames.find(frame);
  return it != frames.end() ? static_cast<AutofillDriver*>((*it)->driver.get())
                            : nullptr;
}

void AutofillDriverRouter::UnregisterDriver(AutofillDriver& driver,
                                            bool driver_is_dying) {
  form_forest_.EraseFormsOfFrame(driver.GetFrameToken(),
                                 /*keep_frame=*/!driver_is_dying);
}

bool AutofillDriverRouter::IsSafeToFill(
    const FormFieldData& field,
    FieldType filled_type,
    const url::Origin& main_origin,
    const url::Origin& trigger_origin) const {
  // Non-sensitive values may be filled into fields that belong to the
  // main frame's origin. This is independent of the origin of the
  // field that triggered the autofill.
  const bool is_sensitive_field_type = [filled_type] {
    switch (filled_type) {
      case CREDIT_CARD_TYPE:
      case CREDIT_CARD_NAME_FULL:
      case CREDIT_CARD_NAME_FIRST:
      case CREDIT_CARD_NAME_LAST:
      case CREDIT_CARD_EXP_MONTH:
      case CREDIT_CARD_EXP_2_DIGIT_YEAR:
      case CREDIT_CARD_EXP_4_DIGIT_YEAR:
      case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
      case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
        return false;
      default:
        return true;
    }
  }();

  // Fields whose document enables the policy-controlled feature "autofill"
  // may be safe to fill.
  const bool is_policy_controlled_autofill_enabled = [&] {
    const AutofillDriver* target = DriverOfFrame(field.host_frame());
    return target && target->IsPolicyControlledFeatureAutofillEnabled();
  }();

  return field.origin() == trigger_origin ||
         (field.origin() == main_origin && !is_sensitive_field_type &&
          is_policy_controlled_autofill_enabled) ||
         (trigger_origin == main_origin &&
          is_policy_controlled_autofill_enabled);
}

// Routing of events called by the renderer:

// Calls TriggerFormExtraction() on all AutofillDrivers in |form_forest_| as
// well as their ancestor AutofillDrivers.
//
// An ancestor might not be contained in the form tree known to FormForest: if
// the ancestor contained only invisible iframe(s) and no interesting fields, it
// would not be sent to the browser. In the meantime, these frames may have
// become visible. Therefore, we also call TriggerFormExtraction() in all
// ancestors.
//
// The typical use case is that some frame triggers form extractions on its own
// initiative and triggers an event. Then AutofillDriverRouter's event handler
// tells the other frames to form extraction, too, using
// TriggerFormExtractionExcept(source).
void AutofillDriverRouter::TriggerFormExtractionExcept(
    AutofillDriver& exception) {
#if BUILDFLAG(IS_IOS)
  if (!base::FeatureList::IsEnabled(
          features::kAutofillAcrossIframesIosTriggerFormExtraction)) {
    return;
  }
#endif
  // TODO(crbug.com/384874225): Cleanup that instrumentation once the feature is
  // launched on iOS.
  SCOPED_UMA_HISTOGRAM_TIMER_MICROS(
      "Autofill.DriverRouter.TriggerFormExtractionExcept.Duration");
  size_t frame_count = form_forest_.frame_datas().size();
  base::UmaHistogramCounts10000(
      "Autofill.DriverRouter.TriggerFormExtractionExcept.FrameCount",
      frame_count);
  SCOPED_CRASH_KEY_NUMBER("Autofill", "num_frame_extract_total", frame_count);
  base::flat_set<AutofillDriver*> already_triggered;
  ForEachFrame(form_forest_, [&](AutofillDriver& driver_ref) {
    AutofillDriver* driver = &driver_ref;
    do {
      SCOPED_CRASH_KEY_NUMBER("Autofill", "num_frame_extract_so_far",
                              already_triggered.size());
      if (driver == &exception) {
        continue;
      }
      if (!driver->IsActive()) {
        // The `form_forest_` may contain inactive frames because it retains
        // BFcached frames.
        continue;
      }
      if (!already_triggered.insert(driver).second) {
        // An earlier invocation of this lambda has executed the rest of this
        // loop's body for `driver` and hence also for all its ancestors.
        break;
      }
      driver->TriggerFormExtractionInDriverFrame(/*pass_key=*/{});
    } while ((driver = driver->GetParent()) != nullptr);
  });
}

void AutofillDriverRouter::FormsSeen(
    RoutedCallback<std::vector<FormData>, std::vector<FormGlobalId>> callback,
    AutofillDriver& source,
    std::vector<FormData> renderer_forms,
    std::vector<FormGlobalId> removed_forms) {
  base::flat_set<FormGlobalId> forms_with_removed_fields =
      form_forest_.EraseForms(removed_forms);

  std::vector<FormGlobalId> renderer_form_ids =
      base::ToVector(renderer_forms, &FormData::global_id);

  for (FormData& form : renderer_forms) {
    form_forest_.UpdateTreeOfRendererForm(std::move(form), source);
  }

  // Collects the browser forms of the |renderer_forms_ids|. If all forms in
  // |renderer_forms_ids| are root forms, each of them has a different browser
  // form. Otherwise, all forms in |renderer_forms_ids| are non-root forms in
  // the same tree, and |browser_forms| will contain the flattened root of this
  // tree.
  std::vector<FormData> browser_forms;
  browser_forms.reserve(renderer_form_ids.size());
  absl::flat_hash_set<FormGlobalId> browser_form_ids;
  for (FormGlobalId renderer_form_id : renderer_form_ids) {
    const FormData& browser_form =
        form_forest_.GetBrowserForm(renderer_form_id);
    if (browser_form_ids.insert(browser_form.global_id()).second) {
      browser_forms.push_back(browser_form);
    }
  }
  DCHECK(browser_forms.size() == renderer_form_ids.size() ||
         browser_forms.size() == 1);

  for (const FormGlobalId form_id : forms_with_removed_fields) {
    const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
    if (browser_form_ids.insert(browser_form.global_id()).second) {
      browser_forms.push_back(browser_form);
    }
  }

  // Send the browser forms to the individual frames.
  if (!browser_forms.empty()) {
    LocalFrameToken frame = browser_forms.front().host_frame();
    DCHECK(std::ranges::all_of(browser_forms, [frame](const FormData& f) {
      return f.host_frame() == frame;
    }));
    AutofillDriver* target = DriverOfFrame(frame);
    callback(CHECK_DEREF(target), std::move(browser_forms),
             std::move(removed_forms));
  } else if (!removed_forms.empty()) {
    callback(source, {}, std::move(removed_forms));
  }
}

void AutofillDriverRouter::FormSubmitted(
    RoutedCallback<const FormData&, mojom::SubmissionSource> callback,
    AutofillDriver& source,
    FormData form,
    mojom::SubmissionSource submission_source) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, submission_source);
}

void AutofillDriverRouter::CaretMovedInFormField(
    RoutedCallback<const FormData&, const FieldGlobalId&, const gfx::Rect&>
        callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id,
    const gfx::Rect& caret_bounds) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id, caret_bounds);
}

void AutofillDriverRouter::TextFieldValueChanged(
    RoutedCallback<const FormData&, const FieldGlobalId&, base::TimeTicks>
        callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id,
    base::TimeTicks timestamp) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id, timestamp);
}

void AutofillDriverRouter::TextFieldDidScroll(
    RoutedCallback<const FormData&, const FieldGlobalId&> callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id);
}

void AutofillDriverRouter::SelectControlSelectionChanged(
    RoutedCallback<const FormData&, const FieldGlobalId&> callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id);
}

void AutofillDriverRouter::AskForValuesToFill(
    RoutedCallback<const FormData&,
                   const FieldGlobalId&,
                   const gfx::Rect&,
                   AutofillSuggestionTriggerSource,
                   std::optional<PasswordSuggestionRequest>> callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id,
    const gfx::Rect& caret_bounds,
    AutofillSuggestionTriggerSource trigger_source,
    std::optional<PasswordSuggestionRequest> password_request) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id, caret_bounds,
           trigger_source, std::move(password_request));
}

void AutofillDriverRouter::HidePopup(RoutedCallback<> callback,
                                     AutofillDriver& source) {
  // We don't know which AutofillManager is currently displaying the popup.
  // Since the the general approach of popup hiding in Autofill seems to be
  // "better safe than sorry", broadcasting this event is fine.
  // TODO(crbug.com/40284890): This event should go away when the popup-hiding
  // mechanism has been cleaned up.
  ForEachFrame(form_forest_, callback);
}

void AutofillDriverRouter::SuppressAutomaticRefills(
    RoutedCallback<const FillId&> callback,
    AutofillDriver& source,
    const FillId& fill_id) {
  // We don't know which AutofillManager caused the fill with `fill_id`.
  ForEachFrame(form_forest_,
               [&](AutofillDriver& driver) { callback(driver, fill_id); });
}

void AutofillDriverRouter::RequestRefill(RoutedCallback<const FillId&> callback,
                                         AutofillDriver& source,
                                         const FillId& fill_id) {
  // We don't know which AutofillManager caused the fill with `fill_id`.
  ForEachFrame(form_forest_,
               [&](AutofillDriver& driver) { callback(driver, fill_id); });
}

void AutofillDriverRouter::FocusOnNonFormField(RoutedCallback<> callback,
                                               AutofillDriver& source) {
  // Suppresses FocusOnNonFormField() if the focus has already moved to a
  // different frame.
  if (focused_frame_ != source.GetFrameToken()) {
    return;
  }

  // Prevents FocusOnFormField() from calling FocusOnNonFormField().
  focus_no_longer_on_form_has_fired_ = true;

  TriggerFormExtractionExcept(source);

  // The last-focused form is not known at this time. Even if
  // FocusOnNonFormField() had a FormGlobalId parameter, we couldn't call
  // `form_forest_.GetBrowserForm()` because this is admissible only after a
  // `form_forest_.UpdateTreeOfRendererForm()` for the same form.
  //
  // Therefore, we simply broadcast the event.
  ForEachFrame(form_forest_, callback);
}

void AutofillDriverRouter::FocusOnFormField(
    RoutedCallback<const FormData&, const FieldGlobalId&> callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id,
    RoutedCallback<> focus_no_longer_on_form) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  // Calls FocusOnNonFormField() if the focus has already moved from a
  // different frame and FocusOnNonFormField() hasn't been called yet.
  if (focused_frame_ != source.GetFrameToken() &&
      !focus_no_longer_on_form_has_fired_) {
    ForEachFrame(form_forest_, focus_no_longer_on_form);
  }

  // Suppresses late FocusOnNonFormField().
  focused_frame_ = source.GetFrameToken();
  focus_no_longer_on_form_has_fired_ = false;

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id);
}

void AutofillDriverRouter::DidAutofillForm(
    RoutedCallback<const FormData&> callback,
    AutofillDriver& source,
    FormData form) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form);
}

void AutofillDriverRouter::DidEndTextFieldEditing(RoutedCallback<> callback,
                                                  AutofillDriver& source) {
  TriggerFormExtractionExcept(source);

  // The last-focused form is not known at this time. Even if
  // DidEndTextFieldEditing() had a FormGlobalId parameter, we couldn't call
  // `form_forest_.GetBrowserForm()` because this is admissible only after a
  // `form_forest_.UpdateTreeOfRendererForm()` for the same form.
  //
  // Therefore, we simply broadcast the event.
  ForEachFrame(form_forest_, callback);
}

void AutofillDriverRouter::FormWithEmailVerificationTokenSubmitted(
    RoutedCallback<const FormData&, const FieldGlobalId&> callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& email_field_id) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), email_field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, email_field_id);
}

void AutofillDriverRouter::DidDetectJavaScriptAutofill(
    RoutedCallback<const FormData&,
                   const FieldGlobalId&,
                   const std::vector<JavaScriptFieldModification>&> callback,
    AutofillDriver& source,
    FormData form,
    FieldGlobalId trigger_field_id,
    std::vector<JavaScriptFieldModification> field_modifications) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), trigger_field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, trigger_field_id,
           field_modifications);
}

void AutofillDriverRouter::SelectFieldOptionsDidChange(
    RoutedCallback<const FormData&, const FieldGlobalId&> callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id);
}

void AutofillDriverRouter::JavaScriptChangedAutofilledValue(
    RoutedCallback<const FormData&, const FieldGlobalId&, const std::u16string&>
        callback,
    AutofillDriver& source,
    FormData form,
    const FieldGlobalId& field_id,
    const std::u16string& old_value) {
  FormGlobalId form_id = form.global_id();
  form_forest_.UpdateTreeOfRendererForm(std::move(form), source);

  TriggerFormExtractionExcept(source);

  const FormData& browser_form = form_forest_.GetBrowserForm(form_id);
  if (!std::ranges::contains(browser_form.fields(), field_id,
                             &FormFieldData::global_id)) {
    // To avoid very large flattened forms, UpdateTreeOfRendererForm() may have
    // cut the tree into two and, as a result, may have lost some fields. We
    // drop such events.
    // See `kMaxVisits` in FormForest::UpdateTreeOfRendererForm() for details.
    return;
  }
  auto* target = DriverOfFrame(browser_form.host_frame());
  callback(CHECK_DEREF(target), browser_form, field_id, old_value);
}

// Routing of events triggered by the browser.
//
// Below, `DriverOfFrame() == nullptr` does not necessarily indicate a bug and
// is therefore not NOTREACHED().
// The reason is that browser forms may be outdated and hence refer to frames
// that do not exist anymore.

base::flat_set<FieldGlobalId> AutofillDriverRouter::ApplyFormAction(
    RoutedCallback<mojom::FormActionType,
                   mojom::ActionPersistence,
                   const std::vector<FormFieldData::FillData>&,
                   const FillId&,
                   bool> callback,
    mojom::FormActionType action_type,
    mojom::ActionPersistence action_persistence,
    base::span<const FormFieldData> data,
    const FillId& fill_id,
    bool supports_refill,
    const url::Origin& main_origin,
    const url::Origin& triggered_origin,
    const absl::flat_hash_map<FieldGlobalId, FieldType>& field_type_map) {
  // Since Undo only affects fields that were already filled, and only sets
  // values of fields to something that already existed in it prior to the
  // filling, it is okay to bypass the filling security checks and hence passing
  // `TrustAllOrigins()`.
  std::vector<FormData> renderer_forms =
      form_forest_.GetRendererFormsOfBrowserFields(data);
  // Collect the fields per frame and emit a single fill operation per frame,
  // even if multiple renderer forms belong to the same iframe due to
  // flattening.
  absl::flat_hash_map<AutofillDriver*, std::vector<FormFieldData::FillData>>
      fields_of_driver;

  std::vector<FieldGlobalId> safe_fields;
  safe_fields.reserve(data.size());
  for (FormData& renderer_form : renderer_forms) {
    if (auto* target = DriverOfFrame(renderer_form.host_frame())) {
      for (const FormFieldData& field : renderer_form.fields()) {
        // Skip unsafe fields so that they do not get filled in the renderer.
        if (action_type == mojom::FormActionType::kUndo ||
            IsSafeToFill(field, field_type_map.at(field.global_id()),
                         main_origin, triggered_origin)) {
          fields_of_driver[target].emplace_back(field);
          safe_fields.push_back(field.global_id());
        }
      }
    }
  }
  for (const auto& [target, fields] : fields_of_driver) {
    CHECK(!fields.empty());
    callback(CHECK_DEREF(target), action_type, action_persistence, fields,
             fill_id, supports_refill);
  }
  return safe_fields;
}

void AutofillDriverRouter::ApplyFieldAction(
    RoutedCallback<mojom::FieldActionType,
                   mojom::ActionPersistence,
                   FieldRendererId,
                   const std::u16string&> callback,
    mojom::FieldActionType action_type,
    mojom::ActionPersistence action_persistence,
    const FieldGlobalId& field_id,
    const std::u16string& value) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, action_type, action_persistence, field_id.renderer_id,
             value);
  }
}

void AutofillDriverRouter::ExtractFormWithField(
    RoutedCallback<FieldRendererId, RendererFormHandler> callback,
    FieldGlobalId field_id,
    BrowserFormHandler browser_form_handler) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    // `renderer_form_handler` converts a received renderer `form` into a
    // browser form and passes that to `browser_form_handler`.
    // Binding `*this` and `*target` is safe because
    // - `*this` outlives `*target`, and
    // - `*target` outlives all pending callbacks of `*target`'s AutofillAgent.
    auto renderer_form_handler = base::BindOnce(
        [](raw_ref<AutofillDriverRouter> self,
           raw_ref<AutofillDriver> response_source,
           BrowserFormHandler browser_form_handler,
           const std::optional<FormData>& form) {
          if (!form) {
            std::move(browser_form_handler).Run(nullptr, std::nullopt);
            return;
          }
          self->form_forest_.UpdateTreeOfRendererForm(*form, *response_source);
          const FormData& browser_form =
              self->form_forest_.GetBrowserForm(form->global_id());
          auto* response_target =
              self->DriverOfFrame(browser_form.host_frame());
          std::move(browser_form_handler).Run(response_target, browser_form);
        },
        raw_ref(*this), raw_ref(*target), std::move(browser_form_handler));
    callback(*target, field_id.renderer_id, std::move(renderer_form_handler));
  } else {
    std::move(browser_form_handler).Run(nullptr, std::nullopt);
  }
}

void AutofillDriverRouter::ObserveFieldVisibility(
    RoutedCallback<FieldRendererId,
                   mojo::PendingRemote<mojom::AutofillVisibilityObserver>>
        callback,
    const FieldGlobalId& field_id,
    mojo::PendingRemote<mojom::AutofillVisibilityObserver> observer) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, field_id.renderer_id, std::move(observer));
  }
}

void AutofillDriverRouter::SendTypePredictionsToRenderer(
    RoutedCallback<const std::vector<FormDataPredictions>&> callback,
    const FormDataPredictions& browser_fdp) {
  // Splits the FrameDataPredictions according to the FormData's renderer forms,
  // and groups these FormDataPredictions by the renderer form's frame. We uso
  // "fdp" as abbreviation of FormDataPredictions.
  std::map<LocalFrameToken, std::vector<FormDataPredictions>> renderer_fdps;

  // Builds an index of the field predictions by the field's global ID.
  std::map<FieldGlobalId, FormFieldDataPredictions> field_predictions;
  DCHECK_EQ(browser_fdp.data.fields().size(), browser_fdp.fields.size());
  for (auto [field, field_prediction] :
       std::views::zip(browser_fdp.data.fields(), browser_fdp.fields)) {
    field_predictions.emplace(field.global_id(), field_prediction);
  }

  // Builds the FormDataPredictions of each renderer form and groups them by
  // the renderer form's frame in |renderer_fdps|.
  std::vector<FormData> renderer_forms =
      form_forest_.GetRendererFormsOfBrowserFields(browser_fdp.data.fields());
  for (FormData& renderer_form : renderer_forms) {
    LocalFrameToken frame = renderer_form.host_frame();
    FormDataPredictions renderer_fdp;
    renderer_fdp.data = std::move(renderer_form);
    renderer_fdp.signature = browser_fdp.signature;
    renderer_fdp.alternative_signature = browser_fdp.alternative_signature;
    renderer_fdp.structural_form_signature =
        browser_fdp.structural_form_signature;
    for (const FormFieldData& field : renderer_fdp.data.fields()) {
      renderer_fdp.fields.push_back(
          std::move(field_predictions[field.global_id()]));
    }
    renderer_fdps[frame].push_back(std::move(renderer_fdp));
  }

  // Sends the predictions of the renderer forms to the individual frames.
  for (const auto& p : renderer_fdps) {
    LocalFrameToken frame = p.first;
    const std::vector<FormDataPredictions>& renderer_fdp = p.second;
    if (auto* target = DriverOfFrame(frame)) {
      callback(*target, renderer_fdp);
    }
  }
}

void AutofillDriverRouter::ScrollFieldIntoView(
    RoutedCallback<FieldRendererId> callback,
    FieldGlobalId field_id) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, field_id.renderer_id);
  }
}

void AutofillDriverRouter::RendererShouldAcceptDataListSuggestion(
    RoutedCallback<FieldRendererId, const std::u16string&> callback,
    const FieldGlobalId& field_id,
    const std::u16string& value) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, field_id.renderer_id, value);
  }
}

void AutofillDriverRouter::RendererShouldClearPreviewedForm(
    RoutedCallback<> callback) {
  ForEachFrame(form_forest_, callback);
}

void AutofillDriverRouter::RendererShouldTriggerSuggestions(
    RoutedCallback<FieldRendererId, AutofillSuggestionTriggerSource> callback,
    const FieldGlobalId& field_id,
    AutofillSuggestionTriggerSource trigger_source) {
  if (AutofillDriver* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, field_id.renderer_id, trigger_source);
  }
}

void AutofillDriverRouter::GetNonceForEmailVerification(
    RoutedCallback<FieldRendererId,
                   base::OnceCallback<void(const std::optional<std::string>&)>>
        callback,
    const FieldGlobalId& field_id,
    base::OnceCallback<void(const std::optional<std::string>&)>
        browser_callback) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, field_id.renderer_id, std::move(browser_callback));
  } else {
    std::move(browser_callback).Run(std::nullopt);
  }
}

void AutofillDriverRouter::SendEmailVerificationToken(
    RoutedCallback<FieldRendererId, const std::string&, const std::string&>
        callback,
    const FieldGlobalId& email_field_id,
    const std::string& email,
    const std::string& token) {
  if (auto* target = DriverOfFrame(email_field_id.frame_token)) {
    callback(*target, email_field_id.renderer_id, email, token);
  }
}

void AutofillDriverRouter::UpdateEmailVerificationState(
    RoutedCallback<FieldRendererId, mojom::EmailVerificationState> callback,
    const FieldGlobalId& email_field_id,
    mojom::EmailVerificationState state) {
  if (AutofillDriver* target = DriverOfFrame(email_field_id.frame_token)) {
    callback(*target, email_field_id.renderer_id, state);
  }
}

void AutofillDriverRouter::ExposeDomNodeIdsInAllFrames(
    RoutedCallback<> callback) {
  ForEachFrame(form_forest_, callback);
}

void AutofillDriverRouter::RendererShouldSetSuggestionAvailability(
    RoutedCallback<FieldRendererId, mojom::AutofillSuggestionAvailability>
        callback,
    const FieldGlobalId& field_id,
    mojom::AutofillSuggestionAvailability suggestion_availability) {
  if (auto* target = DriverOfFrame(field_id.frame_token)) {
    callback(*target, field_id.renderer_id, suggestion_availability);
  }
}

std::vector<FormData> AutofillDriverRouter::GetRendererForms(
    const FormData& browser_form) const {
  return form_forest_.GetRendererFormsOfBrowserFields(browser_form.fields());
}

}  // namespace autofill
