chromium/components/autofill/content/renderer/form_autofill_util.cc

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

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

#include <limits>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/check_deref.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/debug/crash_logging.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/not_fatal_until.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/autofill/content/renderer/timing.h"
#include "components/autofill/core/common/autocomplete_parsing_util.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/field_data_manager.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "content/public/renderer/render_frame.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_autofill_state.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_element_collection.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_label_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_option_element.h"
#include "third_party/blink/public/web/web_remote_frame.h"
#include "third_party/blink/public/web/web_select_element.h"
#include "third_party/blink/public/web/web_select_list_element.h"
#include "third_party/re2/src/re2/re2.h"

WebAutofillState;
WebDocument;
WebElement;
WebElementCollection;
WebFormControlElement;
WebFormElement;
WebFrame;
WebInputElement;
WebLabelElement;
WebLocalFrame;
WebNode;
WebOptionElement;
WebSelectElement;
WebSelectListElement;
WebString;
WebVector;

namespace autofill::form_util {

struct ShadowFieldData {};

namespace {

LabelSource;

// Maximal length of a button's title.
constexpr int kMaxLengthForSingleButtonTitle =;
// Maximal length of all button titles.
constexpr int kMaxLengthForAllButtonTitles =;

// Number of shadow roots to traverse upwards when looking for relevant forms
// and labels of an input element inside a shadow root.
constexpr size_t kMaxShadowLevelsUp =;

// Text features to detect form submission buttons. Features are selected based
// on analysis of real forms and their buttons.
// TODO(crbug.com/41429204): Consider to add more features (e.g. non-English
// features).
const char* const kButtonFeatures[] =;

// Number of form neighbor nodes to traverse in search of four digit
// combinations on the webpage.
constexpr int kFormNeighborNodesToTraverse =;

// Maximum number of consecutive numbers to allow in the four digit combination
// matches.
constexpr int kMaxConsecutiveInFourDigitCombinationMatches =;

// Maximum number of four digit combination matches to find in the DOM.
constexpr size_t kMaxFourDigitCombinationMatches =;

// Constants to be passed to GetWebString<kConstant>().
constexpr std::string_view kAnchor =;
constexpr std::string_view kAutocomplete =;
constexpr std::string_view kAriaDescribedBy =;
constexpr std::string_view kAriaLabel =;
constexpr std::string_view kAriaLabelledBy =;
constexpr std::string_view kBold =;
constexpr std::string_view kBreak =;
constexpr std::string_view kButton =;
constexpr std::string_view kClass =;
constexpr std::string_view kColspan =;
constexpr std::string_view kDefinitionDescriptionTag =;
constexpr std::string_view kDefinitionTermTag =;
constexpr std::string_view kDiv =;
constexpr std::string_view kFieldset =;
constexpr std::string_view kFont =;
constexpr std::string_view kFor =;
constexpr std::string_view kForm =;
constexpr std::string_view kFormControlSelector =;
constexpr std::string_view kId =;
constexpr std::string_view kIframe =;
constexpr std::string_view kImage =;
constexpr std::string_view kInput =;
constexpr std::string_view kLabel =;
constexpr std::string_view kListItem =;
constexpr std::string_view kMeta =;
constexpr std::string_view kName =;
constexpr std::string_view kNoScript =;
constexpr std::string_view kOption =;
constexpr std::string_view kParagraph =;
constexpr std::string_view kPlaceholder =;
constexpr std::string_view kRole =;
constexpr std::string_view kScript =;
constexpr std::string_view kSpan =;
#if BUILDFLAG(IS_ANDROID)
constexpr std::string_view kSrc = "src";
#endif
constexpr std::string_view kStrong =;
constexpr std::string_view kSubmit =;
constexpr std::string_view kTable =;
constexpr std::string_view kTableCell =;
constexpr std::string_view kTableHeader =;
constexpr std::string_view kTableRow =;
constexpr std::string_view kTitle =;
constexpr std::string_view kType =;
constexpr std::string_view kValue =;

// Wrapper for frequently used WebString constants.
template <const std::string_view& string>
const WebString& GetWebString() {}

template <const std::string_view& tag_name>
bool HasTagName(const WebElement& element) {}

template <const std::string_view& tag_name>
bool HasTagName(const WebNode& node) {}

template <const std::string_view& attribute>
bool HasAttribute(const WebElement& element) {}

template <const std::string_view& attribute>
WebString GetAttribute(const WebElement& element) {}

// Returns the form's |name| attribute if non-empty; otherwise the form's |id|
// attribute.
std::u16string GetFormIdentifier(const WebFormElement& form) {}

// Helper function to return the next web node of `current_node` in the DOM.
// `forward` determines the direction to traverse in.
WebNode NextWebNode(const WebNode& current_node, bool forward) {}

// All text fields, including password fields, should be extracted.
bool IsTextInput(const WebInputElement& element) {}

bool IsSelectElement(const WebFormControlElement& element) {}

bool IsSelectListElement(const WebFormControlElement& element) {}

bool IsSelectOrSelectListElement(const WebFormControlElement& element) {}

bool IsTextInput(const WebFormControlElement& element) {}

bool IsMonthInput(const WebInputElement& element) {}

bool IsCheckableElement(const WebFormControlElement& element) {}

bool IsCheckableElement(const WebElement& element) {}

// Returns true if |node| is an element and it is a container type that
// InferLabelForElement() can traverse.
bool IsTraversableContainerElement(const WebNode& node) {}

// This function checks whether the children of |element|
// are of the type <script>, <meta>, or <title>.
bool IsWebElementEmpty(const WebElement& root) {}

// Returns the colspan for a <td> / <th>. Defaults to 1.
size_t CalculateTableCellColumnSpan(const WebElement& element) {}

// Appends |suffix| to |prefix| so that any intermediary whitespace is collapsed
// to a single space.  If |force_whitespace| is true, then the resulting string
// is guaranteed to have a space between |prefix| and |suffix|.  Otherwise, the
// result includes a space only if |prefix| has trailing whitespace or |suffix|
// has leading whitespace.
// A few examples:
//  * CombineAndCollapseWhitespace("foo", "bar", false)       -> "foobar"
//  * CombineAndCollapseWhitespace("foo", "bar", true)        -> "foo bar"
//  * CombineAndCollapseWhitespace("foo ", "bar", false)      -> "foo bar"
//  * CombineAndCollapseWhitespace("foo", " bar", false)      -> "foo bar"
//  * CombineAndCollapseWhitespace("foo", " bar", true)       -> "foo bar"
//  * CombineAndCollapseWhitespace("foo   ", "   bar", false) -> "foo bar"
//  * CombineAndCollapseWhitespace(" foo", "bar ", false)     -> " foobar "
//  * CombineAndCollapseWhitespace(" foo", "bar ", true)      -> " foo bar "
const std::u16string CombineAndCollapseWhitespace(const std::u16string& prefix,
                                                  const std::u16string& suffix,
                                                  bool force_whitespace) {}

// This is a helper function for the FindChildText() function (see below).
// Search depth is limited with the |depth| parameter.
// |divs_to_skip| is a list of <div> tags to ignore if encountered.
std::u16string FindChildTextInner(const WebNode& node,
                                  int depth,
                                  const std::set<WebNode>& divs_to_skip) {}

// Same as FindChildText() below, but with a list of div nodes to skip.
std::u16string FindChildTextWithIgnoreList(
    const WebNode& node,
    const std::set<WebNode>& divs_to_skip) {}

struct InferredLabel {};

// Shared function for InferLabelFromPrevious() and InferLabelFromNext().
std::optional<InferredLabel> InferLabelFromSibling(
    const WebFormControlElement& element,
    bool forward) {}

// Helper function to add a button's |title| to the |list|.
void AddButtonTitleToList(std::u16string title,
                          mojom::ButtonTitleType button_type,
                          ButtonTitleList* list) {}

// Returns true iff |attribute| contains one of |kButtonFeatures|.
bool AttributeHasButtonFeature(const WebString& attribute) {}

// Returns true if |element|'s id, name or css class contain |kButtonFeatures|.
bool ElementAttributesHasButtonFeature(const WebElement& element) {}

// Finds elements from |elements| that contains |kButtonFeatures| and appends it
// to the |list|. If |extract_value_attribute|, the "value" attribute is
// extracted as a button title. Otherwise, |WebElement::TextContent| (aka
// innerText in Javascript) is extracted as a title.
void FindElementsWithButtonFeatures(const WebElementCollection& elements,
                                    mojom::ButtonTitleType button_type,
                                    bool extract_value_attribute,
                                    ButtonTitleList* list) {}

// Returns a list of elements whose id matches one of the ids found in
// `id_list`.
std::vector<WebElement> GetWebElementsFromIdList(const WebDocument& document,
                                                 const WebString& id_list) {}

// Returns the coalesced child of the elements who's ids are found in
// |id_list|.
//
// For example, given this document...
//
//      <div id="billing">Billing</div>
//      <div>
//        <div id="name">Name</div>
//        <input id="field1" type="text" aria-labelledby="billing name"/>
//     </div>
//     <div>
//       <div id="address">Address</div>
//       <input id="field2" type="text" aria-labelledby="billing address"/>
//     </div>
//
// The coalesced text by the id_list found in the aria-labelledby attribute
// of the field1 input element would be "Billing Name" and for field2 it would
// be "Billing Address".
std::u16string CoalesceTextByIdList(const WebDocument& document,
                                    const WebString& id_list) {}

// Returns the ARIA label text of the elements denoted by the aria-labelledby
// attribute of |element| or the value of the aria-label attribute of
// |element|, with priority given to the aria-labelledby attribute.
std::u16string GetAriaLabel(const WebDocument& document,
                            const WebElement& element) {}

// Returns the ARIA label text of the elements denoted by the aria-describedby
// attribute of |element|.
std::u16string GetAriaDescription(const WebDocument& document,
                                  const WebElement& element) {}

// Helper for |InferLabelForElement()| that infers a label, if possible, from
// a previous sibling of |element|,
// e.g. Some Text <input ...>
// or   Some <span>Text</span> <input ...>
// or   <p>Some Text</p><input ...>
// or   <label>Some Text</label> <input ...>
// or   Some Text <img><input ...>
// or   <b>Some Text</b><br/> <input ...>.
std::optional<InferredLabel> InferLabelFromPrevious(
    const WebFormControlElement& element) {}

// Same as InferLabelFromPrevious(), but in the other direction.
// Useful for cases like: <span><input type="checkbox">Label For Checkbox</span>
std::optional<InferredLabel> InferLabelFromNext(
    const WebFormControlElement& element) {}

// Helper for |InferLabelForElement()| that infers a label, if possible, from
// the placeholder text. e.g. <input placeholder="foo">
std::optional<InferredLabel> InferLabelFromPlaceholder(
    const WebFormControlElement& element) {}

std::optional<InferredLabel> InferLabelFromAriaLabel(
    const WebFormControlElement& element) {}

// Detects a label declared after the `element`, which is visually positioned
// above the element (usually using CSS). Such labels often act as
// placeholders. E.g.
// <div>
//  <input>
//  <span>Placeholder</span>
// </div>
// We want to consider placeholders which are either positioned over the input
// element or placed on the top left (or top right in RTL languages) of the
// input element (they need to overlap a bit). We want to disregard elements
// that are primarily below the input element (even if they overlap) because
// that place is often used to indicate incorrect inputs.
std::optional<InferredLabel> InferLabelFromOverlayingSuccessor(
    const WebFormControlElement& element) {}

// Helper for |InferLabelForElement()| that infers a label, from
// the value attribute when it is present and user has not typed in (if
// element's value attribute is same as the element's value).
std::optional<InferredLabel> InferLabelFromValueAttribute(
    const WebFormControlElement& element) {}

// Helper for `InferLabelForElement()` that infers a label, if possible, from
// surrounding table structure,
// e.g. <tr><td>Some Text</td><td><input ...></td></tr>
// or   <tr><th>Some Text</th><td><input ...></td></tr>
// or   <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr>
// or   <tr><th><b>Some Text</b></th><td><b><input ...></b></td></tr>
// `cell` represents the <td> tag containing the input element.
std::optional<InferredLabel> InferLabelFromTableColumn(const WebNode& cell) {}

// Helper for `InferLabelForElement()` that infers a label, if possible, from
// surrounding table structure.
//
// If there are multiple cells and the row with the input matches up with the
// previous row, then look for a specific cell within the previous row.
// e.g. <tr><td>Input 1 label</td><td>Input 2 label</td></tr>
//      <tr><td><input name="input 1"></td><td><input name="input2"></td></tr>
//
// Otherwise, just look in the entire previous row.
// e.g. <tr><td>Some Text</td></tr><tr><td><input ...></td></tr>
// `cell` represents the <td> tag containing the input element.
std::optional<InferredLabel> InferLabelFromTableRow(const WebNode& cell) {}

// Helper for `InferLabelForElement()` that infers a label, if possible, from
// a surrounding div table,
// e.g. <div>Some Text<span><input ...></span></div>
// e.g. <div>Some Text</div><div><input ...></div>
//
// Contrary to the other InferLabelFrom* functions, this functions walks up
// the DOM tree from the original input, instead of down from the surrounding
// tag. While doing so, if a <label> or text node sibling are found along the
// way, a label is inferred from them directly. For example, <div>First
// name<div><input></div>Last name<div><input></div></div> infers "First name"
// and "Last name" for the two inputs, respectively, by picking up the text
// nodes on the way to the surrounding div. Without doing so, the label of both
// inputs becomes "First nameLast name".
std::optional<InferredLabel> InferLabelFromDivTable(
    const WebFormControlElement& element) {}

// Helper for `InferLabelForElement()` that infers a label, if possible, from
// a surrounding definition list,
// e.g. <dl><dt>Some Text</dt><dd><input ...></dd></dl>
// e.g. <dl><dt><b>Some Text</b></dt><dd><b><input ...></b></dd></dl>
std::optional<InferredLabel> InferLabelFromDefinitionList(const WebNode& dd) {}

// Helper for `InferLabelForElement()` that infers a label, if possible, from
// the first surrounding <label>, <div>, <td>, <dd> or <li> tag (if any).
// See `FindChildText()`, `InferLabelFromDivTable()`,
// `InferLabelFromTableColumn()`, `InferLabelFromTableRow()` and
// `InferLabelFromDefinitionList()` for examples how a label is extracted from
// the different tags.
std::optional<InferredLabel> InferLabelFromAncestors(
    const WebFormControlElement& element) {}
// Infers corresponding label for `element` from surrounding context in the DOM,
// e.g. the contents of the preceding <p> tag or text element. Returns an empty
// string if it could not find a label for `element`.
std::optional<InferredLabel> InferLabelForElement(
    const WebFormControlElement& element) {}

void InferLabelForElements(
    base::span<const WebFormControlElement> control_elements,
    std::vector<FormFieldData>& fields) {}

// Removes the duplicate titles and limits totals length. The order of the list
// is preserved as first elements are more reliable features than following
// ones.
void RemoveDuplicatesAndLimitTotalLength(ButtonTitleList* result) {}

// Return button titles with highest priority based on credibility of their HTML
// tags and attributes.
ButtonTitleList InferButtonTitlesForForm(const WebFormElement& web_form) {}

// Returns the list items for the passed-in <select> or <selectlist>.
WebVector<WebElement> GetListItemsForSelectOrSelectList(
    const WebFormControlElement& element) {}

// Fills `options` with the <option> elements present in `option_elements`.
void FilterOptionElementsAndGetOptionStrings(
    const WebVector<WebElement>& option_elements,
    std::vector<SelectOption>* options) {}

bool ShouldSkipFillField(const FormFieldData::FillData& field,
                         const WebFormControlElement& element) {}

// Sets the |field|'s value to the value in |data|, and specifies the section
// for filled fields.  Also sets the "autofilled" attribute,
// causing the background to be blue.
void FillFormField(const FormFieldData::FillData& data,
                   bool is_initiating_node,
                   WebFormControlElement& field,
                   FieldDataManager& field_data_manager) {}

// Sets the |field|'s "suggested" (non JS visible) value to the value in |data|.
// Also sets the "autofilled" attribute, causing the background to be blue.
void PreviewFormField(const FormFieldData::FillData& data,
                      WebFormControlElement& field,
                      FieldDataManager& field_data_manager) {}

// A less-than comparator for FormFieldData's pointer by their FieldRendererId.
// It also supports direct comparison of a FieldRendererId with a FormFieldData
// pointer.
struct CompareByRendererId {};

// Searches |fields| for a unique field with name |field_name|. If there is
// none or more than one field with that name, the fields' shadow hosts' name
// and id attributes are tested, and the first match is returned. Returns
// nullptr if no match was found.
FormFieldData* SearchForFormControlByName(
    const std::u16string& field_name,
    base::span<const std::pair<FormFieldData*, ShadowFieldData>> fields,
    LabelSource& label_source) {}

// Considers all <label> descendents of `root`, looks at their corresponding
// control and matches them to the fields in `fields`. The corresponding
// control is either a descendent of the label or an input specified by id in
// the label's for-attribute.
// In case no corresponding control exists, but a for-attribute is specified,
// we look for fields with matching name as a fallback. Moreover, the ids and
// names of shadow root ancestors of the fields are considered as a fallback.
void MatchLabelsAndFields(const WebDocument& root,
                          base::span<FormFieldData> fields,
                          std::vector<ShadowFieldData> shadow_fields) {}

bool IsAdIframe(const WebElement& element) {}

// A heuristic visibility detection. See crbug.com/1335257 for an overview of
// relevant aspects.
//
// Note that WebElement::BoundsInWidget(), WebElement::GetClientSize(),
// and WebElement::GetScrollSize() include the padding but do not include the
// border and margin. BoundsInWidget() additionally scales the
// dimensions according to the zoom factor.
//
// It seems that invisible fields on websites typically have dimensions between
// 0 and 10 pixels, before the zoom factor. Therefore choosing `kMinPixelSize`
// is easier without including the zoom factor. For that reason, this function
// prefers GetClientSize() over BoundsInWidget().
//
// This function does not check the position in the viewport because fields in
// iframes commonly are visible despite the body having height zero. Therefore,
// `e.GetDocument().Body().BoundsInWidget().Intersects(
//      e.BoundsInWidget())` yields false negatives.
//
// TODO(crbug.com/40846971): Can input fields or iframes actually overflow?
bool IsWebElementVisible(const WebElement& element) {}

// Returns the topmost <form> ancestor of |node|, or an IsNull() pointer.
//
// Generally, WebFormElements must not be nested [1]. When parsing HTML, Blink
// ignores nested form tags; the inner forms therefore never make it into the
// DOM. However, nested forms can be created and added to the DOM dynamically,
// in which case Blink associates each field with its closest ancestor.
//
// For some elements, Autofill determines the associated form without Blink's
// help (currently, these are only iframe elements). For consistency with
// Blink's behaviour, we associate them with their closest form element
// ancestor.
//
// [1] https://html.spec.whatwg.org/multipage/forms.html#the-form-element
WebFormElement GetClosestAncestorFormElement(WebNode n) {}

// Returns true if a DOM traversal (pre-order, depth-first) visits `x` before
// `y`.
// As a performance improvement, `ancestor_hint` can be set to a suspected
// ancestor of `x` and `y`. Otherwise, `ancestor_hint` can be arbitrary.
//
// This function is a simplified/specialized version of Blink's private
// Node::compareDocumentPosition().
bool IsDOMPredecessor(const WebNode& x,
                      const WebNode& y,
                      const WebNode& ancestor_hint) {}

// Indicates if an iframe |element| is considered actually visible to the user.
//
// This function is not intended to implement a perfect visibility check. It
// rather aims to strike balance between cheap tests and filtering invisible
// frames, which can then be skipped during parsing.
//
// The current visibility check requires focusability and a sufficiently large
// bounding box. Thus, particularly elements with "visibility: invisible",
// "display: none", and "width: 0; height: 0" are considered invisible.
//
// Future potential improvements include:
// * Detect potential visibility of elements with "overflow: visible".
//   (See WebElement::GetScrollSize().)
// * Detect invisibility of elements with
//   - "position: absolute; {left,top,right,bottom}: -100px"
//   - "opacity: 0.0"
//   - "clip: rect(0,0,0,0)"
//
// TODO(crbug.com/40846971): This check is very similar to IsWebElementVisible()
// (see the documentation there for the subtle differences: zoom factor and
// scroll size). We can probably merge them but should do a Finch experiment
// about it.
bool IsVisibleIframe(const WebElement& element) {}

// A necessary condition for an iframe to be added to FormData::child_frames.
//
// We also extract invisible iframes for the following reason. An iframe may be
// invisible at page load (for example, when it contains parts of a credit card
// form and the user hasn't chosen a payment method yet). Autofill is not
// notified when the iframe becomes visible. That is, Autofill may have not
// re-extracted the main frame's form by the time the iframe has become visible
// and the user has focused a field in that iframe. This outdated form is
// missing the link in FormData::child_frames between the parent form and the
// iframe's form, which prevents Autofill from filling across frames.
//
// The current implementation extracts visible ad frames. Assuming IsAdIframe()
// has no false positives, we could omit the IsVisibleIframe() disjunct. We
// could even take this further and disable Autofill in ad frames.
//
// For further details, see crbug.com/1117028#c8 and crbug.com/1245631.
bool IsRelevantChildFrame(const WebElement& element) {}

// Returns the <iframe> elements that are associated with `form_element`.
// An iframe is associated with `form_element` iff
// - if `form_element` is non-null:
//   `form_element` is the iframe's closest <form> ancestor
// - if `form_element` is null:
//   the iframe has no <form> ancestor.
std::vector<WebElement> GetIframeElements(const WebDocument& document,
                                          const WebFormElement& form_element) {}

// Returns if a script-modified username or credit card number is suitable to
// store in Password Manager/Autofill given `typed_value`.
bool ScriptModifiedUsernameOrCreditCardNumberAcceptable(
    const std::u16string& value,
    const std::u16string& typed_value,
    const FieldDataManager& field_data_manager) {}

// Returns the maximum length value that Autofill may fill into the field. There
// are two special cases:
// - It is 0 for fields that do not support free text input (e.g., <select> and
//   <input type=month>).
// - It is the maximum 32 bit number for fields that support text values (e.g.,
//   <input type=text> or <textarea>) but have no maxlength attribute set.
//   The choice of 32 (as opposed to 64) is intentional: it allows us to still
//   do arithmetic with FormFieldData::max_length without having to worry about
//   integer overflows everywhere.
uint64_t GetMaxLength(const WebFormControlElement& element) {}

// Gets up to kMaxListSize data list values (with corresponding label) for the
// given element, each value and label have as far as kMaxDataLength.
void GetDataListSuggestions(const WebInputElement& element,
                            std::vector<SelectOption>* options) {}

// Returns whether `node` has a shadow-tree-including ancestor that is a
// `<form>`.
bool HasFormAncestor(WebNode node) {}

// Returns all connected form control elements
// - owned by `form_element` if `!form_element.IsNull()`;
// - owned by no form otherwise.
std::vector<WebFormControlElement> GetOwnedFormControls(
    const WebDocument& document,
    const WebFormElement& form_element) {}

// Fills out a FormField object from a given autofillable WebFormControlElement.
// |extract_options|: See the enum ExtractOption above for details. Field
// properties will be copied from |field_data_manager|, if the argument is not
// null and has entry for |element| (see properties in FieldPropertiesFlags).
void WebFormControlElementToFormField(
    const WebFormElement& form_element,
    const WebFormControlElement& element,
    const FieldDataManager* field_data_manager,
    DenseSet<ExtractOption> extract_options,
    FormFieldData* field,
    ShadowFieldData* shadow_data) {}

#if BUILDFLAG(IS_ANDROID)
// Checks whether an `element` looks like a captcha based on
// heuristics. The heuristics cannot be perfect and therefore is a subject to
// change, e.g. adding a list of domains of captcha providers to be compared
// with 'src' attribute.
bool IsLikelyCaptchaIframe(const WebElement& element) {
  static constexpr std::string_view kCaptcha = "captcha";
  return GetAttribute<kSrc>(element).Find(kCaptcha) != std::string::npos ||
         GetAttribute<kTitle>(element).Find(kCaptcha) != std::string::npos ||
         GetAttribute<kId>(element).Find(kCaptcha) != std::string::npos ||
         GetAttribute<kName>(element).Find(kCaptcha) != std::string::npos;
}
#endif

std::optional<FormData> ExtractFormDataWithFieldsAndFrames(
    const WebDocument& document,
    const WebFormElement& form_element,
    const FieldDataManager& field_data_manager,
    DenseSet<ExtractOption> extract_options) {}

}  // namespace

InferredLabel::InferredLabel(std::u16string label, LabelSource source)
    :{}

// static
std::optional<InferredLabel> InferredLabel::BuildIfValid(std::u16string label,
                                                         LabelSource source) {}

std::string GetAutocompleteAttribute(const WebElement& element) {}

std::optional<FormData> ExtractFormData(
    const WebDocument& document,
    const WebFormElement& form_element,
    const FieldDataManager& field_data_manager,
    const CallTimerState& timer_state,
    DenseSet<ExtractOption> extract_options) {}

GURL GetCanonicalActionForForm(const WebFormElement& form) {}

bool IsTextAreaElement(const WebFormControlElement& element) {}

bool IsTextAreaElementOrTextInput(const WebFormControlElement& element) {}

bool IsAutofillableInputElement(const WebInputElement& element) {}

bool IsAutofillableElement(const WebFormControlElement& element) {}

FormControlType ToAutofillFormControlType(blink::mojom::FormControlType type) {}

bool IsCheckable(FormControlType form_control_type) {}

bool IsWebauthnTaggedElement(const WebFormControlElement& element) {}

bool IsElementEditable(const WebInputElement& element) {}

bool IsWebElementFocusableForAutofill(const WebElement& element) {}

FormRendererId GetFormRendererId(const WebElement& e) {}

FieldRendererId GetFieldRendererId(const WebElement& e) {}

base::i18n::TextDirection GetTextDirectionForElement(
    const WebFormControlElement& element) {}

std::vector<WebFormControlElement> GetOwnedAutofillableFormControls(
    const WebDocument& document,
    const WebFormElement& form_element) {}

WebFormElement GetOwningForm(const WebFormControlElement& form_control) {}

std::optional<std::pair<FormData, raw_ref<const FormFieldData>>>
FindFormAndFieldForFormControlElement(
    const WebFormControlElement& element,
    const FieldDataManager& field_data_manager,
    const CallTimerState& timer_state,
    DenseSet<ExtractOption> extract_options) {}

std::optional<FormData> FindFormForContentEditable(
    const WebElement& content_editable) {}

std::vector<std::pair<FieldRef, WebAutofillState>> ApplyFieldsAction(
    const WebDocument& document,
    base::span<const FormFieldData::FillData> fields,
    mojom::FormActionType action_type,
    mojom::ActionPersistence action_persistence,
    FieldDataManager& field_data_manager) {}

void ClearPreviewedElements(
    base::span<std::pair<WebFormControlElement, WebAutofillState>>
        previewed_elements) {}

bool IsOwnedByFrame(const WebNode& node, content::RenderFrame* frame) {}

bool MaybeWasOwnedByFrame(const WebNode& node, content::RenderFrame* frame) {}

bool IsWebpageEmpty(const WebLocalFrame* frame) {}

std::u16string FindChildText(const WebNode& node) {}

ButtonTitleList GetButtonTitles(const WebFormElement& web_form,
                                ButtonTitlesCache* button_titles_cache) {}

WebFormElement GetFormByRendererId(FormRendererId form_renderer_id) {}

WebFormControlElement GetFormControlByRendererId(
    FieldRendererId queried_form_control) {}

WebElement GetContentEditableByRendererId(FieldRendererId field_renderer_id) {}

void TraverseDomForFourDigitCombinations(
    const WebDocument& document,
    base::OnceCallback<void(const std::vector<std::string>&)>
        potential_matches) {}

std::u16string GetAriaLabelForTesting(  // IN-TEST
    const WebDocument& document,
    const WebElement& element) {}

std::u16string GetAriaDescriptionForTesting(  // IN-TEST
    const WebDocument& document,
    const WebElement& element) {}

void InferLabelForElementsForTesting(  // IN-TEST
    base::span<const blink::WebFormControlElement> control_elements,
    std::vector<FormFieldData>& fields) {}

std::vector<blink::WebFormControlElement>
GetOwnedFormControlsForTesting(  // IN-TEST
    const blink::WebDocument& document,
    const blink::WebFormElement& form_element) {}

WebNode NextWebNodeForTesting(  // IN-TEST
    const WebNode& current_node,
    bool forward) {}

std::u16string FindChildTextWithIgnoreListForTesting(  // IN-TEST
    const WebNode& node,
    const std::set<WebNode>& divs_to_skip) {}

bool IsWebElementVisibleForTesting(const WebElement& element) {}

bool IsVisibleIframeForTesting(  // IN-TEST
    const WebElement& iframe_element) {}

WebFormElement GetClosestAncestorFormElementForTesting(WebNode n) {}

bool IsDOMPredecessorForTesting(const WebNode& x,  // IN-TEST
                                const WebNode& y,
                                const WebNode& ancestor_hint) {}

uint64_t GetMaxLengthForTesting(  // IN-TEST
    const WebFormControlElement& element) {}

void WebFormControlElementToFormFieldForTesting(  // IN-TEST
    const WebFormElement& form_element,
    const WebFormControlElement& element,
    const FieldDataManager* field_data_manager,
    DenseSet<ExtractOption> extract_options,
    FormFieldData* field) {}

void GetDataListSuggestionsForTesting(  // IN-TEST
    const WebInputElement& element,
    std::vector<SelectOption>* options) {}

}  // namespace autofill::form_util