[Autofill] Migrate DetermineHeuristicTypes() to FormData

This CL eliminates the last dependencies on FormStructure in
DetermineHeuristicTypes().

Bug: 427787155, 40232021
Change-Id: Ib3cb5f8e4c7d9eaac97315bebd4739232275f58e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6909712
Reviewed-by: Jan Keitel <jkeitel@google.com>
Reviewed-by: Gauthier Ambard <gambard@chromium.org>
Commit-Queue: Christoph Schwering <schwering@google.com>
Cr-Commit-Position: refs/heads/main@{#1510174}
diff --git a/components/autofill/core/browser/autofill_merge_unittest.cc b/components/autofill/core/browser/autofill_merge_unittest.cc
index 97a50444..7832775 100644
--- a/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -101,8 +101,9 @@
     const FormData& form) {
   auto cached_form_structure =
       std::make_unique<FormStructure>(test::WithoutValues(form));
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *cached_form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              cached_form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(cached_form_structure->fields());
   cached_form_structure->RationalizeAndAssignSections(
       GeoIpCountryCode(""), LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding_unittest.cc b/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding_unittest.cc
index 55aa3c6..5942f4b 100644
--- a/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding_unittest.cc
+++ b/components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding_unittest.cc
@@ -1988,8 +1988,9 @@
   // Form structure containing the state on submit.
   FormStructure form_structure(form);
 
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), cached_form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              cached_form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(cached_form_structure.fields());
   cached_form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                      LanguageCode(""), nullptr);
@@ -2448,7 +2449,7 @@
   // Parse the response and update the field type predictions.
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2502,7 +2503,7 @@
 
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2553,7 +2554,7 @@
 
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2606,7 +2607,7 @@
        .url = "http://foo.com"});
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2653,7 +2654,7 @@
        .url = "http://foo.com"});
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2697,7 +2698,7 @@
                            "address-level2")});
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2764,7 +2765,7 @@
                            "address-level2")});
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -2944,7 +2945,7 @@
 
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -3670,8 +3671,9 @@
   FormStructure form_structure(form);
   std::vector<raw_ptr<FormStructure, VectorExperimental>> forms;
   forms.push_back(&form_structure);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *forms.front(), nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              forms.front()->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(forms.front()->fields());
   forms.front()->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -3726,8 +3728,9 @@
 
   FormStructure form_structure(form);
   // Will identify the sections based on the heuristics types.
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -3781,8 +3784,9 @@
   FormStructure form_structure(form);
 
   // Will identify the sections based on the heuristics types.
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -3840,8 +3844,9 @@
   FormStructure form_structure(form);
 
   // Will identify the sections based on the heuristics types.
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -3888,7 +3893,7 @@
 
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -3933,7 +3938,7 @@
 
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
@@ -3978,7 +3983,7 @@
 
   FormStructure form(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+      GeoIpCountryCode(""), LanguageCode(""), form.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form.fields());
   form.RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                     nullptr);
diff --git a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc
index 7ce01ad..3619a5d 100644
--- a/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc
+++ b/components/autofill/core/browser/crowdsourcing/determine_possible_field_types_unittest.cc
@@ -110,8 +110,9 @@
     const FormData& form) {
   auto cached_form_structure =
       std::make_unique<FormStructure>(test::WithoutValues(form));
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *cached_form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              cached_form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(cached_form_structure->fields());
   cached_form_structure->RationalizeAndAssignSections(
       GeoIpCountryCode(""), LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/form_import/form_data_importer_unittest.cc b/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
index 330d992..f628529 100644
--- a/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
@@ -212,8 +212,9 @@
     GeoIpCountryCode geo_country = GeoIpCountryCode("")) {
   auto cached_form_structure =
       std::make_unique<FormStructure>(test::WithoutValues(form));
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      geo_country, LanguageCode(""), *cached_form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(geo_country, LanguageCode(""),
+                              cached_form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(cached_form_structure->fields());
   cached_form_structure->RationalizeAndAssignSections(
       geo_country, LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/form_parsing/determine_heuristic_types.cc b/components/autofill/core/browser/form_parsing/determine_heuristic_types.cc
index 7555771..302adb8 100644
--- a/components/autofill/core/browser/form_parsing/determine_heuristic_types.cc
+++ b/components/autofill/core/browser/form_parsing/determine_heuristic_types.cc
@@ -24,21 +24,18 @@
 
 namespace {
 
-raw_ptr<const FormFieldData> to_form_field_data(
-    const std::unique_ptr<AutofillField>& field) {
-  return field.get();
+raw_ptr<const FormFieldData> ToPointer(const FormFieldData& field) {
+  return &field;
 }
 
 // Classifies each field using the regular expressions. The classifications
 // are returned, but not assigned to the `fields_` yet. Use
 // `AssignBestFieldTypes()` to do so.
-FieldCandidatesMap ParseFieldTypesWithPatterns(const FormStructure& form,
+FieldCandidatesMap ParseFieldTypesWithPatterns(const FormData& form,
                                                ParsingContext& context) {
   FieldCandidatesMap field_type_map;
 
-  auto form_field_data_vector = base::ToVector(
-      form.fields(),
-      [](const auto& f) -> raw_ptr<const FormFieldData> { return f.get(); });
+  auto form_field_data_vector = base::ToVector(form.fields(), &ToPointer);
   if (form.ShouldRunHeuristics()) {
     FormFieldParser::ParseFormFields(context, form_field_data_vector,
                                      field_type_map);
@@ -68,12 +65,12 @@
 HeuristicPredictions::HeuristicPredictions(
     HeuristicSource source,
     const FieldCandidatesMap& field_type_map,
-    base::span<const std::unique_ptr<AutofillField>> fields)
+    base::span<const FormFieldData> fields)
     : source_(source) {
   const HeuristicSource active_source = GetActiveHeuristicSource();
   std::vector<std::pair<FieldGlobalId, FieldType>> field_predictions;
-  for (const auto& field : fields) {
-    auto iter = field_type_map.find(field->global_id());
+  for (const FormFieldData& field : fields) {
+    auto iter = field_type_map.find(field.global_id());
     if (iter == field_type_map.end()) {
       continue;
     }
@@ -84,7 +81,7 @@
           candidates.BestHeuristicTypeReason());
     }
 
-    field_predictions.emplace_back(field->global_id(),
+    field_predictions.emplace_back(field.global_id(),
                                    candidates.BestHeuristicType());
   }
   predictions_ = base::flat_map(std::move(field_predictions));
@@ -133,7 +130,7 @@
 HeuristicPredictions DetermineHeuristicTypes(
     const GeoIpCountryCode& client_country,
     const LanguageCode& current_page_language,
-    FormStructure& form,
+    const FormData& form,
     LogManager* log_manager) {
   SCOPED_UMA_HISTOGRAM_TIMER("Autofill.Timing.DetermineHeuristicTypes");
 
@@ -141,7 +138,7 @@
       base::FeatureList::IsEnabled(features::kAutofillPageLanguageDetection)
           ? current_page_language
           : LanguageCode();
-  ParsingContext context(base::ToVector(form.fields(), &to_form_field_data),
+  ParsingContext context(base::ToVector(form.fields(), &ToPointer),
                          client_country, page_language,
 #if BUILDFLAG(USE_INTERNAL_AUTOFILL_PATTERNS)
                          PatternFile::kDefault,
diff --git a/components/autofill/core/browser/form_parsing/determine_heuristic_types.h b/components/autofill/core/browser/form_parsing/determine_heuristic_types.h
index 0b53020..a2d1e45 100644
--- a/components/autofill/core/browser/form_parsing/determine_heuristic_types.h
+++ b/components/autofill/core/browser/form_parsing/determine_heuristic_types.h
@@ -19,7 +19,6 @@
 namespace autofill {
 
 class AutofillField;
-class FormStructure;
 class LogManager;
 
 // Holds the predictions returned by DetermineHeuristicTypes().
@@ -27,7 +26,7 @@
  public:
   HeuristicPredictions(HeuristicSource source,
                        const FieldCandidatesMap& field_type_map,
-                       base::span<const std::unique_ptr<AutofillField>> fields);
+                       base::span<const FormFieldData> fields);
   HeuristicPredictions(const HeuristicPredictions&);
   HeuristicPredictions(HeuristicPredictions&&);
   HeuristicPredictions& operator=(const HeuristicPredictions&);
@@ -47,7 +46,7 @@
 [[nodiscard]] HeuristicPredictions DetermineHeuristicTypes(
     const GeoIpCountryCode& client_country,
     const LanguageCode& current_page_language,
-    FormStructure& form,
+    const FormData& form,
     LogManager* log_manager);
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index f699d75..6edf7c2 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -80,6 +80,7 @@
 #include "components/autofill/core/common/unique_ids.h"
 #include "components/security_state/core/security_state.h"
 #include "components/version_info/version_info.h"
+#include "third_party/abseil-cpp/absl/functional/overload.h"
 #include "url/origin.h"
 
 namespace autofill {
@@ -138,7 +139,7 @@
 
 // A field is active if it contributes to the form signature and it is are
 // included in queries to the Autofill server.
-bool is_active(const AutofillField& field) {
+bool is_active(const FormFieldData& field) {
   return !IsCheckable(field.check_status());
 }
 
@@ -463,12 +464,14 @@
 }
 
 bool FormStructure::ShouldRunHeuristics() const {
+  // Must be identical to FormData::ShouldRunHeuristics()!
   return AtLeastNumSatisfy(fields(), kMinRequiredFieldsForHeuristics,
                            is_active) &&
          HasAllowedScheme(source_url_);
 }
 
 bool FormStructure::ShouldRunHeuristicsForSingleFields() const {
+  // Must be identical to FormData::ShouldRunHeuristicsForSingleFields()!
   return AtLeastNumSatisfy(fields(), 1, is_active) &&
          HasAllowedScheme(source_url_);
 }
diff --git a/components/autofill/core/browser/form_structure_fuzzer.cc b/components/autofill/core/browser/form_structure_fuzzer.cc
index 0aa2a8e5..05727672 100644
--- a/components/autofill/core/browser/form_structure_fuzzer.cc
+++ b/components/autofill/core/browser/form_structure_fuzzer.cc
@@ -72,7 +72,7 @@
 
   FormStructure form_structure(form_data);
   const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GenerateGeoIpCountryCode(data_provider), LanguageCode(""), form_structure,
+      GenerateGeoIpCountryCode(data_provider), LanguageCode(""), form_data,
       /*log_manager=*/nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(
@@ -85,7 +85,10 @@
   std::ignore = form_structure.IsCompleteCreditCardForm(
       FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm);
   std::ignore = form_structure.ShouldBeParsed();
+  std::ignore = form_structure.ToFormData().ShouldRunHeuristics();
   std::ignore = form_structure.ShouldRunHeuristics();
+  std::ignore =
+      form_structure.ToFormData().ShouldRunHeuristicsForSingleFields();
   std::ignore = form_structure.ShouldRunHeuristicsForSingleFields();
   std::ignore = form_structure.ShouldBeQueried();
   std::ignore = form_structure.ShouldBeUploaded();
diff --git a/components/autofill/core/browser/form_structure_rationalizer_unittest.cc b/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
index 429dd1b..d46df7b 100644
--- a/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
+++ b/components/autofill/core/browser/form_structure_rationalizer_unittest.cc
@@ -133,8 +133,9 @@
 
   // Identifies the sections based on the heuristics types.
   if (run_heuristics) {
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure->ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure->fields());
     form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                  LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index 0407da1..f2d5af1 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -82,26 +82,15 @@
  protected:
   bool FormIsAutofillable(const FormData& form) {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
     return form_structure.IsAutofillable();
   }
 
-  bool FormShouldRunHeuristics(const FormData& form) {
-    return FormStructure(form).ShouldRunHeuristics();
-  }
-
-  bool FormShouldRunHeuristicsForSingleFields(const FormData& form) {
-    return FormStructure(form).ShouldRunHeuristicsForSingleFields();
-  }
-
-  bool FormShouldBeQueried(const FormData& form) {
-    return FormStructure(form).ShouldBeQueried();
-  }
-
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   test::AutofillUnitTestEnvironment autofill_test_environment_;
@@ -460,6 +449,7 @@
   form.set_url(GURL("http://wwww.foo.com/myform"));
   form_structure = std::make_unique<FormStructure>(form);
   EXPECT_TRUE(form_structure->ShouldBeParsed());
+  EXPECT_TRUE(form_structure->ToFormData().ShouldRunHeuristics());
   EXPECT_TRUE(form_structure->ShouldRunHeuristics());
   EXPECT_TRUE(form_structure->ShouldBeQueried());
   EXPECT_TRUE(form_structure->ShouldBeUploaded());
@@ -468,6 +458,7 @@
   form.set_url(GURL("https://wwww.foo.com/myform"));
   form_structure = std::make_unique<FormStructure>(form);
   EXPECT_TRUE(form_structure->ShouldBeParsed());
+  EXPECT_TRUE(form_structure->ToFormData().ShouldRunHeuristics());
   EXPECT_TRUE(form_structure->ShouldRunHeuristics());
   EXPECT_TRUE(form_structure->ShouldBeQueried());
   EXPECT_TRUE(form_structure->ShouldBeUploaded());
@@ -476,6 +467,7 @@
   form.set_url(GURL("chrome://settings"));
   form_structure = std::make_unique<FormStructure>(form);
   EXPECT_FALSE(form_structure->ShouldBeParsed());
+  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldBeQueried());
   EXPECT_FALSE(form_structure->ShouldBeUploaded());
@@ -484,6 +476,7 @@
   form.set_url(GURL("ftp://ftp.foo.com/form.html"));
   form_structure = std::make_unique<FormStructure>(form);
   EXPECT_FALSE(form_structure->ShouldBeParsed());
+  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldBeQueried());
   EXPECT_FALSE(form_structure->ShouldBeUploaded());
@@ -492,6 +485,7 @@
   form.set_url(GURL("blob://blob.foo.com/form.html"));
   form_structure = std::make_unique<FormStructure>(form);
   EXPECT_FALSE(form_structure->ShouldBeParsed());
+  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldBeQueried());
   EXPECT_FALSE(form_structure->ShouldBeUploaded());
@@ -500,6 +494,7 @@
   form.set_url(GURL("about://about.foo.com/form.html"));
   form_structure = std::make_unique<FormStructure>(form);
   EXPECT_FALSE(form_structure->ShouldBeParsed());
+  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldRunHeuristics());
   EXPECT_FALSE(form_structure->ShouldBeQueried());
   EXPECT_FALSE(form_structure->ShouldBeUploaded());
@@ -883,15 +878,17 @@
   field.set_renderer_id(test::MakeFieldRendererId());
   test_api(form).Append(field);
 
-  EXPECT_FALSE(FormShouldRunHeuristics(form));
+  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
+  EXPECT_FALSE(form.ShouldRunHeuristics());
 
-  EXPECT_TRUE(FormShouldBeQueried(form));
+  EXPECT_TRUE(FormStructure(form).ShouldBeQueried());
 
   // Default configuration.
   {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -918,8 +915,9 @@
                            FormControlType::kInputText, "given-name"),
        CreateTestFormField("Last Name", "lastname", "",
                            FormControlType::kInputText, "")});
-  EXPECT_FALSE(FormShouldRunHeuristics(form));
-  EXPECT_TRUE(FormShouldBeQueried(form));
+  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
+  EXPECT_FALSE(form.ShouldRunHeuristics());
+  EXPECT_TRUE(FormStructure(form).ShouldBeQueried());
 
   // As a side effect of parsing small forms, if any of the heuristics, query,
   // or upload minimums are disabled, we'll autofill fields with an
@@ -928,8 +926,9 @@
     FormData form_copy = form;
     test_api(form_copy).Remove(-1);
     FormStructure form_structure(form_copy);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -957,13 +956,15 @@
   field.set_renderer_id(test::MakeFieldRendererId());
   test_api(form).Append(field);
 
-  EXPECT_TRUE(FormShouldRunHeuristicsForSingleFields(form));
+  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
+  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
 
   // Default configuration.
   {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -991,8 +992,9 @@
                    CreateTestFormField("Password", "Password", "",
                                        FormControlType::kInputPassword)});
   FormStructure form_structure(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -1027,8 +1029,9 @@
        CreateTestFormField("", "", "", FormControlType::kInputText,
                            "garbage billing email")});
   FormStructure form_structure(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -1057,8 +1060,9 @@
                    CreateTestFormField("", "", "", FormControlType::kInputText,
                                        "section-foo address-line1")});
   FormStructure form_structure(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure.ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                               LanguageCode(""), nullptr);
@@ -1136,8 +1140,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1214,8 +1219,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1292,8 +1298,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1360,8 +1367,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1432,8 +1440,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1488,8 +1497,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1537,8 +1547,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1589,8 +1600,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1635,8 +1647,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1676,8 +1689,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1758,8 +1772,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1816,8 +1831,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1867,8 +1883,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -1932,8 +1949,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -2001,8 +2019,9 @@
   test_api(form).Append(field);
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -2480,19 +2499,22 @@
 }
 
 // The test ensures that single field email forms are correctly parsed via
-// `FormShouldRunHeuristicsForSingleFields`.
+// `ShouldRunHeuristicsForSingleFields()`.
 TEST_F(FormStructureTestImpl, SingleFieldEmailHeuristicsBehavior) {
   FormData form = test::GetFormData({.fields = {{.role = EMAIL_ADDRESS}}});
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormShouldRunHeuristics(form));
-  EXPECT_TRUE(FormShouldRunHeuristicsForSingleFields(form));
+  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
+  EXPECT_FALSE(form.ShouldRunHeuristics());
+  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
+  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
 
   {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -2504,20 +2526,23 @@
 }
 
 // The test ensures that email fields are correctly parsed (via
-// `FormShouldRunHeuristicsForSingleFields`) on small forms with two fields.
+// `ShouldRunHeuristicsForSingleFields()`) on small forms with two fields.
 TEST_F(FormStructureTestImpl, TwoFieldFormEmailHeuristicsBehavior) {
   FormData form = test::GetFormData(
       {.fields = {{.role = NAME_FULL}, {.role = EMAIL_ADDRESS}}});
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormShouldRunHeuristics(form));
-  EXPECT_TRUE(FormShouldRunHeuristicsForSingleFields(form));
+  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
+  EXPECT_FALSE(form.ShouldRunHeuristics());
+  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
+  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
 
   {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -2538,13 +2563,16 @@
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormShouldRunHeuristics(form));
-  EXPECT_TRUE(FormShouldRunHeuristicsForSingleFields(form));
+  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
+  EXPECT_FALSE(form.ShouldRunHeuristics());
+  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
+  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
 
   {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -2565,12 +2593,15 @@
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormShouldRunHeuristics(form));
-  EXPECT_TRUE(FormShouldRunHeuristicsForSingleFields(form));
+  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
+  EXPECT_FALSE(form.ShouldRunHeuristics());
+  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
+  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
   {
     FormStructure form_structure(form);
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure.ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure.fields());
     form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -2628,8 +2659,9 @@
                            FormControlType::kInputText, "phone")});
 
   form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/foundations/autofill_manager.cc b/components/autofill/core/browser/foundations/autofill_manager.cc
index 800f210f..47f2668e 100644
--- a/components/autofill/core/browser/foundations/autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/autofill_manager.cc
@@ -707,8 +707,8 @@
     context.heuristic_predictions.reserve(context.form_structures.size());
     for (auto& form_structure : context.form_structures) {
       context.heuristic_predictions.push_back(DetermineHeuristicTypes(
-          context.country_code, context.current_page_language, *form_structure,
-          context.log_manager.get()));
+          context.country_code, context.current_page_language,
+          form_structure->ToFormData(), context.log_manager.get()));
     }
     return context;
   };
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
index ea1c151..6e0ca929 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -2326,8 +2326,9 @@
       test::GetFormData({.fields = {{.role = EMAIL_OR_LOYALTY_MEMBERSHIP_ID},
                                     {.role = PASSWORD}}});
   auto form_structure = std::make_unique<FormStructure>(form_data);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -2403,8 +2404,9 @@
       test::GetFormData({.fields = {{.role = EMAIL_OR_LOYALTY_MEMBERSHIP_ID},
                                     {.role = PASSWORD}}});
   auto form_structure = std::make_unique<FormStructure>(form_data);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -4588,8 +4590,9 @@
   // Simulate having seen this form on page load.
   auto form_structure_instance = std::make_unique<FormStructure>(form);
   FormStructure* form_structure = form_structure_instance.get();
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -4642,8 +4645,9 @@
   // Simulate having seen this form on page load.
   auto form_structure_instance = std::make_unique<FormStructure>(form);
   FormStructure* form_structure = form_structure_instance.get();
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -4754,8 +4758,9 @@
   // Simulate having seen this form on page load.
   auto form_structure_instance = std::make_unique<FormStructure>(form);
   FormStructure* form_structure = form_structure_instance.get();
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -5104,8 +5109,9 @@
   // Simulate having seen this form on page load.
   auto form_structure_instance = std::make_unique<FormStructure>(form);
   FormStructure* form_structure = form_structure_instance.get();
-  HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -5127,8 +5133,9 @@
   auto form_structure_instance2 = std::make_unique<FormStructure>(form2);
   // This pointer is valid as long as autofill manager lives.
   FormStructure* form_structure2 = form_structure_instance2.get();
-  heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure2, nullptr);
+  heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure2->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure2->fields());
   form_structure2->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                 LanguageCode(""), nullptr);
@@ -5199,8 +5206,9 @@
   // Simulate having seen this form on page load.
   // |form_structure| will be owned by |manager()|.
   auto form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -5253,8 +5261,9 @@
   FormStructure* form_structure = [&] {
     auto form_structure = std::make_unique<FormStructure>(form);
     FormStructure* ptr = form_structure.get();
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                form_structure->ToFormData(), nullptr);
     heuristic_predictions.ApplyTo(form_structure->fields());
     form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                  LanguageCode(""), nullptr);
@@ -6042,8 +6051,9 @@
                                        FormControlType::kInputText)});
 
   auto form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -7008,8 +7018,9 @@
   }
   // Override the types and simulate seeing the form on page load.
   auto form_structure = std::make_unique<FormStructure>(form);
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
@@ -7440,8 +7451,8 @@
       auto fs = std::make_unique<FormStructure>(form);
       form_structure = fs.get();
       const HeuristicPredictions heuristic_predictions =
-          DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""), *fs,
-                                  nullptr);
+          DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                                  fs->ToFormData(), nullptr);
       heuristic_predictions.ApplyTo(fs->fields());
       fs->RationalizeAndAssignSections(GeoIpCountryCode(""), LanguageCode(""),
                                        nullptr);
diff --git a/components/autofill/core/browser/heuristic_classification_unittests.cc b/components/autofill/core/browser/heuristic_classification_unittests.cc
index 6e3788d..0e26f62 100644
--- a/components/autofill/core/browser/heuristic_classification_unittests.cc
+++ b/components/autofill/core/browser/heuristic_classification_unittests.cc
@@ -491,8 +491,9 @@
     // Similarly to AutofillManager::ParseFormsAsync, the heuristics are
     // executed after the ML model. If ML predictions are enabled, this does
     // not override the heuristic types but performs rationalization.
-    const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-        client_country, page_language, *form_structure, log_manager);
+    const HeuristicPredictions heuristic_predictions =
+        DetermineHeuristicTypes(client_country, page_language,
+                                form_structure->ToFormData(), log_manager);
     heuristic_predictions.ApplyTo(form_structure->fields());
     form_structure->RationalizeAndAssignSections(client_country, page_language,
                                                  log_manager);
diff --git a/components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide_decider_unittest.cc b/components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide_decider_unittest.cc
index 1e964dd..0c9373da 100644
--- a/components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide_decider_unittest.cc
+++ b/components/autofill/core/browser/integrators/optimization_guide/autofill_optimization_guide_decider_unittest.cc
@@ -145,9 +145,9 @@
   FormStructure form_structure{
       CreateTestCreditCardFormData(/*is_https=*/true,
                                    /*use_month_type=*/true)};
-  const HeuristicPredictions heuristic_predictions =
-      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
-                              form_structure, /*log_manager=*/nullptr);
+  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
+      GeoIpCountryCode(""), LanguageCode(""), form_structure.ToFormData(),
+      /*log_manager=*/nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(
       GeoIpCountryCode(""), LanguageCode(""), /*log_manager=*/nullptr);
@@ -171,9 +171,9 @@
   FormStructure form_structure{
       CreateTestCreditCardFormData(/*is_https=*/true,
                                    /*use_month_type=*/true)};
-  const HeuristicPredictions heuristic_predictions =
-      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
-                              form_structure, /*log_manager=*/nullptr);
+  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
+      GeoIpCountryCode(""), LanguageCode(""), form_structure.ToFormData(),
+      /*log_manager=*/nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(
       GeoIpCountryCode(""), LanguageCode(""), /*log_manager=*/nullptr);
@@ -196,9 +196,9 @@
   FormStructure form_structure{
       CreateTestCreditCardFormData(/*is_https=*/true,
                                    /*use_month_type=*/true)};
-  const HeuristicPredictions heuristic_predictions =
-      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
-                              form_structure, /*log_manager=*/nullptr);
+  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
+      GeoIpCountryCode(""), LanguageCode(""), form_structure.ToFormData(),
+      /*log_manager=*/nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(
       GeoIpCountryCode(""), LanguageCode(""), /*log_manager=*/nullptr);
@@ -218,9 +218,9 @@
   FormStructure form_structure{
       CreateTestCreditCardFormData(/*is_https=*/true,
                                    /*use_month_type=*/true)};
-  const HeuristicPredictions heuristic_predictions =
-      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
-                              form_structure, /*log_manager=*/nullptr);
+  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
+      GeoIpCountryCode(""), LanguageCode(""), form_structure.ToFormData(),
+      /*log_manager=*/nullptr);
   heuristic_predictions.ApplyTo(form_structure.fields());
   form_structure.RationalizeAndAssignSections(
       GeoIpCountryCode(""), LanguageCode(""), /*log_manager=*/nullptr);
diff --git a/components/autofill/core/browser/metrics/form_interactions_ukm_logger_unittest.cc b/components/autofill/core/browser/metrics/form_interactions_ukm_logger_unittest.cc
index f0d76f66..5bc4b39 100644
--- a/components/autofill/core/browser/metrics/form_interactions_ukm_logger_unittest.cc
+++ b/components/autofill/core/browser/metrics/form_interactions_ukm_logger_unittest.cc
@@ -540,8 +540,9 @@
 
   auto form_structure = std::make_unique<FormStructure>(form);
   FormStructure* form_structure_ptr = form_structure.get();
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/metrics/quality_metrics_filling_unittest.cc b/components/autofill/core/browser/metrics/quality_metrics_filling_unittest.cc
index 7bec1bca..be89f884 100644
--- a/components/autofill/core/browser/metrics/quality_metrics_filling_unittest.cc
+++ b/components/autofill/core/browser/metrics/quality_metrics_filling_unittest.cc
@@ -22,8 +22,9 @@
     const test::FormDescription& form_description) {
   auto form_structure =
       std::make_unique<FormStructure>(test::GetFormData(form_description));
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/metrics/quality_metrics_unittest.cc b/components/autofill/core/browser/metrics/quality_metrics_unittest.cc
index fd44d0b4..87c813d7 100644
--- a/components/autofill/core/browser/metrics/quality_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/quality_metrics_unittest.cc
@@ -841,8 +841,9 @@
   std::unique_ptr<FormStructure> form_structure =
       std::make_unique<FormStructure>(form);
   FormStructure* form_structure_ptr = form_structure.get();
-  const HeuristicPredictions heuristic_predictions = DetermineHeuristicTypes(
-      GeoIpCountryCode(""), LanguageCode(""), *form_structure, nullptr);
+  const HeuristicPredictions heuristic_predictions =
+      DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
diff --git a/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc b/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
index 1e319b8..7907100 100644
--- a/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
+++ b/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
@@ -227,7 +227,7 @@
     if (test_case.form_flags.determine_heuristic_type) {
       const HeuristicPredictions heuristic_predictions =
           DetermineHeuristicTypes(GeoIpCountryCode(""), LanguageCode(""),
-                                  *form_structure, nullptr);
+                                  form_structure->ToFormData(), nullptr);
       heuristic_predictions.ApplyTo(form_structure->fields());
       form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                    LanguageCode(""), nullptr);
diff --git a/components/autofill/core/common/form_data.cc b/components/autofill/core/common/form_data.cc
index 25666620e..df4c00c2 100644
--- a/components/autofill/core/common/form_data.cc
+++ b/components/autofill/core/common/form_data.cc
@@ -16,6 +16,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/autofill/core/common/logging/log_buffer.h"
 #include "components/autofill/core/common/logging/stream_operator_util.h"
@@ -73,6 +75,34 @@
            << " FormData from pickle.";
 }
 
+// Returns true if the scheme given by |url| is one for which autofill is
+// allowed to activate. By default this only returns true for HTTP and HTTPS.
+bool HasAllowedScheme(const GURL& url) {
+  return url.SchemeIsHTTPOrHTTPS();
+}
+
+// A field is active if it contributes to the form signature and it is are
+// included in queries to the Autofill server.
+bool is_active(const FormFieldData& field) {
+  return !IsCheckable(field.check_status());
+}
+
+// Returns true if at least `num` fields satisfy `p`.
+// This is useful if `num` is significantly smaller than `fields.size()` because
+// it may avoid iterating over all of `fields`. It's equivalent to
+// `std::range::count_if(fields, [](auto& f) { p(*f); }) >= num`.
+template <typename Predicate>
+bool AtLeastNumSatisfy(base::span<const FormFieldData> fields,
+                       size_t num,
+                       Predicate p) {
+  for (auto it = fields.begin(); it != fields.end() && num > 0; ++it) {
+    if (std::invoke(p, *it)) {
+      --num;
+    }
+  }
+  return num == 0;
+}
+
 }  // namespace
 
 FrameTokenWithPredecessor::FrameTokenWithPredecessor() = default;
@@ -118,6 +148,28 @@
   return true;
 }
 
+const FormFieldData* FormData::FindFieldByGlobalId(
+    const FieldGlobalId& global_id) const {
+  auto fields_it =
+      std::ranges::find(fields(), global_id, &FormFieldData::global_id);
+
+  // If the field is found, return a pointer to the field, otherwise return
+  // nullptr.
+  return fields_it != fields().end() ? &*fields_it : nullptr;
+}
+
+bool FormData::ShouldRunHeuristics() const {
+  // Must be identical to FormStructure::ShouldRunHeuristics()!
+  return AtLeastNumSatisfy(fields(), kMinRequiredFieldsForHeuristics,
+                           is_active) &&
+         HasAllowedScheme(url());
+}
+
+bool FormData::ShouldRunHeuristicsForSingleFields() const {
+  // Must be identical to FormStructure::ShouldRunHeuristicsForSingleFields()!
+  return AtLeastNumSatisfy(fields(), 1, is_active) && HasAllowedScheme(url());
+}
+
 bool FormHasNonEmptyPasswordField(const FormData& form) {
   for (const auto& field : form.fields()) {
     if (field.IsPasswordInputElement()) {
@@ -170,16 +222,6 @@
 
 }  // namespace internal
 
-const FormFieldData* FormData::FindFieldByGlobalId(
-    const FieldGlobalId& global_id) const {
-  auto fields_it =
-      std::ranges::find(fields(), global_id, &FormFieldData::global_id);
-
-  // If the field is found, return a pointer to the field, otherwise return
-  // nullptr.
-  return fields_it != fields().end() ? &*fields_it : nullptr;
-}
-
 void SerializeFormData(const FormData& form_data, base::Pickle* pickle) {
   pickle->WriteInt(kFormDataPickleVersion);
   pickle->WriteString16(form_data.name());
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index bf6031a3..40c8cc5f 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -347,6 +347,9 @@
     likely_contains_captcha_ = likely_contains_captcha;
   }
 
+  bool ShouldRunHeuristics() const;
+  bool ShouldRunHeuristicsForSingleFields() const;
+
  private:
   friend class FormDataTestApi;
 
diff --git a/ios/web_view/internal/autofill/cwv_autofill_form_unittest.mm b/ios/web_view/internal/autofill/cwv_autofill_form_unittest.mm
index 9cf63a3d..f9a9d34 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_form_unittest.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_form_unittest.mm
@@ -39,8 +39,8 @@
       std::make_unique<autofill::FormStructure>(form_data);
   const autofill::HeuristicPredictions heuristic_predictions =
       DetermineHeuristicTypes(autofill::GeoIpCountryCode(""),
-                              autofill::LanguageCode(""), *form_structure,
-                              nullptr);
+                              autofill::LanguageCode(""),
+                              form_structure->ToFormData(), nullptr);
   heuristic_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(
       autofill::GeoIpCountryCode(""), autofill::LanguageCode(""), nullptr);