• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "components/autofill/core/common/form_field_data.h"
14 #include "components/autofill/core/common/form_field_data_predictions.h"
15 #include "grit/component_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/WebDocument.h"
19 #include "third_party/WebKit/public/web/WebFormControlElement.h"
20 #include "third_party/WebKit/public/web/WebFormElement.h"
21 #include "third_party/WebKit/public/web/WebFrame.h"
22 #include "third_party/WebKit/public/web/WebInputElement.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"
26 
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 // Helper function to discard state of various WebFormElements when they go out
40 // of web frame's scope. This is done to release memory that we no longer need
41 // to hold.
42 // K should inherit from WebFormControlElement as the function looks to extract
43 // WebFormElement for K.form().
44 template <class K, class V>
RemoveOldElements(const WebFrame & frame,std::map<const K,V> * states)45 void RemoveOldElements(const WebFrame& frame, std::map<const K, V>* states) {
46   std::vector<K> to_remove;
47   for (typename std::map<const K, V>::const_iterator it = states->begin();
48        it != states->end(); ++it) {
49     WebFormElement form_element = it->first.form();
50     if (form_element.isNull()) {
51       to_remove.push_back(it->first);
52     } else {
53       const WebFrame* element_frame = form_element.document().frame();
54       if (!element_frame || element_frame == &frame)
55         to_remove.push_back(it->first);
56     }
57   }
58 
59   for (typename std::vector<K>::const_iterator it = to_remove.begin();
60        it != to_remove.end(); ++it) {
61     states->erase(*it);
62   }
63 }
64 
FormCache()65 FormCache::FormCache() {
66 }
67 
~FormCache()68 FormCache::~FormCache() {
69 }
70 
ExtractForms(const WebFrame & frame,std::vector<FormData> * forms)71 void FormCache::ExtractForms(const WebFrame& frame,
72                              std::vector<FormData>* forms) {
73   ExtractFormsAndFormElements(frame, kRequiredAutofillFields, forms, NULL);
74 }
75 
ExtractFormsAndFormElements(const WebFrame & frame,size_t minimum_required_fields,std::vector<FormData> * forms,std::vector<WebFormElement> * web_form_elements)76 bool FormCache::ExtractFormsAndFormElements(
77     const WebFrame& frame,
78     size_t minimum_required_fields,
79     std::vector<FormData>* forms,
80     std::vector<WebFormElement>* web_form_elements) {
81   // Reset the cache for this frame.
82   ResetFrame(frame);
83 
84   WebDocument document = frame.document();
85   if (document.isNull())
86     return false;
87 
88   web_documents_.insert(document);
89 
90   WebVector<WebFormElement> web_forms;
91   document.forms(web_forms);
92 
93   size_t num_fields_seen = 0;
94   bool has_skipped_forms = false;
95   for (size_t i = 0; i < web_forms.size(); ++i) {
96     WebFormElement form_element = web_forms[i];
97 
98     std::vector<WebFormControlElement> control_elements;
99     ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
100                                 &control_elements);
101 
102     size_t num_editable_elements = 0;
103     for (size_t j = 0; j < control_elements.size(); ++j) {
104       WebFormControlElement element = control_elements[j];
105 
106       // Save original values of <select> elements so we can restore them
107       // when |ClearFormWithNode()| is invoked.
108       if (IsSelectElement(element)) {
109         const WebSelectElement select_element =
110             element.toConst<WebSelectElement>();
111         initial_select_values_.insert(std::make_pair(select_element,
112                                                      select_element.value()));
113         ++num_editable_elements;
114       } else if (IsTextAreaElement(element)) {
115         ++num_editable_elements;
116       } else {
117         const WebInputElement input_element =
118             element.toConst<WebInputElement>();
119         if (IsCheckableElement(&input_element)) {
120           initial_checked_state_.insert(
121               std::make_pair(input_element, input_element.isChecked()));
122         } else {
123           ++num_editable_elements;
124         }
125       }
126     }
127 
128     // To avoid overly expensive computation, we impose a minimum number of
129     // allowable fields.  The corresponding maximum number of allowable fields
130     // is imposed by WebFormElementToFormData().
131     if (num_editable_elements < minimum_required_fields &&
132         control_elements.size() > 0) {
133       has_skipped_forms = true;
134       continue;
135     }
136 
137     FormData form;
138     ExtractMask extract_mask =
139       static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
140 
141     if (!WebFormElementToFormData(form_element, WebFormControlElement(),
142                                   REQUIRE_NONE, extract_mask, &form, NULL)) {
143       continue;
144     }
145 
146     num_fields_seen += form.fields.size();
147     if (num_fields_seen > kMaxParseableFields)
148       break;
149 
150     if (form.fields.size() >= minimum_required_fields) {
151       forms->push_back(form);
152       if (web_form_elements)
153         web_form_elements->push_back(form_element);
154     } else {
155       has_skipped_forms = true;
156     }
157   }
158 
159   // Return true if there are any WebFormElements skipped, else false.
160   return has_skipped_forms;
161 }
162 
ResetFrame(const WebFrame & frame)163 void FormCache::ResetFrame(const WebFrame& frame) {
164   std::vector<WebDocument> documents_to_delete;
165   for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
166        it != web_documents_.end(); ++it) {
167     const WebFrame* document_frame = it->frame();
168     if (!document_frame || document_frame == &frame)
169       documents_to_delete.push_back(*it);
170   }
171 
172   for (std::vector<WebDocument>::const_iterator it =
173            documents_to_delete.begin();
174        it != documents_to_delete.end(); ++it) {
175     web_documents_.erase(*it);
176   }
177 
178   RemoveOldElements(frame, &initial_select_values_);
179   RemoveOldElements(frame, &initial_checked_state_);
180 }
181 
ClearFormWithElement(const WebInputElement & element)182 bool FormCache::ClearFormWithElement(const WebInputElement& element) {
183   WebFormElement form_element = element.form();
184   if (form_element.isNull())
185     return false;
186 
187   std::vector<WebFormControlElement> control_elements;
188   ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
189                               &control_elements);
190   for (size_t i = 0; i < control_elements.size(); ++i) {
191     WebFormControlElement control_element = control_elements[i];
192     // Don't modify the value of disabled fields.
193     if (!control_element.isEnabled())
194       continue;
195 
196     control_element.setAutofilled(false);
197 
198     WebInputElement* input_element = toWebInputElement(&control_element);
199     if (IsTextInput(input_element) || IsMonthInput(input_element)) {
200       input_element->setValue(base::string16(), true);
201 
202       // Clearing the value in the focused node (above) can cause selection
203       // to be lost. We force selection range to restore the text cursor.
204       if (element == *input_element) {
205         int length = input_element->value().length();
206         input_element->setSelectionRange(length, length);
207       }
208     } else if (IsTextAreaElement(control_element)) {
209       WebTextAreaElement text_area = control_element.to<WebTextAreaElement>();
210       text_area.setValue(base::string16());
211       text_area.dispatchFormControlChangeEvent();
212     } else if (IsSelectElement(control_element)) {
213       WebSelectElement select_element = control_element.to<WebSelectElement>();
214 
215       std::map<const WebSelectElement, base::string16>::const_iterator
216           initial_value_iter = initial_select_values_.find(select_element);
217       if (initial_value_iter != initial_select_values_.end() &&
218           select_element.value() != initial_value_iter->second) {
219         select_element.setValue(initial_value_iter->second);
220         select_element.dispatchFormControlChangeEvent();
221       }
222     } else {
223       WebInputElement input_element = control_element.to<WebInputElement>();
224       DCHECK(IsCheckableElement(&input_element));
225       std::map<const WebInputElement, bool>::const_iterator it =
226           initial_checked_state_.find(input_element);
227       if (it != initial_checked_state_.end() &&
228           input_element.isChecked() != it->second) {
229         input_element.setChecked(it->second, true);
230       }
231     }
232   }
233 
234   return true;
235 }
236 
ShowPredictions(const FormDataPredictions & form)237 bool FormCache::ShowPredictions(const FormDataPredictions& form) {
238   DCHECK_EQ(form.data.fields.size(), form.fields.size());
239 
240   // Find the form.
241   bool found_form = false;
242   WebFormElement form_element;
243   for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
244        it != web_documents_.end() && !found_form; ++it) {
245     WebVector<WebFormElement> web_forms;
246     it->forms(web_forms);
247 
248     for (size_t i = 0; i < web_forms.size(); ++i) {
249       form_element = web_forms[i];
250 
251       // Note: matching on the form name here which is not guaranteed to be
252       // unique for the page, nor is it guaranteed to be non-empty.  Ideally, we
253       // would have a way to uniquely identify the form cross-process.  For now,
254       // we'll check form name and form action for identity.
255       // Also note that WebString() == WebString(string16()) does not evaluate
256       // to |true| -- WebKit distinguishes between a "null" string (lhs) and an
257       // "empty" string (rhs).  We don't want that distinction, so forcing to
258       // string16.
259       base::string16 element_name = GetFormIdentifier(form_element);
260       GURL action(form_element.document().completeURL(form_element.action()));
261       if (element_name == form.data.name && action == form.data.action) {
262         found_form = true;
263         break;
264       }
265     }
266   }
267 
268   if (!found_form)
269     return false;
270 
271   std::vector<WebFormControlElement> control_elements;
272   ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
273                               &control_elements);
274   if (control_elements.size() != form.fields.size()) {
275     // Keep things simple.  Don't show predictions for forms that were modified
276     // between page load and the server's response to our query.
277     return false;
278   }
279 
280   for (size_t i = 0; i < control_elements.size(); ++i) {
281     WebFormControlElement* element = &control_elements[i];
282 
283     if (base::string16(element->nameForAutofill()) !=
284         form.data.fields[i].name) {
285       // Keep things simple.  Don't show predictions for elements whose names
286       // were modified between page load and the server's response to our query.
287       continue;
288     }
289 
290     std::string placeholder = form.fields[i].overall_type;
291     base::string16 title = l10n_util::GetStringFUTF16(
292         IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE,
293         UTF8ToUTF16(form.fields[i].heuristic_type),
294         UTF8ToUTF16(form.fields[i].server_type),
295         UTF8ToUTF16(form.fields[i].signature),
296         UTF8ToUTF16(form.signature),
297         UTF8ToUTF16(form.experiment_id));
298     if (!element->hasAttribute("placeholder"))
299       element->setAttribute("placeholder", WebString(UTF8ToUTF16(placeholder)));
300     element->setAttribute("title", WebString(title));
301   }
302 
303   return true;
304 }
305 
306 }  // namespace autofill
307