ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / components / autofill / content / renderer / form_autofill_util.cc
blobc5d30307b7ecf401ce6fa64d1b07320388b62cdb
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/autofill/content/renderer/form_autofill_util.h"
7 #include <map>
8 #include <set>
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_vector.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/autofill/core/common/autofill_data_validation.h"
16 #include "components/autofill/core/common/autofill_switches.h"
17 #include "components/autofill/core/common/form_data.h"
18 #include "components/autofill/core/common/form_field_data.h"
19 #include "third_party/WebKit/public/platform/WebString.h"
20 #include "third_party/WebKit/public/platform/WebVector.h"
21 #include "third_party/WebKit/public/web/WebDocument.h"
22 #include "third_party/WebKit/public/web/WebElement.h"
23 #include "third_party/WebKit/public/web/WebElementCollection.h"
24 #include "third_party/WebKit/public/web/WebFormControlElement.h"
25 #include "third_party/WebKit/public/web/WebFormElement.h"
26 #include "third_party/WebKit/public/web/WebInputElement.h"
27 #include "third_party/WebKit/public/web/WebLabelElement.h"
28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
29 #include "third_party/WebKit/public/web/WebNode.h"
30 #include "third_party/WebKit/public/web/WebNodeList.h"
31 #include "third_party/WebKit/public/web/WebOptionElement.h"
32 #include "third_party/WebKit/public/web/WebSelectElement.h"
33 #include "third_party/WebKit/public/web/WebTextAreaElement.h"
35 using blink::WebDocument;
36 using blink::WebElement;
37 using blink::WebElementCollection;
38 using blink::WebFormControlElement;
39 using blink::WebFormElement;
40 using blink::WebFrame;
41 using blink::WebInputElement;
42 using blink::WebLabelElement;
43 using blink::WebNode;
44 using blink::WebNodeList;
45 using blink::WebOptionElement;
46 using blink::WebSelectElement;
47 using blink::WebTextAreaElement;
48 using blink::WebString;
49 using blink::WebVector;
51 namespace autofill {
52 namespace {
54 // A bit field mask for FillForm functions to not fill some fields.
55 enum FieldFilterMask {
56 FILTER_NONE = 0,
57 FILTER_DISABLED_ELEMENTS = 1 << 0,
58 FILTER_READONLY_ELEMENTS = 1 << 1,
59 FILTER_NON_FOCUSABLE_ELEMENTS = 1 << 2,
60 FILTER_ALL_NON_EDITABLE_ELEMENTS = FILTER_DISABLED_ELEMENTS |
61 FILTER_READONLY_ELEMENTS |
62 FILTER_NON_FOCUSABLE_ELEMENTS,
65 RequirementsMask ExtractionRequirements() {
66 return base::CommandLine::ForCurrentProcess()->HasSwitch(
67 switches::kRespectAutocompleteOffForAutofill)
68 ? REQUIRE_AUTOCOMPLETE
69 : REQUIRE_NONE;
72 void TruncateString(base::string16* str, size_t max_length) {
73 if (str->length() > max_length)
74 str->resize(max_length);
77 bool IsOptionElement(const WebElement& element) {
78 CR_DEFINE_STATIC_LOCAL(WebString, kOption, ("option"));
79 return element.hasHTMLTagName(kOption);
82 bool IsScriptElement(const WebElement& element) {
83 CR_DEFINE_STATIC_LOCAL(WebString, kScript, ("script"));
84 return element.hasHTMLTagName(kScript);
87 bool IsNoScriptElement(const WebElement& element) {
88 CR_DEFINE_STATIC_LOCAL(WebString, kNoScript, ("noscript"));
89 return element.hasHTMLTagName(kNoScript);
92 bool HasTagName(const WebNode& node, const blink::WebString& tag) {
93 return node.isElementNode() && node.toConst<WebElement>().hasHTMLTagName(tag);
96 bool IsAutofillableElement(const WebFormControlElement& element) {
97 const WebInputElement* input_element = toWebInputElement(&element);
98 return IsAutofillableInputElement(input_element) ||
99 IsSelectElement(element) ||
100 IsTextAreaElement(element);
103 bool IsElementInControlElementSet(
104 const WebElement& element,
105 const std::vector<WebFormControlElement>& control_elements) {
106 if (!element.isFormControlElement())
107 return false;
108 const WebFormControlElement form_control_element =
109 element.toConst<WebFormControlElement>();
110 return std::find(control_elements.begin(),
111 control_elements.end(),
112 form_control_element) != control_elements.end();
115 bool IsElementInsideFormOrFieldSet(const WebElement& element) {
116 for (WebNode parent_node = element.parentNode();
117 !parent_node.isNull();
118 parent_node = parent_node.parentNode()) {
119 if (!parent_node.isElementNode())
120 continue;
122 WebElement cur_element = parent_node.to<WebElement>();
123 if (cur_element.hasHTMLTagName("form") ||
124 cur_element.hasHTMLTagName("fieldset")) {
125 return true;
128 return false;
131 // Check whether the given field satisfies the REQUIRE_AUTOCOMPLETE requirement.
132 bool SatisfiesRequireAutocomplete(const WebInputElement& input_element) {
133 return input_element.autoComplete();
136 // Appends |suffix| to |prefix| so that any intermediary whitespace is collapsed
137 // to a single space. If |force_whitespace| is true, then the resulting string
138 // is guaranteed to have a space between |prefix| and |suffix|. Otherwise, the
139 // result includes a space only if |prefix| has trailing whitespace or |suffix|
140 // has leading whitespace.
141 // A few examples:
142 // * CombineAndCollapseWhitespace("foo", "bar", false) -> "foobar"
143 // * CombineAndCollapseWhitespace("foo", "bar", true) -> "foo bar"
144 // * CombineAndCollapseWhitespace("foo ", "bar", false) -> "foo bar"
145 // * CombineAndCollapseWhitespace("foo", " bar", false) -> "foo bar"
146 // * CombineAndCollapseWhitespace("foo", " bar", true) -> "foo bar"
147 // * CombineAndCollapseWhitespace("foo ", " bar", false) -> "foo bar"
148 // * CombineAndCollapseWhitespace(" foo", "bar ", false) -> " foobar "
149 // * CombineAndCollapseWhitespace(" foo", "bar ", true) -> " foo bar "
150 const base::string16 CombineAndCollapseWhitespace(
151 const base::string16& prefix,
152 const base::string16& suffix,
153 bool force_whitespace) {
154 base::string16 prefix_trimmed;
155 base::TrimPositions prefix_trailing_whitespace =
156 base::TrimWhitespace(prefix, base::TRIM_TRAILING, &prefix_trimmed);
158 // Recursively compute the children's text.
159 base::string16 suffix_trimmed;
160 base::TrimPositions suffix_leading_whitespace =
161 base::TrimWhitespace(suffix, base::TRIM_LEADING, &suffix_trimmed);
163 if (prefix_trailing_whitespace || suffix_leading_whitespace ||
164 force_whitespace) {
165 return prefix_trimmed + base::ASCIIToUTF16(" ") + suffix_trimmed;
166 } else {
167 return prefix_trimmed + suffix_trimmed;
171 // This is a helper function for the FindChildText() function (see below).
172 // Search depth is limited with the |depth| parameter.
173 // |divs_to_skip| is a list of <div> tags to ignore if encountered.
174 base::string16 FindChildTextInner(const WebNode& node,
175 int depth,
176 const std::set<WebNode>& divs_to_skip) {
177 if (depth <= 0 || node.isNull())
178 return base::string16();
180 // Skip over comments.
181 if (node.nodeType() == WebNode::CommentNode)
182 return FindChildTextInner(node.nextSibling(), depth - 1, divs_to_skip);
184 if (node.nodeType() != WebNode::ElementNode &&
185 node.nodeType() != WebNode::TextNode)
186 return base::string16();
188 // Ignore elements known not to contain inferable labels.
189 if (node.isElementNode()) {
190 const WebElement element = node.toConst<WebElement>();
191 if (IsOptionElement(element) ||
192 IsScriptElement(element) ||
193 IsNoScriptElement(element) ||
194 (element.isFormControlElement() &&
195 IsAutofillableElement(element.toConst<WebFormControlElement>()))) {
196 return base::string16();
199 if (element.hasHTMLTagName("div") && ContainsKey(divs_to_skip, node))
200 return base::string16();
203 // Extract the text exactly at this node.
204 base::string16 node_text = node.nodeValue();
206 // Recursively compute the children's text.
207 // Preserve inter-element whitespace separation.
208 base::string16 child_text =
209 FindChildTextInner(node.firstChild(), depth - 1, divs_to_skip);
210 bool add_space = node.nodeType() == WebNode::TextNode && node_text.empty();
211 node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space);
213 // Recursively compute the siblings' text.
214 // Again, preserve inter-element whitespace separation.
215 base::string16 sibling_text =
216 FindChildTextInner(node.nextSibling(), depth - 1, divs_to_skip);
217 add_space = node.nodeType() == WebNode::TextNode && node_text.empty();
218 node_text = CombineAndCollapseWhitespace(node_text, sibling_text, add_space);
220 return node_text;
223 // Same as FindChildText() below, but with a list of div nodes to skip.
224 // TODO(thestig): See if other FindChildText() callers can benefit from this.
225 base::string16 FindChildTextWithIgnoreList(
226 const WebNode& node,
227 const std::set<WebNode>& divs_to_skip) {
228 if (node.isTextNode())
229 return node.nodeValue();
231 WebNode child = node.firstChild();
233 const int kChildSearchDepth = 10;
234 base::string16 node_text =
235 FindChildTextInner(child, kChildSearchDepth, divs_to_skip);
236 base::TrimWhitespace(node_text, base::TRIM_ALL, &node_text);
237 return node_text;
240 // Returns the aggregated values of the descendants of |element| that are
241 // non-empty text nodes. This is a faster alternative to |innerText()| for
242 // performance critical operations. It does a full depth-first search so can be
243 // used when the structure is not directly known. However, unlike with
244 // |innerText()|, the search depth and breadth are limited to a fixed threshold.
245 // Whitespace is trimmed from text accumulated at descendant nodes.
246 base::string16 FindChildText(const WebNode& node) {
247 return FindChildTextWithIgnoreList(node, std::set<WebNode>());
250 // Shared function for InferLabelFromPrevious() and InferLabelFromNext().
251 base::string16 InferLabelFromSibling(const WebFormControlElement& element,
252 bool forward) {
253 base::string16 inferred_label;
254 WebNode sibling = element;
255 while (true) {
256 sibling = forward ? sibling.nextSibling() : sibling.previousSibling();
257 if (sibling.isNull())
258 break;
260 // Skip over comments.
261 WebNode::NodeType node_type = sibling.nodeType();
262 if (node_type == WebNode::CommentNode)
263 continue;
265 // Otherwise, only consider normal HTML elements and their contents.
266 if (node_type != WebNode::TextNode &&
267 node_type != WebNode::ElementNode)
268 break;
270 // A label might be split across multiple "lightweight" nodes.
271 // Coalesce any text contained in multiple consecutive
272 // (a) plain text nodes or
273 // (b) inline HTML elements that are essentially equivalent to text nodes.
274 CR_DEFINE_STATIC_LOCAL(WebString, kBold, ("b"));
275 CR_DEFINE_STATIC_LOCAL(WebString, kStrong, ("strong"));
276 CR_DEFINE_STATIC_LOCAL(WebString, kSpan, ("span"));
277 CR_DEFINE_STATIC_LOCAL(WebString, kFont, ("font"));
278 if (sibling.isTextNode() ||
279 HasTagName(sibling, kBold) || HasTagName(sibling, kStrong) ||
280 HasTagName(sibling, kSpan) || HasTagName(sibling, kFont)) {
281 base::string16 value = FindChildText(sibling);
282 // A text node's value will be empty if it is for a line break.
283 bool add_space = sibling.isTextNode() && value.empty();
284 inferred_label =
285 CombineAndCollapseWhitespace(value, inferred_label, add_space);
286 continue;
289 // If we have identified a partial label and have reached a non-lightweight
290 // element, consider the label to be complete.
291 base::string16 trimmed_label;
292 base::TrimWhitespace(inferred_label, base::TRIM_ALL, &trimmed_label);
293 if (!trimmed_label.empty())
294 break;
296 // <img> and <br> tags often appear between the input element and its
297 // label text, so skip over them.
298 CR_DEFINE_STATIC_LOCAL(WebString, kImage, ("img"));
299 CR_DEFINE_STATIC_LOCAL(WebString, kBreak, ("br"));
300 if (HasTagName(sibling, kImage) || HasTagName(sibling, kBreak))
301 continue;
303 // We only expect <p> and <label> tags to contain the full label text.
304 CR_DEFINE_STATIC_LOCAL(WebString, kPage, ("p"));
305 CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label"));
306 if (HasTagName(sibling, kPage) || HasTagName(sibling, kLabel))
307 inferred_label = FindChildText(sibling);
309 break;
312 base::TrimWhitespace(inferred_label, base::TRIM_ALL, &inferred_label);
313 return inferred_label;
316 // Helper for |InferLabelForElement()| that infers a label, if possible, from
317 // a previous sibling of |element|,
318 // e.g. Some Text <input ...>
319 // or Some <span>Text</span> <input ...>
320 // or <p>Some Text</p><input ...>
321 // or <label>Some Text</label> <input ...>
322 // or Some Text <img><input ...>
323 // or <b>Some Text</b><br/> <input ...>.
324 base::string16 InferLabelFromPrevious(const WebFormControlElement& element) {
325 return InferLabelFromSibling(element, false /* forward? */);
328 // Same as InferLabelFromPrevious(), but in the other direction.
329 // Useful for cases like: <span><input type="checkbox">Label For Checkbox</span>
330 base::string16 InferLabelFromNext(const WebFormControlElement& element) {
331 return InferLabelFromSibling(element, true /* forward? */);
334 // Helper for |InferLabelForElement()| that infers a label, if possible, from
335 // placeholder text,
336 base::string16 InferLabelFromPlaceholder(const WebFormControlElement& element) {
337 CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder"));
338 if (element.hasAttribute(kPlaceholder))
339 return element.getAttribute(kPlaceholder);
341 return base::string16();
344 // Helper for |InferLabelForElement()| that infers a label, if possible, from
345 // enclosing list item,
346 // e.g. <li>Some Text<input ...><input ...><input ...></tr>
347 base::string16 InferLabelFromListItem(const WebFormControlElement& element) {
348 WebNode parent = element.parentNode();
349 CR_DEFINE_STATIC_LOCAL(WebString, kListItem, ("li"));
350 while (!parent.isNull() && parent.isElementNode() &&
351 !parent.to<WebElement>().hasHTMLTagName(kListItem)) {
352 parent = parent.parentNode();
355 if (!parent.isNull() && HasTagName(parent, kListItem))
356 return FindChildText(parent);
358 return base::string16();
361 // Helper for |InferLabelForElement()| that infers a label, if possible, from
362 // surrounding table structure,
363 // e.g. <tr><td>Some Text</td><td><input ...></td></tr>
364 // or <tr><th>Some Text</th><td><input ...></td></tr>
365 // or <tr><td><b>Some Text</b></td><td><b><input ...></b></td></tr>
366 // or <tr><th><b>Some Text</b></th><td><b><input ...></b></td></tr>
367 base::string16 InferLabelFromTableColumn(const WebFormControlElement& element) {
368 CR_DEFINE_STATIC_LOCAL(WebString, kTableCell, ("td"));
369 WebNode parent = element.parentNode();
370 while (!parent.isNull() && parent.isElementNode() &&
371 !parent.to<WebElement>().hasHTMLTagName(kTableCell)) {
372 parent = parent.parentNode();
375 if (parent.isNull())
376 return base::string16();
378 // Check all previous siblings, skipping non-element nodes, until we find a
379 // non-empty text block.
380 base::string16 inferred_label;
381 WebNode previous = parent.previousSibling();
382 CR_DEFINE_STATIC_LOCAL(WebString, kTableHeader, ("th"));
383 while (inferred_label.empty() && !previous.isNull()) {
384 if (HasTagName(previous, kTableCell) || HasTagName(previous, kTableHeader))
385 inferred_label = FindChildText(previous);
387 previous = previous.previousSibling();
390 return inferred_label;
393 // Helper for |InferLabelForElement()| that infers a label, if possible, from
394 // surrounding table structure,
395 // e.g. <tr><td>Some Text</td></tr><tr><td><input ...></td></tr>
396 base::string16 InferLabelFromTableRow(const WebFormControlElement& element) {
397 CR_DEFINE_STATIC_LOCAL(WebString, kTableRow, ("tr"));
398 WebNode parent = element.parentNode();
399 while (!parent.isNull() && parent.isElementNode() &&
400 !parent.to<WebElement>().hasHTMLTagName(kTableRow)) {
401 parent = parent.parentNode();
404 if (parent.isNull())
405 return base::string16();
407 // Check all previous siblings, skipping non-element nodes, until we find a
408 // non-empty text block.
409 base::string16 inferred_label;
410 WebNode previous = parent.previousSibling();
411 while (inferred_label.empty() && !previous.isNull()) {
412 if (HasTagName(previous, kTableRow))
413 inferred_label = FindChildText(previous);
415 previous = previous.previousSibling();
418 return inferred_label;
421 // Helper for |InferLabelForElement()| that infers a label, if possible, from
422 // a surrounding div table,
423 // e.g. <div>Some Text<span><input ...></span></div>
424 // e.g. <div>Some Text</div><div><input ...></div>
425 base::string16 InferLabelFromDivTable(const WebFormControlElement& element) {
426 WebNode node = element.parentNode();
427 bool looking_for_parent = true;
428 std::set<WebNode> divs_to_skip;
430 // Search the sibling and parent <div>s until we find a candidate label.
431 base::string16 inferred_label;
432 CR_DEFINE_STATIC_LOCAL(WebString, kDiv, ("div"));
433 CR_DEFINE_STATIC_LOCAL(WebString, kTable, ("table"));
434 CR_DEFINE_STATIC_LOCAL(WebString, kFieldSet, ("fieldset"));
435 while (inferred_label.empty() && !node.isNull()) {
436 if (HasTagName(node, kDiv)) {
437 if (looking_for_parent)
438 inferred_label = FindChildTextWithIgnoreList(node, divs_to_skip);
439 else
440 inferred_label = FindChildText(node);
442 // Avoid sibling DIVs that contain autofillable fields.
443 if (!looking_for_parent && !inferred_label.empty()) {
444 CR_DEFINE_STATIC_LOCAL(WebString, kSelector,
445 ("input, select, textarea"));
446 blink::WebExceptionCode ec = 0;
447 WebElement result_element = node.querySelector(kSelector, ec);
448 if (!result_element.isNull()) {
449 inferred_label.clear();
450 divs_to_skip.insert(node);
454 looking_for_parent = false;
455 } else if (looking_for_parent &&
456 (HasTagName(node, kTable) || HasTagName(node, kFieldSet))) {
457 // If the element is in a table or fieldset, its label most likely is too.
458 break;
461 if (node.previousSibling().isNull()) {
462 // If there are no more siblings, continue walking up the tree.
463 looking_for_parent = true;
466 node = looking_for_parent ? node.parentNode() : node.previousSibling();
469 return inferred_label;
472 // Helper for |InferLabelForElement()| that infers a label, if possible, from
473 // a surrounding definition list,
474 // e.g. <dl><dt>Some Text</dt><dd><input ...></dd></dl>
475 // e.g. <dl><dt><b>Some Text</b></dt><dd><b><input ...></b></dd></dl>
476 base::string16 InferLabelFromDefinitionList(
477 const WebFormControlElement& element) {
478 CR_DEFINE_STATIC_LOCAL(WebString, kDefinitionData, ("dd"));
479 WebNode parent = element.parentNode();
480 while (!parent.isNull() && parent.isElementNode() &&
481 !parent.to<WebElement>().hasHTMLTagName(kDefinitionData))
482 parent = parent.parentNode();
484 if (parent.isNull() || !HasTagName(parent, kDefinitionData))
485 return base::string16();
487 // Skip by any intervening text nodes.
488 WebNode previous = parent.previousSibling();
489 while (!previous.isNull() && previous.isTextNode())
490 previous = previous.previousSibling();
492 CR_DEFINE_STATIC_LOCAL(WebString, kDefinitionTag, ("dt"));
493 if (previous.isNull() || !HasTagName(previous, kDefinitionTag))
494 return base::string16();
496 return FindChildText(previous);
499 // Returns true if the closest ancestor is a <div> and not a <td>.
500 // Returns false if the closest ancestor is a <td> tag,
501 // or if there is no <div> or <td> ancestor.
502 bool ClosestAncestorIsDivAndNotTD(const WebFormControlElement& element) {
503 for (WebNode parent_node = element.parentNode();
504 !parent_node.isNull();
505 parent_node = parent_node.parentNode()) {
506 if (!parent_node.isElementNode())
507 continue;
509 WebElement cur_element = parent_node.to<WebElement>();
510 if (cur_element.hasHTMLTagName("div"))
511 return true;
512 if (cur_element.hasHTMLTagName("td"))
513 return false;
515 return false;
518 // Infers corresponding label for |element| from surrounding context in the DOM,
519 // e.g. the contents of the preceding <p> tag or text element.
520 base::string16 InferLabelForElement(const WebFormControlElement& element) {
521 base::string16 inferred_label;
522 if (IsCheckableElement(toWebInputElement(&element))) {
523 inferred_label = InferLabelFromNext(element);
524 if (!inferred_label.empty())
525 return inferred_label;
528 inferred_label = InferLabelFromPrevious(element);
529 if (!inferred_label.empty())
530 return inferred_label;
532 // If we didn't find a label, check for placeholder text.
533 inferred_label = InferLabelFromPlaceholder(element);
534 if (!inferred_label.empty())
535 return inferred_label;
537 // If we didn't find a label, check for list item case.
538 inferred_label = InferLabelFromListItem(element);
539 if (!inferred_label.empty())
540 return inferred_label;
542 // If we didn't find a label, check for definition list case.
543 inferred_label = InferLabelFromDefinitionList(element);
544 if (!inferred_label.empty())
545 return inferred_label;
547 bool check_div_first = ClosestAncestorIsDivAndNotTD(element);
548 if (check_div_first) {
549 // If we didn't find a label, check for div table case first since it's the
550 // closest ancestor.
551 inferred_label = InferLabelFromDivTable(element);
552 if (!inferred_label.empty())
553 return inferred_label;
556 // If we didn't find a label, check for table cell case.
557 inferred_label = InferLabelFromTableColumn(element);
558 if (!inferred_label.empty())
559 return inferred_label;
561 // If we didn't find a label, check for table row case.
562 inferred_label = InferLabelFromTableRow(element);
563 if (!inferred_label.empty())
564 return inferred_label;
566 if (!check_div_first) {
567 // If we didn't find a label from the table, check for div table case if we
568 // haven't already.
569 inferred_label = InferLabelFromDivTable(element);
571 return inferred_label;
574 // Fills |option_strings| with the values of the <option> elements present in
575 // |select_element|.
576 void GetOptionStringsFromElement(const WebSelectElement& select_element,
577 std::vector<base::string16>* option_values,
578 std::vector<base::string16>* option_contents) {
579 DCHECK(!select_element.isNull());
581 option_values->clear();
582 option_contents->clear();
583 WebVector<WebElement> list_items = select_element.listItems();
585 // Constrain the maximum list length to prevent a malicious site from DOS'ing
586 // the browser, without entirely breaking autocomplete for some extreme
587 // legitimate sites: http://crbug.com/49332 and http://crbug.com/363094
588 if (list_items.size() > kMaxListSize)
589 return;
591 option_values->reserve(list_items.size());
592 option_contents->reserve(list_items.size());
593 for (size_t i = 0; i < list_items.size(); ++i) {
594 if (IsOptionElement(list_items[i])) {
595 const WebOptionElement option = list_items[i].toConst<WebOptionElement>();
596 option_values->push_back(option.value());
597 option_contents->push_back(option.text());
602 // The callback type used by |ForEachMatchingFormField()|.
603 typedef void (*Callback)(const FormFieldData&,
604 bool, /* is_initiating_element */
605 blink::WebFormControlElement*);
607 void ForEachMatchingFormFieldCommon(
608 std::vector<WebFormControlElement>* control_elements,
609 const WebElement& initiating_element,
610 const FormData& data,
611 FieldFilterMask filters,
612 bool force_override,
613 Callback callback) {
614 DCHECK(control_elements);
615 if (control_elements->size() != data.fields.size()) {
616 // This case should be reachable only for pathological websites and tests,
617 // which add or remove form fields while the user is interacting with the
618 // Autofill popup.
619 return;
622 // It's possible that the site has injected fields into the form after the
623 // page has loaded, so we can't assert that the size of the cached control
624 // elements is equal to the size of the fields in |form|. Fortunately, the
625 // one case in the wild where this happens, paypal.com signup form, the fields
626 // are appended to the end of the form and are not visible.
627 for (size_t i = 0; i < control_elements->size(); ++i) {
628 WebFormControlElement* element = &(*control_elements)[i];
630 if (base::string16(element->nameForAutofill()) != data.fields[i].name) {
631 // This case should be reachable only for pathological websites, which
632 // rename form fields while the user is interacting with the Autofill
633 // popup. I (isherman) am not aware of any such websites, and so am
634 // optimistically including a NOTREACHED(). If you ever trip this check,
635 // please file a bug against me.
636 NOTREACHED();
637 continue;
640 bool is_initiating_element = (*element == initiating_element);
642 // Only autofill empty fields and the field that initiated the filling,
643 // i.e. the field the user is currently editing and interacting with.
644 const WebInputElement* input_element = toWebInputElement(element);
645 if (!force_override && !is_initiating_element &&
646 ((IsAutofillableInputElement(input_element) ||
647 IsTextAreaElement(*element)) &&
648 !element->value().isEmpty()))
649 continue;
651 if (((filters & FILTER_DISABLED_ELEMENTS) && !element->isEnabled()) ||
652 ((filters & FILTER_READONLY_ELEMENTS) && element->isReadOnly()) ||
653 ((filters & FILTER_NON_FOCUSABLE_ELEMENTS) && !element->isFocusable()))
654 continue;
656 callback(data.fields[i], is_initiating_element, element);
660 // For each autofillable field in |data| that matches a field in the |form|,
661 // the |callback| is invoked with the corresponding |form| field data.
662 void ForEachMatchingFormField(const WebFormElement& form_element,
663 const WebElement& initiating_element,
664 const FormData& data,
665 FieldFilterMask filters,
666 bool force_override,
667 Callback callback) {
668 std::vector<WebFormControlElement> control_elements =
669 ExtractAutofillableElementsInForm(form_element, ExtractionRequirements());
670 ForEachMatchingFormFieldCommon(&control_elements, initiating_element, data,
671 filters, force_override, callback);
674 // For each autofillable field in |data| that matches a field in the set of
675 // unowned autofillable form fields, the |callback| is invoked with the
676 // corresponding |data| field.
677 void ForEachMatchingUnownedFormField(const WebElement& initiating_element,
678 const FormData& data,
679 FieldFilterMask filters,
680 bool force_override,
681 Callback callback) {
682 if (initiating_element.isNull())
683 return;
685 std::vector<WebFormControlElement> control_elements =
686 GetUnownedAutofillableFormFieldElements(
687 initiating_element.document().all(), nullptr);
688 if (!IsElementInControlElementSet(initiating_element, control_elements))
689 return;
691 ForEachMatchingFormFieldCommon(&control_elements, initiating_element, data,
692 filters, force_override, callback);
695 // Sets the |field|'s value to the value in |data|.
696 // Also sets the "autofilled" attribute, causing the background to be yellow.
697 void FillFormField(const FormFieldData& data,
698 bool is_initiating_node,
699 blink::WebFormControlElement* field) {
700 // Nothing to fill.
701 if (data.value.empty())
702 return;
704 if (!data.is_autofilled)
705 return;
707 WebInputElement* input_element = toWebInputElement(field);
708 if (IsCheckableElement(input_element)) {
709 input_element->setChecked(data.is_checked, true);
710 } else {
711 base::string16 value = data.value;
712 if (IsTextInput(input_element) || IsMonthInput(input_element)) {
713 // If the maxlength attribute contains a negative value, maxLength()
714 // returns the default maxlength value.
715 TruncateString(&value, input_element->maxLength());
717 field->setValue(value, true);
720 field->setAutofilled(true);
722 if (is_initiating_node &&
723 ((IsTextInput(input_element) || IsMonthInput(input_element)) ||
724 IsTextAreaElement(*field))) {
725 int length = field->value().length();
726 field->setSelectionRange(length, length);
727 // Clear the current IME composition (the underline), if there is one.
728 field->document().frame()->unmarkText();
732 // Sets the |field|'s "suggested" (non JS visible) value to the value in |data|.
733 // Also sets the "autofilled" attribute, causing the background to be yellow.
734 void PreviewFormField(const FormFieldData& data,
735 bool is_initiating_node,
736 blink::WebFormControlElement* field) {
737 // Nothing to preview.
738 if (data.value.empty())
739 return;
741 if (!data.is_autofilled)
742 return;
744 // Preview input, textarea and select fields. For input fields, excludes
745 // checkboxes and radio buttons, as there is no provision for
746 // setSuggestedCheckedValue in WebInputElement.
747 WebInputElement* input_element = toWebInputElement(field);
748 if (IsTextInput(input_element) || IsMonthInput(input_element)) {
749 // If the maxlength attribute contains a negative value, maxLength()
750 // returns the default maxlength value.
751 input_element->setSuggestedValue(
752 data.value.substr(0, input_element->maxLength()));
753 input_element->setAutofilled(true);
754 } else if (IsTextAreaElement(*field) || IsSelectElement(*field)) {
755 field->setSuggestedValue(data.value);
756 field->setAutofilled(true);
759 if (is_initiating_node &&
760 (IsTextInput(input_element) || IsTextAreaElement(*field))) {
761 // Select the part of the text that the user didn't type.
762 int start = field->value().length();
763 int end = field->suggestedValue().length();
764 field->setSelectionRange(start, end);
768 // Recursively checks whether |node| or any of its children have a non-empty
769 // bounding box. The recursion depth is bounded by |depth|.
770 bool IsWebNodeVisibleImpl(const blink::WebNode& node, const int depth) {
771 if (depth < 0)
772 return false;
773 if (node.hasNonEmptyBoundingBox())
774 return true;
776 // The childNodes method is not a const method. Therefore it cannot be called
777 // on a const reference. Therefore we need a const cast.
778 const blink::WebNodeList& children =
779 const_cast<blink::WebNode&>(node).childNodes();
780 size_t length = children.length();
781 for (size_t i = 0; i < length; ++i) {
782 const blink::WebNode& item = children.item(i);
783 if (IsWebNodeVisibleImpl(item, depth - 1))
784 return true;
786 return false;
789 bool ExtractFieldsFromControlElements(
790 const WebVector<WebFormControlElement>& control_elements,
791 RequirementsMask requirements,
792 ExtractMask extract_mask,
793 ScopedVector<FormFieldData>* form_fields,
794 std::vector<bool>* fields_extracted,
795 std::map<WebFormControlElement, FormFieldData*>* element_map) {
796 for (size_t i = 0; i < control_elements.size(); ++i) {
797 const WebFormControlElement& control_element = control_elements[i];
799 if (!IsAutofillableElement(control_element))
800 continue;
802 const WebInputElement* input_element = toWebInputElement(&control_element);
803 if (requirements & REQUIRE_AUTOCOMPLETE &&
804 IsAutofillableInputElement(input_element) &&
805 !SatisfiesRequireAutocomplete(*input_element))
806 continue;
808 // Create a new FormFieldData, fill it out and map it to the field's name.
809 FormFieldData* form_field = new FormFieldData;
810 WebFormControlElementToFormField(control_element, extract_mask, form_field);
811 form_fields->push_back(form_field);
812 (*element_map)[control_element] = form_field;
813 (*fields_extracted)[i] = true;
816 // If we failed to extract any fields, give up. Also, to avoid overly
817 // expensive computation, we impose a maximum number of allowable fields.
818 if (form_fields->empty() || form_fields->size() > kMaxParseableFields)
819 return false;
820 return true;
823 // For each label element, get the corresponding form control element, use the
824 // form control element's name as a key into the
825 // <WebFormControlElement, FormFieldData> map to find the previously created
826 // FormFieldData and set the FormFieldData's label to the
827 // label.firstChild().nodeValue() of the label element.
828 void MatchLabelsAndFields(
829 const WebElementCollection& labels,
830 std::map<WebFormControlElement, FormFieldData*>* element_map) {
831 CR_DEFINE_STATIC_LOCAL(WebString, kFor, ("for"));
832 CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden"));
834 for (WebElement item = labels.firstItem(); !item.isNull();
835 item = labels.nextItem()) {
836 WebLabelElement label = item.to<WebLabelElement>();
837 WebFormControlElement field_element =
838 label.correspondingControl().to<WebFormControlElement>();
839 FormFieldData* field_data = nullptr;
841 if (field_element.isNull()) {
842 // Sometimes site authors will incorrectly specify the corresponding
843 // field element's name rather than its id, so we compensate here.
844 base::string16 element_name = label.getAttribute(kFor);
845 if (element_name.empty())
846 continue;
847 // Look through the list for elements with this name. There can actually
848 // be more than one. In this case, the label may not be particularly
849 // useful, so just discard it.
850 for (const auto& iter : *element_map) {
851 if (iter.second->name == element_name) {
852 if (field_data) {
853 field_data = nullptr;
854 break;
855 } else {
856 field_data = iter.second;
860 } else if (!field_element.isFormControlElement() ||
861 field_element.formControlType() == kHidden) {
862 continue;
863 } else {
864 // Typical case: look up |field_data| in |element_map|.
865 auto iter = element_map->find(field_element);
866 if (iter == element_map->end())
867 continue;
868 field_data = iter->second;
871 if (!field_data)
872 continue;
874 base::string16 label_text = FindChildText(label);
876 // Concatenate labels because some sites might have multiple label
877 // candidates.
878 if (!field_data->label.empty() && !label_text.empty())
879 field_data->label += base::ASCIIToUTF16(" ");
880 field_data->label += label_text;
884 // Common function shared by WebFormElementToFormData() and
885 // UnownedFormElementsAndFieldSetsToFormData(). Either pass in:
886 // 1) |form_element| and an empty |fieldsets|.
887 // or
888 // 2) a NULL |form_element|.
890 // If |field| is not NULL, then |form_control_element| should be not NULL.
891 bool FormOrFieldsetsToFormData(
892 const blink::WebFormElement* form_element,
893 const blink::WebFormControlElement* form_control_element,
894 const std::vector<blink::WebElement>& fieldsets,
895 const WebVector<WebFormControlElement>& control_elements,
896 RequirementsMask requirements,
897 ExtractMask extract_mask,
898 FormData* form,
899 FormFieldData* field) {
900 CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label"));
902 if (form_element)
903 DCHECK(fieldsets.empty());
904 if (field)
905 DCHECK(form_control_element);
907 // A map from a FormFieldData's name to the FormFieldData itself.
908 std::map<WebFormControlElement, FormFieldData*> element_map;
910 // The extracted FormFields. We use pointers so we can store them in
911 // |element_map|.
912 ScopedVector<FormFieldData> form_fields;
914 // A vector of bools that indicate whether each field in the form meets the
915 // requirements and thus will be in the resulting |form|.
916 std::vector<bool> fields_extracted(control_elements.size(), false);
918 if (!ExtractFieldsFromControlElements(control_elements, requirements,
919 extract_mask, &form_fields,
920 &fields_extracted, &element_map)) {
921 return false;
924 if (form_element) {
925 // Loop through the label elements inside the form element. For each label
926 // element, get the corresponding form control element, use the form control
927 // element's name as a key into the <name, FormFieldData> map to find the
928 // previously created FormFieldData and set the FormFieldData's label to the
929 // label.firstChild().nodeValue() of the label element.
930 WebElementCollection labels =
931 form_element->getElementsByHTMLTagName(kLabel);
932 DCHECK(!labels.isNull());
933 MatchLabelsAndFields(labels, &element_map);
934 } else {
935 // Same as the if block, but for all the labels in fieldsets.
936 for (size_t i = 0; i < fieldsets.size(); ++i) {
937 WebElementCollection labels =
938 fieldsets[i].getElementsByHTMLTagName(kLabel);
939 DCHECK(!labels.isNull());
940 MatchLabelsAndFields(labels, &element_map);
944 // Loop through the form control elements, extracting the label text from
945 // the DOM. We use the |fields_extracted| vector to make sure we assign the
946 // extracted label to the correct field, as it's possible |form_fields| will
947 // not contain all of the elements in |control_elements|.
948 for (size_t i = 0, field_idx = 0;
949 i < control_elements.size() && field_idx < form_fields.size(); ++i) {
950 // This field didn't meet the requirements, so don't try to find a label
951 // for it.
952 if (!fields_extracted[i])
953 continue;
955 const WebFormControlElement& control_element = control_elements[i];
956 if (form_fields[field_idx]->label.empty())
957 form_fields[field_idx]->label = InferLabelForElement(control_element);
958 TruncateString(&form_fields[field_idx]->label, kMaxDataLength);
960 if (field && *form_control_element == control_element)
961 *field = *form_fields[field_idx];
963 ++field_idx;
966 // Copy the created FormFields into the resulting FormData object.
967 for (const auto& iter : form_fields)
968 form->fields.push_back(*iter);
969 return true;
972 } // namespace
974 const size_t kMaxParseableFields = 200;
976 bool IsMonthInput(const WebInputElement* element) {
977 CR_DEFINE_STATIC_LOCAL(WebString, kMonth, ("month"));
978 return element && !element->isNull() && element->formControlType() == kMonth;
981 // All text fields, including password fields, should be extracted.
982 bool IsTextInput(const WebInputElement* element) {
983 return element && !element->isNull() && element->isTextField();
986 bool IsSelectElement(const WebFormControlElement& element) {
987 // Static for improved performance.
988 CR_DEFINE_STATIC_LOCAL(WebString, kSelectOne, ("select-one"));
989 return !element.isNull() && element.formControlType() == kSelectOne;
992 bool IsTextAreaElement(const WebFormControlElement& element) {
993 // Static for improved performance.
994 CR_DEFINE_STATIC_LOCAL(WebString, kTextArea, ("textarea"));
995 return !element.isNull() && element.formControlType() == kTextArea;
998 bool IsCheckableElement(const WebInputElement* element) {
999 if (!element || element->isNull())
1000 return false;
1002 return element->isCheckbox() || element->isRadioButton();
1005 bool IsAutofillableInputElement(const WebInputElement* element) {
1006 return IsTextInput(element) ||
1007 IsMonthInput(element) ||
1008 IsCheckableElement(element);
1011 const base::string16 GetFormIdentifier(const WebFormElement& form) {
1012 base::string16 identifier = form.name();
1013 CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id"));
1014 if (identifier.empty())
1015 identifier = form.getAttribute(kId);
1017 return identifier;
1020 bool IsWebNodeVisible(const blink::WebNode& node) {
1021 // In the bug http://crbug.com/237216 the form's bounding box is empty
1022 // however the form has non empty children. Thus we need to look at the
1023 // form's children.
1024 int kNodeSearchDepth = 2;
1025 return IsWebNodeVisibleImpl(node, kNodeSearchDepth);
1028 std::vector<blink::WebFormControlElement> ExtractAutofillableElementsFromSet(
1029 const WebVector<WebFormControlElement>& control_elements,
1030 RequirementsMask requirements) {
1031 std::vector<blink::WebFormControlElement> autofillable_elements;
1032 for (size_t i = 0; i < control_elements.size(); ++i) {
1033 WebFormControlElement element = control_elements[i];
1034 if (!IsAutofillableElement(element))
1035 continue;
1037 if (requirements & REQUIRE_AUTOCOMPLETE) {
1038 // TODO(isherman): WebKit currently doesn't handle the autocomplete
1039 // attribute for select or textarea elements, but it probably should.
1040 const WebInputElement* input_element =
1041 toWebInputElement(&control_elements[i]);
1042 if (IsAutofillableInputElement(input_element) &&
1043 !SatisfiesRequireAutocomplete(*input_element))
1044 continue;
1047 autofillable_elements.push_back(element);
1049 return autofillable_elements;
1052 std::vector<WebFormControlElement> ExtractAutofillableElementsInForm(
1053 const WebFormElement& form_element,
1054 RequirementsMask requirements) {
1055 WebVector<WebFormControlElement> control_elements;
1056 form_element.getFormControlElements(control_elements);
1058 return ExtractAutofillableElementsFromSet(control_elements, requirements);
1061 void WebFormControlElementToFormField(const WebFormControlElement& element,
1062 ExtractMask extract_mask,
1063 FormFieldData* field) {
1064 DCHECK(field);
1065 DCHECK(!element.isNull());
1066 CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete"));
1067 CR_DEFINE_STATIC_LOCAL(WebString, kRole, ("role"));
1069 // The label is not officially part of a WebFormControlElement; however, the
1070 // labels for all form control elements are scraped from the DOM and set in
1071 // WebFormElementToFormData.
1072 field->name = element.nameForAutofill();
1073 field->form_control_type = base::UTF16ToUTF8(element.formControlType());
1074 field->autocomplete_attribute =
1075 base::UTF16ToUTF8(element.getAttribute(kAutocomplete));
1076 if (field->autocomplete_attribute.size() > kMaxDataLength) {
1077 // Discard overly long attribute values to avoid DOS-ing the browser
1078 // process. However, send over a default string to indicate that the
1079 // attribute was present.
1080 field->autocomplete_attribute = "x-max-data-length-exceeded";
1082 if (LowerCaseEqualsASCII(element.getAttribute(kRole), "presentation"))
1083 field->role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
1085 if (!IsAutofillableElement(element))
1086 return;
1088 const WebInputElement* input_element = toWebInputElement(&element);
1089 if (IsAutofillableInputElement(input_element) ||
1090 IsTextAreaElement(element)) {
1091 field->is_autofilled = element.isAutofilled();
1092 field->is_focusable = element.isFocusable();
1093 field->should_autocomplete = element.autoComplete();
1094 field->text_direction = element.directionForFormData() ==
1095 "rtl" ? base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
1098 if (IsAutofillableInputElement(input_element)) {
1099 if (IsTextInput(input_element))
1100 field->max_length = input_element->maxLength();
1102 field->is_checkable = IsCheckableElement(input_element);
1103 field->is_checked = input_element->isChecked();
1104 } else if (IsTextAreaElement(element)) {
1105 // Nothing more to do in this case.
1106 } else if (extract_mask & EXTRACT_OPTIONS) {
1107 // Set option strings on the field if available.
1108 DCHECK(IsSelectElement(element));
1109 const WebSelectElement select_element = element.toConst<WebSelectElement>();
1110 GetOptionStringsFromElement(select_element,
1111 &field->option_values,
1112 &field->option_contents);
1115 if (!(extract_mask & EXTRACT_VALUE))
1116 return;
1118 base::string16 value = element.value();
1120 if (IsSelectElement(element) && (extract_mask & EXTRACT_OPTION_TEXT)) {
1121 const WebSelectElement select_element = element.toConst<WebSelectElement>();
1122 // Convert the |select_element| value to text if requested.
1123 WebVector<WebElement> list_items = select_element.listItems();
1124 for (size_t i = 0; i < list_items.size(); ++i) {
1125 if (IsOptionElement(list_items[i])) {
1126 const WebOptionElement option_element =
1127 list_items[i].toConst<WebOptionElement>();
1128 if (option_element.value() == value) {
1129 value = option_element.text();
1130 break;
1136 // Constrain the maximum data length to prevent a malicious site from DOS'ing
1137 // the browser: http://crbug.com/49332
1138 TruncateString(&value, kMaxDataLength);
1140 field->value = value;
1143 bool WebFormElementToFormData(
1144 const blink::WebFormElement& form_element,
1145 const blink::WebFormControlElement& form_control_element,
1146 RequirementsMask requirements,
1147 ExtractMask extract_mask,
1148 FormData* form,
1149 FormFieldData* field) {
1150 const WebFrame* frame = form_element.document().frame();
1151 if (!frame)
1152 return false;
1154 if (requirements & REQUIRE_AUTOCOMPLETE && !form_element.autoComplete())
1155 return false;
1157 form->name = GetFormIdentifier(form_element);
1158 form->origin = frame->document().url();
1159 form->action = frame->document().completeURL(form_element.action());
1160 form->user_submitted = form_element.wasUserSubmitted();
1162 // If the completed URL is not valid, just use the action we get from
1163 // WebKit.
1164 if (!form->action.is_valid())
1165 form->action = GURL(form_element.action());
1167 WebVector<WebFormControlElement> control_elements;
1168 form_element.getFormControlElements(control_elements);
1170 std::vector<blink::WebElement> dummy_fieldset;
1171 return FormOrFieldsetsToFormData(&form_element, &form_control_element,
1172 dummy_fieldset, control_elements,
1173 requirements, extract_mask, form, field);
1176 std::vector<WebFormControlElement>
1177 GetUnownedAutofillableFormFieldElements(
1178 const WebElementCollection& elements,
1179 std::vector<WebElement>* fieldsets) {
1180 std::vector<WebFormControlElement> unowned_fieldset_children;
1181 for (WebElement element = elements.firstItem();
1182 !element.isNull();
1183 element = elements.nextItem()) {
1184 if (element.isFormControlElement()) {
1185 WebFormControlElement control = element.to<WebFormControlElement>();
1186 if (control.form().isNull())
1187 unowned_fieldset_children.push_back(control);
1190 if (fieldsets && element.hasHTMLTagName("fieldset") &&
1191 !IsElementInsideFormOrFieldSet(element)) {
1192 fieldsets->push_back(element);
1195 return ExtractAutofillableElementsFromSet(unowned_fieldset_children,
1196 REQUIRE_NONE);
1199 bool UnownedFormElementsAndFieldSetsToFormData(
1200 const std::vector<blink::WebElement>& fieldsets,
1201 const std::vector<blink::WebFormControlElement>& control_elements,
1202 const blink::WebFormControlElement* element,
1203 const GURL& origin,
1204 RequirementsMask requirements,
1205 ExtractMask extract_mask,
1206 FormData* form,
1207 FormFieldData* field) {
1208 form->origin = origin;
1209 form->user_submitted = false;
1210 form->is_form_tag = false;
1212 return FormOrFieldsetsToFormData(nullptr, element, fieldsets,
1213 control_elements, requirements, extract_mask,
1214 form, field);
1217 bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element,
1218 FormData* form,
1219 FormFieldData* field,
1220 RequirementsMask requirements) {
1221 if (!IsAutofillableElement(element))
1222 return false;
1224 ExtractMask extract_mask =
1225 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
1226 const WebFormElement form_element = element.form();
1227 if (form_element.isNull()) {
1228 // No associated form, try the synthetic form for unowned form elements.
1229 WebDocument document = element.document();
1230 std::vector<WebElement> fieldsets;
1231 std::vector<WebFormControlElement> control_elements =
1232 GetUnownedAutofillableFormFieldElements(document.all(), &fieldsets);
1233 return UnownedFormElementsAndFieldSetsToFormData(
1234 fieldsets, control_elements, &element, document.url(), requirements,
1235 extract_mask, form, field);
1238 return WebFormElementToFormData(form_element,
1239 element,
1240 requirements,
1241 extract_mask,
1242 form,
1243 field);
1246 void FillForm(const FormData& form, const WebFormControlElement& element) {
1247 WebFormElement form_element = element.form();
1248 if (form_element.isNull()) {
1249 ForEachMatchingUnownedFormField(element,
1250 form,
1251 FILTER_ALL_NON_EDITABLE_ELEMENTS,
1252 false, /* dont force override */
1253 &FillFormField);
1254 return;
1257 ForEachMatchingFormField(form_element,
1258 element,
1259 form,
1260 FILTER_ALL_NON_EDITABLE_ELEMENTS,
1261 false, /* dont force override */
1262 &FillFormField);
1265 void FillFormIncludingNonFocusableElements(const FormData& form_data,
1266 const WebFormElement& form_element) {
1267 if (form_element.isNull()) {
1268 NOTREACHED();
1269 return;
1272 FieldFilterMask filter_mask = static_cast<FieldFilterMask>(
1273 FILTER_DISABLED_ELEMENTS | FILTER_READONLY_ELEMENTS);
1274 ForEachMatchingFormField(form_element,
1275 WebInputElement(),
1276 form_data,
1277 filter_mask,
1278 true, /* force override */
1279 &FillFormField);
1282 void PreviewForm(const FormData& form, const WebFormControlElement& element) {
1283 WebFormElement form_element = element.form();
1284 if (form_element.isNull()) {
1285 ForEachMatchingUnownedFormField(element,
1286 form,
1287 FILTER_ALL_NON_EDITABLE_ELEMENTS,
1288 false, /* dont force override */
1289 &PreviewFormField);
1290 return;
1293 ForEachMatchingFormField(form_element,
1294 element,
1295 form,
1296 FILTER_ALL_NON_EDITABLE_ELEMENTS,
1297 false, /* dont force override */
1298 &PreviewFormField);
1301 bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
1302 bool was_autofilled) {
1303 WebFormElement form_element = element.form();
1304 std::vector<WebFormControlElement> control_elements;
1305 if (form_element.isNull()) {
1306 control_elements = GetUnownedAutofillableFormFieldElements(
1307 element.document().all(), nullptr);
1308 if (!IsElementInControlElementSet(element, control_elements))
1309 return false;
1310 } else {
1311 control_elements = ExtractAutofillableElementsInForm(
1312 form_element, ExtractionRequirements());
1315 for (size_t i = 0; i < control_elements.size(); ++i) {
1316 // There might be unrelated elements in this form which have already been
1317 // auto-filled. For example, the user might have already filled the address
1318 // part of a form and now be dealing with the credit card section. We only
1319 // want to reset the auto-filled status for fields that were previewed.
1320 WebFormControlElement control_element = control_elements[i];
1322 // Only text input, textarea and select elements can be previewed.
1323 WebInputElement* input_element = toWebInputElement(&control_element);
1324 if (!IsTextInput(input_element) &&
1325 !IsMonthInput(input_element) &&
1326 !IsTextAreaElement(control_element) &&
1327 !IsSelectElement(control_element))
1328 continue;
1330 // If the element is not auto-filled, we did not preview it,
1331 // so there is nothing to reset.
1332 if (!control_element.isAutofilled())
1333 continue;
1335 if ((IsTextInput(input_element) ||
1336 IsMonthInput(input_element) ||
1337 IsTextAreaElement(control_element) ||
1338 IsSelectElement(control_element)) &&
1339 control_element.suggestedValue().isEmpty())
1340 continue;
1342 // Clear the suggested value. For the initiating node, also restore the
1343 // original value.
1344 if (IsTextInput(input_element) || IsMonthInput(input_element) ||
1345 IsTextAreaElement(control_element)) {
1346 control_element.setSuggestedValue(WebString());
1347 bool is_initiating_node = (element == control_element);
1348 if (is_initiating_node) {
1349 control_element.setAutofilled(was_autofilled);
1350 // Clearing the suggested value in the focused node (above) can cause
1351 // selection to be lost. We force selection range to restore the text
1352 // cursor.
1353 int length = control_element.value().length();
1354 control_element.setSelectionRange(length, length);
1355 } else {
1356 control_element.setAutofilled(false);
1358 } else if (IsSelectElement(control_element)) {
1359 control_element.setSuggestedValue(WebString());
1360 control_element.setAutofilled(false);
1364 return true;
1367 bool IsWebpageEmpty(const blink::WebFrame* frame) {
1368 blink::WebDocument document = frame->document();
1370 return IsWebElementEmpty(document.head()) &&
1371 IsWebElementEmpty(document.body());
1374 bool IsWebElementEmpty(const blink::WebElement& element) {
1375 // This array contains all tags which can be present in an empty page.
1376 const char* const kAllowedValue[] = {
1377 "script",
1378 "meta",
1379 "title",
1381 const size_t kAllowedValueLength = arraysize(kAllowedValue);
1383 if (element.isNull())
1384 return true;
1385 // The childNodes method is not a const method. Therefore it cannot be called
1386 // on a const reference. Therefore we need a const cast.
1387 const blink::WebNodeList& children =
1388 const_cast<blink::WebElement&>(element).childNodes();
1389 for (size_t i = 0; i < children.length(); ++i) {
1390 const blink::WebNode& item = children.item(i);
1392 if (item.isTextNode() &&
1393 !base::ContainsOnlyChars(item.nodeValue().utf8(),
1394 base::kWhitespaceASCII))
1395 return false;
1397 // We ignore all other items with names which begin with
1398 // the character # because they are not html tags.
1399 if (item.nodeName().utf8()[0] == '#')
1400 continue;
1402 bool tag_is_allowed = false;
1403 // Test if the item name is in the kAllowedValue array
1404 for (size_t allowed_value_index = 0;
1405 allowed_value_index < kAllowedValueLength; ++allowed_value_index) {
1406 if (HasTagName(item,
1407 WebString::fromUTF8(kAllowedValue[allowed_value_index]))) {
1408 tag_is_allowed = true;
1409 break;
1412 if (!tag_is_allowed)
1413 return false;
1415 return true;
1418 gfx::RectF GetScaledBoundingBox(float scale, WebElement* element) {
1419 gfx::Rect bounding_box(element->boundsInViewportSpace());
1420 return gfx::RectF(bounding_box.x() * scale,
1421 bounding_box.y() * scale,
1422 bounding_box.width() * scale,
1423 bounding_box.height() * scale);
1426 } // namespace autofill