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 "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/WebSelectElement.h"
23 #include "third_party/WebKit/public/web/WebTextAreaElement.h"
24 #include "ui/base/l10n/l10n_util.h"
26 using blink::WebConsoleMessage;
27 using blink::WebDocument;
28 using blink::WebFormControlElement;
29 using blink::WebFormElement;
30 using blink::WebFrame;
31 using blink::WebInputElement;
32 using blink::WebSelectElement;
33 using blink::WebTextAreaElement;
34 using blink::WebString;
35 using blink::WebVector;
41 // Helper function to discard state of various WebFormElements when they go out
42 // of web frame's scope. This is done to release memory that we no longer need
44 // K should inherit from WebFormControlElement as the function looks to extract
45 // WebFormElement for K.form().
46 template <class K, class V>
47 void RemoveOldElements(const WebFrame& frame, std::map<const K, V>* states) {
48 std::vector<K> to_remove;
49 for (typename std::map<const K, V>::const_iterator it = states->begin();
50 it != states->end(); ++it) {
51 const WebFormElement& form_element = it->first.form();
52 if (form_element.isNull()) {
53 to_remove.push_back(it->first);
55 const WebFrame* element_frame = form_element.document().frame();
56 if (!element_frame || element_frame == &frame)
57 to_remove.push_back(it->first);
61 for (typename std::vector<K>::const_iterator it = to_remove.begin();
62 it != to_remove.end(); ++it) {
67 void LogDeprecationMessages(const WebFormControlElement& element) {
68 std::string autocomplete_attribute =
69 base::UTF16ToUTF8(element.getAttribute("autocomplete"));
71 static const char* const deprecated[] = { "region", "locality" };
72 for (size_t i = 0; i < arraysize(deprecated); ++i) {
73 if (autocomplete_attribute.find(deprecated[i]) == std::string::npos)
75 std::string msg = std::string("autocomplete='") + deprecated[i] +
76 "' is deprecated and will soon be ignored. See http://goo.gl/YjeSsW";
77 WebConsoleMessage console_message = WebConsoleMessage(
78 WebConsoleMessage::LevelWarning,
79 WebString(base::ASCIIToUTF16(msg)));
80 element.document().frame()->addMessageToConsole(console_message);
86 FormCache::FormCache() {
89 FormCache::~FormCache() {
92 std::vector<FormData> FormCache::ExtractNewForms(const WebFrame& frame) {
93 std::vector<FormData> forms;
94 WebDocument document = frame.document();
95 if (document.isNull())
98 web_documents_.insert(document);
100 WebVector<WebFormElement> web_forms;
101 document.forms(web_forms);
103 // Log an error message for deprecated attributes, but only the first time
104 // the form is parsed.
105 bool log_deprecation_messages =
106 parsed_forms_.find(&frame) == parsed_forms_.end();
108 size_t num_fields_seen = 0;
109 for (size_t i = 0; i < web_forms.size(); ++i) {
110 const WebFormElement& form_element = web_forms[i];
112 std::vector<WebFormControlElement> control_elements;
113 ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
115 size_t num_editable_elements =
116 ScanFormControlElements(control_elements, log_deprecation_messages);
118 // To avoid overly expensive computation, we impose a minimum number of
119 // allowable fields. The corresponding maximum number of allowable fields
120 // is imposed by WebFormElementToFormData().
121 if (num_editable_elements < kRequiredAutofillFields &&
122 control_elements.size() > 0) {
127 ExtractMask extract_mask =
128 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
130 if (!WebFormElementToFormData(form_element, WebFormControlElement(),
131 REQUIRE_NONE, extract_mask, &form, NULL)) {
135 num_fields_seen += form.fields.size();
136 if (num_fields_seen > kMaxParseableFields)
139 if (form.fields.size() >= kRequiredAutofillFields &&
140 !parsed_forms_[&frame].count(form)) {
141 forms.push_back(form);
142 parsed_forms_[&frame].insert(form);
148 void FormCache::ResetFrame(const WebFrame& frame) {
149 std::vector<WebDocument> documents_to_delete;
150 for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
151 it != web_documents_.end(); ++it) {
152 const WebFrame* document_frame = it->frame();
153 if (!document_frame || document_frame == &frame)
154 documents_to_delete.push_back(*it);
157 for (std::vector<WebDocument>::const_iterator it =
158 documents_to_delete.begin();
159 it != documents_to_delete.end(); ++it) {
160 web_documents_.erase(*it);
163 parsed_forms_[&frame].clear();
164 RemoveOldElements(frame, &initial_select_values_);
165 RemoveOldElements(frame, &initial_checked_state_);
168 bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
169 WebFormElement form_element = element.form();
170 if (form_element.isNull())
173 std::vector<WebFormControlElement> control_elements;
174 ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
176 for (size_t i = 0; i < control_elements.size(); ++i) {
177 WebFormControlElement control_element = control_elements[i];
178 // Don't modify the value of disabled fields.
179 if (!control_element.isEnabled())
182 // Don't clear field that was not autofilled
183 if (!control_element.isAutofilled())
186 control_element.setAutofilled(false);
188 WebInputElement* input_element = toWebInputElement(&control_element);
189 if (IsTextInput(input_element) || IsMonthInput(input_element)) {
190 input_element->setValue(base::string16(), true);
192 // Clearing the value in the focused node (above) can cause selection
193 // to be lost. We force selection range to restore the text cursor.
194 if (element == *input_element) {
195 int length = input_element->value().length();
196 input_element->setSelectionRange(length, length);
198 } else if (IsTextAreaElement(control_element)) {
199 control_element.setValue(base::string16(), true);
200 } else if (IsSelectElement(control_element)) {
201 WebSelectElement select_element = control_element.to<WebSelectElement>();
203 std::map<const WebSelectElement, base::string16>::const_iterator
204 initial_value_iter = initial_select_values_.find(select_element);
205 if (initial_value_iter != initial_select_values_.end() &&
206 select_element.value() != initial_value_iter->second) {
207 select_element.setValue(initial_value_iter->second, true);
210 WebInputElement input_element = control_element.to<WebInputElement>();
211 DCHECK(IsCheckableElement(&input_element));
212 std::map<const WebInputElement, bool>::const_iterator it =
213 initial_checked_state_.find(input_element);
214 if (it != initial_checked_state_.end() &&
215 input_element.isChecked() != it->second) {
216 input_element.setChecked(it->second, true);
224 bool FormCache::ShowPredictions(const FormDataPredictions& form) {
225 DCHECK_EQ(form.data.fields.size(), form.fields.size());
228 bool found_form = false;
229 WebFormElement form_element;
230 for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
231 it != web_documents_.end() && !found_form; ++it) {
232 WebVector<WebFormElement> web_forms;
233 it->forms(web_forms);
235 for (size_t i = 0; i < web_forms.size(); ++i) {
236 form_element = web_forms[i];
238 // Note: matching on the form name here which is not guaranteed to be
239 // unique for the page, nor is it guaranteed to be non-empty. Ideally, we
240 // would have a way to uniquely identify the form cross-process. For now,
241 // we'll check form name and form action for identity.
242 // Also note that WebString() == WebString(string16()) does not evaluate
243 // to |true| -- WebKit distinguishes between a "null" string (lhs) and an
244 // "empty" string (rhs). We don't want that distinction, so forcing to
246 base::string16 element_name = GetFormIdentifier(form_element);
247 GURL action(form_element.document().completeURL(form_element.action()));
248 if (element_name == form.data.name && action == form.data.action) {
258 std::vector<WebFormControlElement> control_elements;
259 ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
261 if (control_elements.size() != form.fields.size()) {
262 // Keep things simple. Don't show predictions for forms that were modified
263 // between page load and the server's response to our query.
267 for (size_t i = 0; i < control_elements.size(); ++i) {
268 WebFormControlElement* element = &control_elements[i];
270 if (base::string16(element->nameForAutofill()) !=
271 form.data.fields[i].name) {
272 // Keep things simple. Don't show predictions for elements whose names
273 // were modified between page load and the server's response to our query.
277 std::string placeholder = form.fields[i].overall_type;
278 base::string16 title = l10n_util::GetStringFUTF16(
279 IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE,
280 base::UTF8ToUTF16(form.fields[i].heuristic_type),
281 base::UTF8ToUTF16(form.fields[i].server_type),
282 base::UTF8ToUTF16(form.fields[i].signature),
283 base::UTF8ToUTF16(form.signature),
284 base::UTF8ToUTF16(form.experiment_id));
285 if (!element->hasAttribute("placeholder")) {
286 element->setAttribute("placeholder",
287 WebString(base::UTF8ToUTF16(placeholder)));
289 element->setAttribute("title", WebString(title));
295 size_t FormCache::ScanFormControlElements(
296 const std::vector<WebFormControlElement>& control_elements,
297 bool log_deprecation_messages) {
298 size_t num_editable_elements = 0;
299 for (size_t i = 0; i < control_elements.size(); ++i) {
300 const WebFormControlElement& element = control_elements[i];
302 if (log_deprecation_messages)
303 LogDeprecationMessages(element);
305 // Save original values of <select> elements so we can restore them
306 // when |ClearFormWithNode()| is invoked.
307 if (IsSelectElement(element)) {
308 const WebSelectElement select_element =
309 element.toConst<WebSelectElement>();
310 initial_select_values_.insert(
311 std::make_pair(select_element, select_element.value()));
312 ++num_editable_elements;
313 } else if (IsTextAreaElement(element)) {
314 ++num_editable_elements;
316 const WebInputElement input_element =
317 element.toConst<WebInputElement>();
318 if (IsCheckableElement(&input_element)) {
319 initial_checked_state_.insert(
320 std::make_pair(input_element, input_element.isChecked()));
322 ++num_editable_elements;
326 return num_editable_elements;
329 } // namespace autofill