Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / autofill / content / renderer / form_cache.cc
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.
4
5 #include "components/autofill/content/renderer/form_cache.h"
6
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"
25
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;
36
37 namespace autofill {
38
39 namespace {
40
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
43 // to hold.
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);
54     } else {
55       const WebFrame* element_frame = form_element.document().frame();
56       if (!element_frame || element_frame == &frame)
57         to_remove.push_back(it->first);
58     }
59   }
60
61   for (typename std::vector<K>::const_iterator it = to_remove.begin();
62        it != to_remove.end(); ++it) {
63     states->erase(*it);
64   }
65 }
66
67 void LogDeprecationMessages(const WebFormControlElement& element) {
68   std::string autocomplete_attribute =
69       base::UTF16ToUTF8(element.getAttribute("autocomplete"));
70
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)
74       continue;
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);
81   }
82 }
83
84 }  // namespace
85
86 FormCache::FormCache() {
87 }
88
89 FormCache::~FormCache() {
90 }
91
92 std::vector<FormData> FormCache::ExtractNewForms(const WebFrame& frame) {
93   std::vector<FormData> forms;
94   WebDocument document = frame.document();
95   if (document.isNull())
96     return forms;
97
98   web_documents_.insert(document);
99
100   WebVector<WebFormElement> web_forms;
101   document.forms(web_forms);
102
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();
107
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];
111
112     std::vector<WebFormControlElement> control_elements;
113     ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
114                                 &control_elements);
115     size_t num_editable_elements =
116         ScanFormControlElements(control_elements, log_deprecation_messages);
117
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) {
123       continue;
124     }
125
126     FormData form;
127     ExtractMask extract_mask =
128       static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
129
130     if (!WebFormElementToFormData(form_element, WebFormControlElement(),
131                                   REQUIRE_NONE, extract_mask, &form, NULL)) {
132       continue;
133     }
134
135     num_fields_seen += form.fields.size();
136     if (num_fields_seen > kMaxParseableFields)
137       break;
138
139     if (form.fields.size() >= kRequiredAutofillFields &&
140         !parsed_forms_[&frame].count(form)) {
141       forms.push_back(form);
142       parsed_forms_[&frame].insert(form);
143     }
144   }
145   return forms;
146 }
147
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);
155   }
156
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);
161   }
162
163   parsed_forms_[&frame].clear();
164   RemoveOldElements(frame, &initial_select_values_);
165   RemoveOldElements(frame, &initial_checked_state_);
166 }
167
168 bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
169   WebFormElement form_element = element.form();
170   if (form_element.isNull())
171     return false;
172
173   std::vector<WebFormControlElement> control_elements;
174   ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
175                               &control_elements);
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())
180       continue;
181
182     // Don't clear field that was not autofilled
183     if (!control_element.isAutofilled())
184       continue;
185
186     control_element.setAutofilled(false);
187
188     WebInputElement* input_element = toWebInputElement(&control_element);
189     if (IsTextInput(input_element) || IsMonthInput(input_element)) {
190       input_element->setValue(base::string16(), true);
191
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);
197       }
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>();
202
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);
208       }
209     } else {
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);
217       }
218     }
219   }
220
221   return true;
222 }
223
224 bool FormCache::ShowPredictions(const FormDataPredictions& form) {
225   DCHECK_EQ(form.data.fields.size(), form.fields.size());
226
227   // Find the form.
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);
234
235     for (size_t i = 0; i < web_forms.size(); ++i) {
236       form_element = web_forms[i];
237
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
245       // string16.
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) {
249         found_form = true;
250         break;
251       }
252     }
253   }
254
255   if (!found_form)
256     return false;
257
258   std::vector<WebFormControlElement> control_elements;
259   ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
260                               &control_elements);
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.
264     return false;
265   }
266
267   for (size_t i = 0; i < control_elements.size(); ++i) {
268     WebFormControlElement* element = &control_elements[i];
269
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.
274       continue;
275     }
276
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)));
288     }
289     element->setAttribute("title", WebString(title));
290   }
291
292   return true;
293 }
294
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];
301
302     if (log_deprecation_messages)
303       LogDeprecationMessages(element);
304
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;
315     } else {
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()));
321       } else {
322         ++num_editable_elements;
323       }
324     }
325   }
326   return num_editable_elements;
327 }
328
329 }  // namespace autofill