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