| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // 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/rationalization_util.h" |
| |
| #include "base/logging.h" |
| #include "components/autofill/core/browser/autofill_field.h" |
| #include "components/autofill/core/browser/autofill_type.h" |
| |
| namespace autofill { |
| namespace rationalization_util { |
| |
| void RationalizePhoneNumberFields( |
| std::vector<AutofillField*>& fields_in_section) { |
| AutofillField* found_number_field = nullptr; |
| AutofillField* found_number_field_second = nullptr; |
| AutofillField* found_city_code_field = nullptr; |
| AutofillField* found_country_code_field = nullptr; |
| AutofillField* found_city_and_number_field = nullptr; |
| AutofillField* found_whole_number_field = nullptr; |
| bool phone_number_found = false; |
| bool phone_number_separate_fields = false; |
| // Iterate through all given fields. Iteration stops when it first finds a |
| // valid set of fields that can compose a whole number. The |found_*| pointers |
| // will be set to that set of fields when iteration finishes. |
| for (AutofillField* field : fields_in_section) { |
| if (!field->is_focusable) |
| continue; |
| ServerFieldType current_field_type = field->Type().GetStorableType(); |
| switch (current_field_type) { |
| case PHONE_HOME_NUMBER: |
| case PHONE_BILLING_NUMBER: |
| if (!found_number_field) { |
| found_number_field = field; |
| if (field->max_length < 5) { |
| phone_number_separate_fields = true; |
| } else { |
| phone_number_found = true; |
| } |
| break; |
| } |
| // If the form has phone number separated into exchange and subscriber |
| // number we mark both of them as number fields. |
| // TODO(wuandy): A less hacky solution to have dedicated enum for |
| // exchange and subscriber number. |
| DCHECK(phone_number_separate_fields); |
| DCHECK(!found_number_field_second); |
| found_number_field_second = field; |
| phone_number_found = true; |
| break; |
| case PHONE_HOME_CITY_CODE: |
| case PHONE_BILLING_CITY_CODE: |
| if (!found_city_code_field) |
| found_city_code_field = field; |
| break; |
| case PHONE_HOME_COUNTRY_CODE: |
| case PHONE_BILLING_COUNTRY_CODE: |
| if (!found_country_code_field) |
| found_country_code_field = field; |
| break; |
| case PHONE_HOME_CITY_AND_NUMBER: |
| case PHONE_BILLING_CITY_AND_NUMBER: |
| DCHECK(!phone_number_found && !found_city_and_number_field); |
| found_city_and_number_field = field; |
| phone_number_found = true; |
| break; |
| case PHONE_HOME_WHOLE_NUMBER: |
| case PHONE_BILLING_WHOLE_NUMBER: |
| DCHECK(!phone_number_found && !found_whole_number_field); |
| found_whole_number_field = field; |
| phone_number_found = true; |
| break; |
| default: |
| break; |
| } |
| if (phone_number_found) |
| break; |
| } |
| |
| // The first number of found may be the whole number field, the |
| // city and number field, or neither. But it cannot be both. |
| DCHECK(!(found_whole_number_field && found_city_and_number_field)); |
| |
| // Prefer to fill the first complete phone number found. The whole number |
| // and city_and_number fields are only set if they represent the first |
| // complete number found; otherwise, a complete number is present as |
| // component input fields. These scenarios are mutually exclusive, so |
| // clean up any inconsistencies. |
| if (found_whole_number_field) { |
| found_number_field = nullptr; |
| found_number_field_second = nullptr; |
| found_city_code_field = nullptr; |
| found_country_code_field = nullptr; |
| } else if (found_city_and_number_field) { |
| found_number_field = nullptr; |
| found_number_field_second = nullptr; |
| found_city_code_field = nullptr; |
| } |
| |
| // A second update pass. |
| // At this point, either |phone_number_found| is false and we should do a |
| // best-effort filling for the field whose types we have seen a first time. |
| // Or |phone_number_found| is true and the pointers to the fields that |
| // compose the first valid phone number are set to not-NULL, specifically: |
| // 1. |found_whole_number_field| is not NULL, other pointers set to NULL, or |
| // 2. |found_city_and_number_field| is not NULL, |found_country_code_field| is |
| // probably not NULL, and other pointers set to NULL, or |
| // 3. |found_city_code_field| and |found_number_field| are not NULL, |
| // |found_country_code_field| is probably not NULL, and other pointers are |
| // NULL. |
| // 4. |found_city_code_field|, |found_number_field| and |
| // |found_number_field_second| |
| // are not NULL, |found_country_code_field| is probably not NULL, and other |
| // pointers are NULL. |
| |
| // For all above cases, in the update pass, if one field is phone |
| // number related but not one of the found fields from first pass, set their |
| // |only_fill_when_focused| field to true. |
| for (auto it = fields_in_section.begin(); it != fields_in_section.end(); |
| ++it) { |
| AutofillField* field = *it; |
| ServerFieldType current_field_type = field->Type().GetStorableType(); |
| switch (current_field_type) { |
| case PHONE_HOME_NUMBER: |
| case PHONE_BILLING_NUMBER: |
| if (field != found_number_field && field != found_number_field_second) |
| field->set_only_fill_when_focused(true); |
| break; |
| case PHONE_HOME_CITY_CODE: |
| case PHONE_BILLING_CITY_CODE: |
| if (field != found_city_code_field) |
| field->set_only_fill_when_focused(true); |
| break; |
| case PHONE_HOME_COUNTRY_CODE: |
| case PHONE_BILLING_COUNTRY_CODE: |
| if (field != found_country_code_field) |
| field->set_only_fill_when_focused(true); |
| break; |
| case PHONE_HOME_CITY_AND_NUMBER: |
| case PHONE_BILLING_CITY_AND_NUMBER: |
| if (field != found_city_and_number_field) |
| field->set_only_fill_when_focused(true); |
| break; |
| case PHONE_HOME_WHOLE_NUMBER: |
| case PHONE_BILLING_WHOLE_NUMBER: |
| if (field != found_whole_number_field) |
| field->set_only_fill_when_focused(true); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| } // namespace rationalization_util |
| } // namespace autofill |