ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / components / autofill / content / renderer / form_cache.cc
blob9bc97e2f5505c598566d3a66b4995d9839aa2dd4
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;
34 using blink::WebNode;
35 using blink::WebSelectElement;
36 using blink::WebString;
37 using blink::WebTextAreaElement;
38 using blink::WebVector;
40 namespace autofill {
42 namespace {
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)
51 continue;
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);
70 } // namespace
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())
82 return forms;
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()))
104 continue;
106 FormData form;
107 if (!WebFormElementToFormData(form_element, WebFormControlElement(),
108 REQUIRE_NONE, extract_mask, &form, nullptr)) {
109 continue;
112 num_fields_seen += form.fields.size();
113 if (num_fields_seen > kMaxParseableFields)
114 return forms;
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()))
132 return forms;
134 FormData synthetic_form;
135 if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets, control_elements,
136 nullptr, document.url(),
137 REQUIRE_NONE, extract_mask,
138 &synthetic_form, nullptr)) {
139 return forms;
142 num_fields_seen += synthetic_form.fields.size();
143 if (num_fields_seen > kMaxParseableFields)
144 return forms;
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;
152 return forms;
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);
168 } else {
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())
176 continue;
178 // Don't clear field that was not autofilled
179 if (!control_element.isAutofilled())
180 continue;
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);
205 } else {
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);
217 return 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();
230 control_elements =
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
250 // to string16.
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) {
254 found_form = true;
255 control_elements =
256 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE);
257 break;
261 if (!found_form)
262 return false;
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.
268 return false;
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.
277 continue;
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));
290 return true;
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;
313 } else {
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()));
319 } else {
320 ++num_editable_elements;
324 return num_editable_elements;
327 } // namespace autofill