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_cache.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/autofill/content/renderer/form_autofill_util.h"
11 #include "components/autofill/core/common/autofill_constants.h"
12 #include "components/autofill/core/common/form_data_predictions.h"
13 #include "grit/components_strings.h"
14 #include "third_party/WebKit/public/platform/WebString.h"
15 #include "third_party/WebKit/public/platform/WebVector.h"
16 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
17 #include "third_party/WebKit/public/web/WebDocument.h"
18 #include "third_party/WebKit/public/web/WebFormControlElement.h"
19 #include "third_party/WebKit/public/web/WebFormElement.h"
20 #include "third_party/WebKit/public/web/WebInputElement.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebNodeList.h"
23 #include "third_party/WebKit/public/web/WebSelectElement.h"
24 #include "third_party/WebKit/public/web/WebTextAreaElement.h"
25 #include "ui/base/l10n/l10n_util.h"
27 using blink::WebConsoleMessage
;
28 using blink::WebDocument
;
29 using blink::WebElement
;
30 using blink::WebFormControlElement
;
31 using blink::WebFormElement
;
32 using blink::WebFrame
;
33 using blink::WebInputElement
;
35 using blink::WebSelectElement
;
36 using blink::WebString
;
37 using blink::WebTextAreaElement
;
38 using blink::WebVector
;
44 void LogDeprecationMessages(const WebFormControlElement
& element
) {
45 std::string autocomplete_attribute
=
46 base::UTF16ToUTF8(element
.getAttribute("autocomplete"));
48 static const char* const deprecated
[] = { "region", "locality" };
49 for (size_t i
= 0; i
< arraysize(deprecated
); ++i
) {
50 if (autocomplete_attribute
.find(deprecated
[i
]) == std::string::npos
)
52 std::string msg
= std::string("autocomplete='") + deprecated
[i
] +
53 "' is deprecated and will soon be ignored. See http://goo.gl/YjeSsW";
54 WebConsoleMessage console_message
= WebConsoleMessage(
55 WebConsoleMessage::LevelWarning
,
56 WebString(base::ASCIIToUTF16(msg
)));
57 element
.document().frame()->addMessageToConsole(console_message
);
61 // To avoid overly expensive computation, we impose a minimum number of
62 // allowable fields. The corresponding maximum number of allowable fields
63 // is imposed by WebFormElementToFormData().
64 bool ShouldIgnoreForm(size_t num_editable_elements
,
65 size_t num_control_elements
) {
66 return (num_editable_elements
< kRequiredAutofillFields
&&
67 num_control_elements
> 0);
72 FormCache::FormCache(const WebFrame
& frame
) : frame_(frame
) {
75 FormCache::~FormCache() {
78 std::vector
<FormData
> FormCache::ExtractNewForms() {
79 std::vector
<FormData
> forms
;
80 WebDocument document
= frame_
.document();
81 if (document
.isNull())
84 WebVector
<WebFormElement
> web_forms
;
85 document
.forms(web_forms
);
87 // Log an error message for deprecated attributes, but only the first time
88 // the form is parsed.
89 bool log_deprecation_messages
= parsed_forms_
.empty();
91 const ExtractMask extract_mask
=
92 static_cast<ExtractMask
>(EXTRACT_VALUE
| EXTRACT_OPTIONS
);
94 size_t num_fields_seen
= 0;
95 for (size_t i
= 0; i
< web_forms
.size(); ++i
) {
96 const WebFormElement
& form_element
= web_forms
[i
];
98 std::vector
<WebFormControlElement
> control_elements
=
99 ExtractAutofillableElementsInForm(form_element
, REQUIRE_NONE
);
100 size_t num_editable_elements
=
101 ScanFormControlElements(control_elements
, log_deprecation_messages
);
103 if (ShouldIgnoreForm(num_editable_elements
, control_elements
.size()))
107 if (!WebFormElementToFormData(form_element
, WebFormControlElement(),
108 REQUIRE_NONE
, extract_mask
, &form
, nullptr)) {
112 num_fields_seen
+= form
.fields
.size();
113 if (num_fields_seen
> kMaxParseableFields
)
116 if (form
.fields
.size() >= kRequiredAutofillFields
&&
117 !ContainsKey(parsed_forms_
, form
)) {
118 forms
.push_back(form
);
119 parsed_forms_
.insert(form
);
123 // Look for more parseable fields outside of forms.
124 std::vector
<WebElement
> fieldsets
;
125 std::vector
<WebFormControlElement
> control_elements
=
126 GetUnownedAutofillableFormFieldElements(document
.all(), &fieldsets
);
128 size_t num_editable_elements
=
129 ScanFormControlElements(control_elements
, log_deprecation_messages
);
131 if (ShouldIgnoreForm(num_editable_elements
, control_elements
.size()))
134 FormData synthetic_form
;
135 if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets
, control_elements
,
136 nullptr, document
.url(),
137 REQUIRE_NONE
, extract_mask
,
138 &synthetic_form
, nullptr)) {
142 num_fields_seen
+= synthetic_form
.fields
.size();
143 if (num_fields_seen
> kMaxParseableFields
)
146 if (synthetic_form
.fields
.size() >= kRequiredAutofillFields
&&
147 !parsed_forms_
.count(synthetic_form
)) {
148 forms
.push_back(synthetic_form
);
149 parsed_forms_
.insert(synthetic_form
);
150 synthetic_form_
= synthetic_form
;
155 void FormCache::Reset() {
156 synthetic_form_
= FormData();
157 parsed_forms_
.clear();
158 initial_select_values_
.clear();
159 initial_checked_state_
.clear();
162 bool FormCache::ClearFormWithElement(const WebFormControlElement
& element
) {
163 WebFormElement form_element
= element
.form();
164 std::vector
<WebFormControlElement
> control_elements
;
165 if (form_element
.isNull()) {
166 control_elements
= GetUnownedAutofillableFormFieldElements(
167 element
.document().all(), nullptr);
169 control_elements
= ExtractAutofillableElementsInForm(
170 form_element
, REQUIRE_NONE
);
172 for (size_t i
= 0; i
< control_elements
.size(); ++i
) {
173 WebFormControlElement control_element
= control_elements
[i
];
174 // Don't modify the value of disabled fields.
175 if (!control_element
.isEnabled())
178 // Don't clear field that was not autofilled
179 if (!control_element
.isAutofilled())
182 control_element
.setAutofilled(false);
184 WebInputElement
* input_element
= toWebInputElement(&control_element
);
185 if (IsTextInput(input_element
) || IsMonthInput(input_element
)) {
186 input_element
->setValue(base::string16(), true);
188 // Clearing the value in the focused node (above) can cause selection
189 // to be lost. We force selection range to restore the text cursor.
190 if (element
== *input_element
) {
191 int length
= input_element
->value().length();
192 input_element
->setSelectionRange(length
, length
);
194 } else if (IsTextAreaElement(control_element
)) {
195 control_element
.setValue(base::string16(), true);
196 } else if (IsSelectElement(control_element
)) {
197 WebSelectElement select_element
= control_element
.to
<WebSelectElement
>();
199 std::map
<const WebSelectElement
, base::string16
>::const_iterator
200 initial_value_iter
= initial_select_values_
.find(select_element
);
201 if (initial_value_iter
!= initial_select_values_
.end() &&
202 select_element
.value() != initial_value_iter
->second
) {
203 select_element
.setValue(initial_value_iter
->second
, true);
206 WebInputElement input_element
= control_element
.to
<WebInputElement
>();
207 DCHECK(IsCheckableElement(&input_element
));
208 std::map
<const WebInputElement
, bool>::const_iterator it
=
209 initial_checked_state_
.find(input_element
);
210 if (it
!= initial_checked_state_
.end() &&
211 input_element
.isChecked() != it
->second
) {
212 input_element
.setChecked(it
->second
, true);
220 bool FormCache::ShowPredictions(const FormDataPredictions
& form
) {
221 DCHECK_EQ(form
.data
.fields
.size(), form
.fields
.size());
223 std::vector
<WebFormControlElement
> control_elements
;
225 // First check the synthetic form.
226 bool found_synthetic_form
= false;
227 if (form
.data
.SameFormAs(synthetic_form_
)) {
228 found_synthetic_form
= true;
229 WebDocument document
= frame_
.document();
231 GetUnownedAutofillableFormFieldElements(document
.all(), nullptr);
234 if (!found_synthetic_form
) {
235 // Find the real form by searching through the WebDocuments.
236 bool found_form
= false;
237 WebFormElement form_element
;
238 WebVector
<WebFormElement
> web_forms
;
239 frame_
.document().forms(web_forms
);
241 for (size_t i
= 0; i
< web_forms
.size(); ++i
) {
242 form_element
= web_forms
[i
];
243 // Note: matching on the form name here which is not guaranteed to be
244 // unique for the page, nor is it guaranteed to be non-empty. Ideally,
245 // we would have a way to uniquely identify the form cross-process. For
246 // now, we'll check form name and form action for identity.
247 // Also note that WebString() == WebString(string16()) does not evaluate
248 // to |true| -- WebKit distinguishes between a "null" string (lhs) and
249 // an "empty" string (rhs). We don't want that distinction, so forcing
251 base::string16 element_name
= GetFormIdentifier(form_element
);
252 GURL
action(form_element
.document().completeURL(form_element
.action()));
253 if (element_name
== form
.data
.name
&& action
== form
.data
.action
) {
256 ExtractAutofillableElementsInForm(form_element
, REQUIRE_NONE
);
265 if (control_elements
.size() != form
.fields
.size()) {
266 // Keep things simple. Don't show predictions for forms that were modified
267 // between page load and the server's response to our query.
271 for (size_t i
= 0; i
< control_elements
.size(); ++i
) {
272 WebFormControlElement
& element
= control_elements
[i
];
274 if (base::string16(element
.nameForAutofill()) != form
.data
.fields
[i
].name
) {
275 // Keep things simple. Don't show predictions for elements whose names
276 // were modified between page load and the server's response to our query.
280 base::string16 title
= l10n_util::GetStringFUTF16(
281 IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE
,
282 base::UTF8ToUTF16(form
.fields
[i
].heuristic_type
),
283 base::UTF8ToUTF16(form
.fields
[i
].server_type
),
284 base::UTF8ToUTF16(form
.fields
[i
].signature
),
285 base::UTF8ToUTF16(form
.signature
),
286 base::UTF8ToUTF16(form
.experiment_id
));
287 element
.setAttribute("title", WebString(title
));
293 size_t FormCache::ScanFormControlElements(
294 const std::vector
<WebFormControlElement
>& control_elements
,
295 bool log_deprecation_messages
) {
296 size_t num_editable_elements
= 0;
297 for (size_t i
= 0; i
< control_elements
.size(); ++i
) {
298 const WebFormControlElement
& element
= control_elements
[i
];
300 if (log_deprecation_messages
)
301 LogDeprecationMessages(element
);
303 // Save original values of <select> elements so we can restore them
304 // when |ClearFormWithNode()| is invoked.
305 if (IsSelectElement(element
)) {
306 const WebSelectElement select_element
=
307 element
.toConst
<WebSelectElement
>();
308 initial_select_values_
.insert(
309 std::make_pair(select_element
, select_element
.value()));
310 ++num_editable_elements
;
311 } else if (IsTextAreaElement(element
)) {
312 ++num_editable_elements
;
314 const WebInputElement input_element
=
315 element
.toConst
<WebInputElement
>();
316 if (IsCheckableElement(&input_element
)) {
317 initial_checked_state_
.insert(
318 std::make_pair(input_element
, input_element
.isChecked()));
320 ++num_editable_elements
;
324 return num_editable_elements
;
327 } // namespace autofill