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