OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/renderer/form_cache.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/utf_string_conversions.h" | |
9 #include "components/autofill/common/autofill_constants.h" | |
10 #include "components/autofill/common/form_data.h" | |
11 #include "components/autofill/common/form_data_predictions.h" | |
12 #include "components/autofill/common/form_field_data.h" | |
13 #include "components/autofill/common/form_field_data_predictions.h" | |
14 #include "components/autofill/renderer/form_autofill_util.h" | |
15 #include "grit/component_resources.h" | |
16 #include "third_party/WebKit/public/platform/WebString.h" | |
17 #include "third_party/WebKit/public/platform/WebVector.h" | |
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | |
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement
.h" | |
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h" | |
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" | |
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSelectElement.h" | |
24 #include "ui/base/l10n/l10n_util.h" | |
25 | |
26 using WebKit::WebDocument; | |
27 using WebKit::WebFormControlElement; | |
28 using WebKit::WebFormElement; | |
29 using WebKit::WebFrame; | |
30 using WebKit::WebInputElement; | |
31 using WebKit::WebSelectElement; | |
32 using WebKit::WebString; | |
33 using WebKit::WebVector; | |
34 | |
35 namespace 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(). | |
42 template <class K, class V> | |
43 void 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 | |
63 FormCache::FormCache() { | |
64 } | |
65 | |
66 FormCache::~FormCache() { | |
67 } | |
68 | |
69 void FormCache::ExtractForms(const WebFrame& frame, | |
70 std::vector<FormData>* forms) { | |
71 ExtractFormsAndFormElements(frame, kRequiredAutofillFields, forms, NULL); | |
72 } | |
73 | |
74 bool 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 | |
159 void 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 | |
178 bool 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 | |
228 bool 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 | |
OLD | NEW |