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/strings/utf_string_conversions.h"
9 #include "components/autofill/content/renderer/form_autofill_util.h"
10 #include "components/autofill/core/common/autofill_constants.h"
11 #include "components/autofill/core/common/form_data.h"
12 #include "components/autofill/core/common/form_data_predictions.h"
13 #include "components/autofill/core/common/form_field_data.h"
14 #include "components/autofill/core/common/form_field_data_predictions.h"
15 #include "grit/components_strings.h"
16 #include "third_party/WebKit/public/platform/WebString.h"
17 #include "third_party/WebKit/public/platform/WebVector.h"
18 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
19 #include "third_party/WebKit/public/web/WebDocument.h"
20 #include "third_party/WebKit/public/web/WebFormControlElement.h"
21 #include "third_party/WebKit/public/web/WebFormElement.h"
22 #include "third_party/WebKit/public/web/WebInputElement.h"
23 #include "third_party/WebKit/public/web/WebLocalFrame.h"
24 #include "third_party/WebKit/public/web/WebNodeList.h"
25 #include "third_party/WebKit/public/web/WebSelectElement.h"
26 #include "third_party/WebKit/public/web/WebTextAreaElement.h"
27 #include "ui/base/l10n/l10n_util.h"
29 using blink::WebConsoleMessage
;
30 using blink::WebDocument
;
31 using blink::WebFormControlElement
;
32 using blink::WebFormElement
;
33 using blink::WebFrame
;
34 using blink::WebInputElement
;
35 using blink::WebSelectElement
;
36 using blink::WebTextAreaElement
;
37 using blink::WebString
;
38 using blink::WebVector
;
42 // Helper function to discard state of various WebFormElements when they go out
43 // of web frame's scope. This is done to release memory that we no longer need
45 // K should inherit from WebFormControlElement as the function looks to extract
46 // WebFormElement for K.form().
47 template <class K
, class V
>
48 void RemoveOldElements(const WebFrame
& frame
, std::map
<const K
, V
>* states
) {
49 std::vector
<K
> to_remove
;
50 for (typename
std::map
<const K
, V
>::const_iterator it
= states
->begin();
51 it
!= states
->end(); ++it
) {
52 WebFormElement form_element
= it
->first
.form();
53 if (form_element
.isNull()) {
54 to_remove
.push_back(it
->first
);
56 const WebFrame
* element_frame
= form_element
.document().frame();
57 if (!element_frame
|| element_frame
== &frame
)
58 to_remove
.push_back(it
->first
);
62 for (typename
std::vector
<K
>::const_iterator it
= to_remove
.begin();
63 it
!= to_remove
.end(); ++it
) {
68 FormCache::FormCache() {
71 FormCache::~FormCache() {
74 void FormCache::ExtractNewForms(const WebFrame
& frame
,
75 std::vector
<FormData
>* forms
) {
76 WebDocument document
= frame
.document();
77 if (document
.isNull())
80 web_documents_
.insert(document
);
82 WebVector
<WebFormElement
> web_forms
;
83 document
.forms(web_forms
);
85 // Log an error message for deprecated attributes, but only the first time
86 // the form is parsed.
87 bool log_deprecation_messages
=
88 parsed_forms_
.find(&frame
) == parsed_forms_
.end();
90 size_t num_fields_seen
= 0;
91 for (size_t i
= 0; i
< web_forms
.size(); ++i
) {
92 WebFormElement form_element
= web_forms
[i
];
94 std::vector
<WebFormControlElement
> control_elements
;
95 ExtractAutofillableElements(form_element
, autofill::REQUIRE_NONE
,
98 size_t num_editable_elements
= 0;
99 for (size_t j
= 0; j
< control_elements
.size(); ++j
) {
100 WebFormControlElement element
= control_elements
[j
];
102 if (log_deprecation_messages
) {
103 std::string autocomplete_attribute
=
104 base::UTF16ToUTF8(element
.getAttribute("autocomplete"));
106 static const char* const deprecated
[] = { "region", "locality" };
107 for (size_t i
= 0; i
< arraysize(deprecated
); ++i
) {
108 if (autocomplete_attribute
.find(deprecated
[i
]) != std::string::npos
) {
109 WebConsoleMessage console_message
= WebConsoleMessage(
110 WebConsoleMessage::LevelWarning
,
111 WebString(base::ASCIIToUTF16(std::string("autocomplete='") +
112 deprecated
[i
] + "' is deprecated and will soon be ignored. "
113 "See http://goo.gl/YjeSsW")));
114 element
.document().frame()->addMessageToConsole(console_message
);
119 // Save original values of <select> elements so we can restore them
120 // when |ClearFormWithNode()| is invoked.
121 if (IsSelectElement(element
)) {
122 const WebSelectElement select_element
=
123 element
.toConst
<WebSelectElement
>();
124 initial_select_values_
.insert(std::make_pair(select_element
,
125 select_element
.value()));
126 ++num_editable_elements
;
127 } else if (IsTextAreaElement(element
)) {
128 ++num_editable_elements
;
130 const WebInputElement input_element
=
131 element
.toConst
<WebInputElement
>();
132 if (IsCheckableElement(&input_element
)) {
133 initial_checked_state_
.insert(
134 std::make_pair(input_element
, input_element
.isChecked()));
136 ++num_editable_elements
;
141 // To avoid overly expensive computation, we impose a minimum number of
142 // allowable fields. The corresponding maximum number of allowable fields
143 // is imposed by WebFormElementToFormData().
144 if (num_editable_elements
< kRequiredAutofillFields
&&
145 control_elements
.size() > 0) {
150 ExtractMask extract_mask
=
151 static_cast<ExtractMask
>(EXTRACT_VALUE
| EXTRACT_OPTIONS
);
153 if (!WebFormElementToFormData(form_element
, WebFormControlElement(),
154 REQUIRE_NONE
, extract_mask
, &form
, NULL
)) {
158 num_fields_seen
+= form
.fields
.size();
159 if (num_fields_seen
> kMaxParseableFields
)
162 if (form
.fields
.size() >= kRequiredAutofillFields
&&
163 !parsed_forms_
[&frame
].count(form
)) {
164 forms
->push_back(form
);
165 parsed_forms_
[&frame
].insert(form
);
170 void FormCache::ResetFrame(const WebFrame
& frame
) {
171 std::vector
<WebDocument
> documents_to_delete
;
172 for (std::set
<WebDocument
>::const_iterator it
= web_documents_
.begin();
173 it
!= web_documents_
.end(); ++it
) {
174 const WebFrame
* document_frame
= it
->frame();
175 if (!document_frame
|| document_frame
== &frame
)
176 documents_to_delete
.push_back(*it
);
179 for (std::vector
<WebDocument
>::const_iterator it
=
180 documents_to_delete
.begin();
181 it
!= documents_to_delete
.end(); ++it
) {
182 web_documents_
.erase(*it
);
185 parsed_forms_
[&frame
].clear();
186 RemoveOldElements(frame
, &initial_select_values_
);
187 RemoveOldElements(frame
, &initial_checked_state_
);
190 bool FormCache::ClearFormWithElement(const WebFormControlElement
& element
) {
191 WebFormElement form_element
= element
.form();
192 if (form_element
.isNull())
195 std::vector
<WebFormControlElement
> control_elements
;
196 ExtractAutofillableElements(form_element
, autofill::REQUIRE_NONE
,
198 for (size_t i
= 0; i
< control_elements
.size(); ++i
) {
199 WebFormControlElement control_element
= control_elements
[i
];
200 // Don't modify the value of disabled fields.
201 if (!control_element
.isEnabled())
204 // Don't clear field that was not autofilled
205 if (!control_element
.isAutofilled())
208 control_element
.setAutofilled(false);
210 WebInputElement
* input_element
= toWebInputElement(&control_element
);
211 if (IsTextInput(input_element
) || IsMonthInput(input_element
)) {
212 input_element
->setValue(base::string16(), true);
214 // Clearing the value in the focused node (above) can cause selection
215 // to be lost. We force selection range to restore the text cursor.
216 if (element
== *input_element
) {
217 int length
= input_element
->value().length();
218 input_element
->setSelectionRange(length
, length
);
220 } else if (IsTextAreaElement(control_element
)) {
221 control_element
.setValue(base::string16(), true);
222 } else if (IsSelectElement(control_element
)) {
223 WebSelectElement select_element
= control_element
.to
<WebSelectElement
>();
225 std::map
<const WebSelectElement
, base::string16
>::const_iterator
226 initial_value_iter
= initial_select_values_
.find(select_element
);
227 if (initial_value_iter
!= initial_select_values_
.end() &&
228 select_element
.value() != initial_value_iter
->second
) {
229 select_element
.setValue(initial_value_iter
->second
, true);
232 WebInputElement input_element
= control_element
.to
<WebInputElement
>();
233 DCHECK(IsCheckableElement(&input_element
));
234 std::map
<const WebInputElement
, bool>::const_iterator it
=
235 initial_checked_state_
.find(input_element
);
236 if (it
!= initial_checked_state_
.end() &&
237 input_element
.isChecked() != it
->second
) {
238 input_element
.setChecked(it
->second
, true);
246 bool FormCache::ShowPredictions(const FormDataPredictions
& form
) {
247 DCHECK_EQ(form
.data
.fields
.size(), form
.fields
.size());
250 bool found_form
= false;
251 WebFormElement form_element
;
252 for (std::set
<WebDocument
>::const_iterator it
= web_documents_
.begin();
253 it
!= web_documents_
.end() && !found_form
; ++it
) {
254 WebVector
<WebFormElement
> web_forms
;
255 it
->forms(web_forms
);
257 for (size_t i
= 0; i
< web_forms
.size(); ++i
) {
258 form_element
= web_forms
[i
];
260 // Note: matching on the form name here which is not guaranteed to be
261 // unique for the page, nor is it guaranteed to be non-empty. Ideally, we
262 // would have a way to uniquely identify the form cross-process. For now,
263 // we'll check form name and form action for identity.
264 // Also note that WebString() == WebString(string16()) does not evaluate
265 // to |true| -- WebKit distinguishes between a "null" string (lhs) and an
266 // "empty" string (rhs). We don't want that distinction, so forcing to
268 base::string16 element_name
= GetFormIdentifier(form_element
);
269 GURL
action(form_element
.document().completeURL(form_element
.action()));
270 if (element_name
== form
.data
.name
&& action
== form
.data
.action
) {
280 std::vector
<WebFormControlElement
> control_elements
;
281 ExtractAutofillableElements(form_element
, autofill::REQUIRE_NONE
,
283 if (control_elements
.size() != form
.fields
.size()) {
284 // Keep things simple. Don't show predictions for forms that were modified
285 // between page load and the server's response to our query.
289 for (size_t i
= 0; i
< control_elements
.size(); ++i
) {
290 WebFormControlElement
* element
= &control_elements
[i
];
292 if (base::string16(element
->nameForAutofill()) !=
293 form
.data
.fields
[i
].name
) {
294 // Keep things simple. Don't show predictions for elements whose names
295 // were modified between page load and the server's response to our query.
299 std::string placeholder
= form
.fields
[i
].overall_type
;
300 base::string16 title
= l10n_util::GetStringFUTF16(
301 IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE
,
302 base::UTF8ToUTF16(form
.fields
[i
].heuristic_type
),
303 base::UTF8ToUTF16(form
.fields
[i
].server_type
),
304 base::UTF8ToUTF16(form
.fields
[i
].signature
),
305 base::UTF8ToUTF16(form
.signature
),
306 base::UTF8ToUTF16(form
.experiment_id
));
307 if (!element
->hasAttribute("placeholder")) {
308 element
->setAttribute("placeholder",
309 WebString(base::UTF8ToUTF16(placeholder
)));
311 element
->setAttribute("title", WebString(title
));
317 } // namespace autofill