OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/autofill/content/renderer/form_cache.h" | 5 #include "components/autofill/content/renderer/form_cache.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "components/autofill/content/renderer/form_autofill_util.h" | 10 #include "components/autofill/content/renderer/form_autofill_util.h" |
11 #include "components/autofill/core/common/autofill_constants.h" | 11 #include "components/autofill/core/common/autofill_constants.h" |
12 #include "components/autofill/core/common/form_data.h" | |
13 #include "components/autofill/core/common/form_data_predictions.h" | 12 #include "components/autofill/core/common/form_data_predictions.h" |
14 #include "grit/components_strings.h" | 13 #include "grit/components_strings.h" |
15 #include "third_party/WebKit/public/platform/WebString.h" | 14 #include "third_party/WebKit/public/platform/WebString.h" |
16 #include "third_party/WebKit/public/platform/WebVector.h" | 15 #include "third_party/WebKit/public/platform/WebVector.h" |
17 #include "third_party/WebKit/public/web/WebConsoleMessage.h" | 16 #include "third_party/WebKit/public/web/WebConsoleMessage.h" |
18 #include "third_party/WebKit/public/web/WebDocument.h" | 17 #include "third_party/WebKit/public/web/WebDocument.h" |
19 #include "third_party/WebKit/public/web/WebElementCollection.h" | 18 #include "third_party/WebKit/public/web/WebElementCollection.h" |
20 #include "third_party/WebKit/public/web/WebFormControlElement.h" | 19 #include "third_party/WebKit/public/web/WebFormControlElement.h" |
21 #include "third_party/WebKit/public/web/WebFormElement.h" | 20 #include "third_party/WebKit/public/web/WebFormElement.h" |
22 #include "third_party/WebKit/public/web/WebInputElement.h" | 21 #include "third_party/WebKit/public/web/WebInputElement.h" |
(...skipping 14 matching lines...) Expand all Loading... |
37 using blink::WebNode; | 36 using blink::WebNode; |
38 using blink::WebSelectElement; | 37 using blink::WebSelectElement; |
39 using blink::WebString; | 38 using blink::WebString; |
40 using blink::WebTextAreaElement; | 39 using blink::WebTextAreaElement; |
41 using blink::WebVector; | 40 using blink::WebVector; |
42 | 41 |
43 namespace autofill { | 42 namespace autofill { |
44 | 43 |
45 namespace { | 44 namespace { |
46 | 45 |
47 // Helper function to discard state of various WebFormElements when they go out | |
48 // of web frame's scope. This is done to release memory that we no longer need | |
49 // to hold. | |
50 // K should inherit from WebFormControlElement as the function looks to extract | |
51 // WebFormElement for K.form(). | |
52 template <class K, class V> | |
53 void RemoveOldElements(const WebFrame& frame, std::map<const K, V>* states) { | |
54 std::vector<K> to_remove; | |
55 for (typename std::map<const K, V>::const_iterator it = states->begin(); | |
56 it != states->end(); ++it) { | |
57 const WebFormElement& form_element = it->first.form(); | |
58 if (form_element.isNull()) { | |
59 to_remove.push_back(it->first); | |
60 } else { | |
61 const WebFrame* element_frame = form_element.document().frame(); | |
62 if (!element_frame || element_frame == &frame) | |
63 to_remove.push_back(it->first); | |
64 } | |
65 } | |
66 | |
67 for (typename std::vector<K>::const_iterator it = to_remove.begin(); | |
68 it != to_remove.end(); ++it) { | |
69 states->erase(*it); | |
70 } | |
71 } | |
72 | |
73 void LogDeprecationMessages(const WebFormControlElement& element) { | 46 void LogDeprecationMessages(const WebFormControlElement& element) { |
74 std::string autocomplete_attribute = | 47 std::string autocomplete_attribute = |
75 base::UTF16ToUTF8(element.getAttribute("autocomplete")); | 48 base::UTF16ToUTF8(element.getAttribute("autocomplete")); |
76 | 49 |
77 static const char* const deprecated[] = { "region", "locality" }; | 50 static const char* const deprecated[] = { "region", "locality" }; |
78 for (size_t i = 0; i < arraysize(deprecated); ++i) { | 51 for (size_t i = 0; i < arraysize(deprecated); ++i) { |
79 if (autocomplete_attribute.find(deprecated[i]) == std::string::npos) | 52 if (autocomplete_attribute.find(deprecated[i]) == std::string::npos) |
80 continue; | 53 continue; |
81 std::string msg = std::string("autocomplete='") + deprecated[i] + | 54 std::string msg = std::string("autocomplete='") + deprecated[i] + |
82 "' is deprecated and will soon be ignored. See http://goo.gl/YjeSsW"; | 55 "' is deprecated and will soon be ignored. See http://goo.gl/YjeSsW"; |
(...skipping 24 matching lines...) Expand all Loading... |
107 // allowable fields. The corresponding maximum number of allowable fields | 80 // allowable fields. The corresponding maximum number of allowable fields |
108 // is imposed by WebFormElementToFormData(). | 81 // is imposed by WebFormElementToFormData(). |
109 bool ShouldIgnoreForm(size_t num_editable_elements, | 82 bool ShouldIgnoreForm(size_t num_editable_elements, |
110 size_t num_control_elements) { | 83 size_t num_control_elements) { |
111 return (num_editable_elements < kRequiredAutofillFields && | 84 return (num_editable_elements < kRequiredAutofillFields && |
112 num_control_elements > 0); | 85 num_control_elements > 0); |
113 } | 86 } |
114 | 87 |
115 } // namespace | 88 } // namespace |
116 | 89 |
117 FormCache::FormCache() { | 90 FormCache::FormCache(const WebFrame& frame) : frame_(frame) { |
118 } | 91 } |
119 | 92 |
120 FormCache::~FormCache() { | 93 FormCache::~FormCache() { |
121 } | 94 } |
122 | 95 |
123 // static | 96 // static |
124 std::vector<WebFormControlElement> | 97 std::vector<WebFormControlElement> |
125 FormCache::GetUnownedAutofillableFormFieldElements( | 98 FormCache::GetUnownedAutofillableFormFieldElements( |
126 const WebElementCollection& elements, | 99 const WebElementCollection& elements, |
127 std::vector<WebElement>* fieldsets) { | 100 std::vector<WebElement>* fieldsets) { |
128 std::vector<WebFormControlElement> unowned_fieldset_children; | 101 std::vector<WebFormControlElement> unowned_fieldset_children; |
129 for (WebElement element = elements.firstItem(); | 102 for (WebElement element = elements.firstItem(); |
130 !element.isNull(); | 103 !element.isNull(); |
131 element = elements.nextItem()) { | 104 element = elements.nextItem()) { |
132 if (element.isFormControlElement()) { | 105 if (element.isFormControlElement()) { |
133 WebFormControlElement control = element.to<WebFormControlElement>(); | 106 WebFormControlElement control = element.to<WebFormControlElement>(); |
134 if (control.form().isNull()) | 107 if (control.form().isNull()) |
135 unowned_fieldset_children.push_back(control); | 108 unowned_fieldset_children.push_back(control); |
136 } | 109 } |
137 | 110 |
138 if (fieldsets && element.hasHTMLTagName("fieldset") && | 111 if (fieldsets && element.hasHTMLTagName("fieldset") && |
139 !IsElementInsideFormOrFieldSet(element)) { | 112 !IsElementInsideFormOrFieldSet(element)) { |
140 fieldsets->push_back(element); | 113 fieldsets->push_back(element); |
141 } | 114 } |
142 } | 115 } |
143 return ExtractAutofillableElementsFromSet(unowned_fieldset_children, | 116 return ExtractAutofillableElementsFromSet(unowned_fieldset_children, |
144 REQUIRE_NONE); | 117 REQUIRE_NONE); |
145 } | 118 } |
146 | 119 |
147 std::vector<FormData> FormCache::ExtractNewForms(const WebFrame& frame) { | 120 std::vector<FormData> FormCache::ExtractNewForms() { |
148 std::vector<FormData> forms; | 121 std::vector<FormData> forms; |
149 WebDocument document = frame.document(); | 122 WebDocument document = frame_.document(); |
150 if (document.isNull()) | 123 if (document.isNull()) |
151 return forms; | 124 return forms; |
152 | 125 |
153 if (!ContainsKey(documents_to_synthetic_form_map_, document)) | |
154 documents_to_synthetic_form_map_[document] = FormData(); | |
155 | |
156 WebVector<WebFormElement> web_forms; | 126 WebVector<WebFormElement> web_forms; |
157 document.forms(web_forms); | 127 document.forms(web_forms); |
158 | 128 |
159 // Log an error message for deprecated attributes, but only the first time | 129 // Log an error message for deprecated attributes, but only the first time |
160 // the form is parsed. | 130 // the form is parsed. |
161 bool log_deprecation_messages = !ContainsKey(parsed_forms_, &frame); | 131 bool log_deprecation_messages = parsed_forms_.empty(); |
162 | 132 |
163 const ExtractMask extract_mask = | 133 const ExtractMask extract_mask = |
164 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); | 134 static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); |
165 | 135 |
166 size_t num_fields_seen = 0; | 136 size_t num_fields_seen = 0; |
167 for (size_t i = 0; i < web_forms.size(); ++i) { | 137 for (size_t i = 0; i < web_forms.size(); ++i) { |
168 const WebFormElement& form_element = web_forms[i]; | 138 const WebFormElement& form_element = web_forms[i]; |
169 | 139 |
170 std::vector<WebFormControlElement> control_elements = | 140 std::vector<WebFormControlElement> control_elements = |
171 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); | 141 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); |
172 size_t num_editable_elements = | 142 size_t num_editable_elements = |
173 ScanFormControlElements(control_elements, log_deprecation_messages); | 143 ScanFormControlElements(control_elements, log_deprecation_messages); |
174 | 144 |
175 if (ShouldIgnoreForm(num_editable_elements, control_elements.size())) | 145 if (ShouldIgnoreForm(num_editable_elements, control_elements.size())) |
176 continue; | 146 continue; |
177 | 147 |
178 FormData form; | 148 FormData form; |
179 if (!WebFormElementToFormData(form_element, WebFormControlElement(), | 149 if (!WebFormElementToFormData(form_element, WebFormControlElement(), |
180 REQUIRE_NONE, extract_mask, &form, NULL)) { | 150 REQUIRE_NONE, extract_mask, &form, NULL)) { |
181 continue; | 151 continue; |
182 } | 152 } |
183 | 153 |
184 num_fields_seen += form.fields.size(); | 154 num_fields_seen += form.fields.size(); |
185 if (num_fields_seen > kMaxParseableFields) | 155 if (num_fields_seen > kMaxParseableFields) |
186 return forms; | 156 return forms; |
187 | 157 |
188 if (form.fields.size() >= kRequiredAutofillFields && | 158 if (form.fields.size() >= kRequiredAutofillFields && |
189 !ContainsKey(parsed_forms_[&frame], form)) { | 159 !ContainsKey(parsed_forms_, form)) { |
190 forms.push_back(form); | 160 forms.push_back(form); |
191 parsed_forms_[&frame].insert(form); | 161 parsed_forms_.insert(form); |
192 } | 162 } |
193 } | 163 } |
194 | 164 |
195 // Look for more parseable fields outside of forms. | 165 // Look for more parseable fields outside of forms. |
196 std::vector<WebElement> fieldsets; | 166 std::vector<WebElement> fieldsets; |
197 std::vector<WebFormControlElement> control_elements = | 167 std::vector<WebFormControlElement> control_elements = |
198 GetUnownedAutofillableFormFieldElements(document.all(), &fieldsets); | 168 GetUnownedAutofillableFormFieldElements(document.all(), &fieldsets); |
199 | 169 |
200 size_t num_editable_elements = | 170 size_t num_editable_elements = |
201 ScanFormControlElements(control_elements, log_deprecation_messages); | 171 ScanFormControlElements(control_elements, log_deprecation_messages); |
202 | 172 |
203 if (ShouldIgnoreForm(num_editable_elements, control_elements.size())) | 173 if (ShouldIgnoreForm(num_editable_elements, control_elements.size())) |
204 return forms; | 174 return forms; |
205 | 175 |
206 FormData form; | 176 FormData synthetic_form; |
207 if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets, control_elements, | 177 if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets, control_elements, |
208 document.url(), extract_mask, | 178 document.url(), extract_mask, |
209 &form)) { | 179 &synthetic_form)) { |
210 return forms; | 180 return forms; |
211 } | 181 } |
212 | 182 |
213 num_fields_seen += form.fields.size(); | 183 num_fields_seen += synthetic_form.fields.size(); |
214 if (num_fields_seen > kMaxParseableFields) | 184 if (num_fields_seen > kMaxParseableFields) |
215 return forms; | 185 return forms; |
216 | 186 |
217 if (form.fields.size() >= kRequiredAutofillFields && | 187 if (synthetic_form.fields.size() >= kRequiredAutofillFields && |
218 !parsed_forms_[&frame].count(form)) { | 188 !parsed_forms_.count(synthetic_form)) { |
219 forms.push_back(form); | 189 forms.push_back(synthetic_form); |
220 parsed_forms_[&frame].insert(form); | 190 parsed_forms_.insert(synthetic_form); |
221 documents_to_synthetic_form_map_[document] = form; | 191 synthetic_form_ = synthetic_form; |
222 } | 192 } |
223 return forms; | 193 return forms; |
224 } | 194 } |
225 | 195 |
226 void FormCache::ResetFrame(const WebFrame& frame) { | 196 void FormCache::Reset() { |
227 std::vector<WebDocument> documents_to_delete; | 197 synthetic_form_ = FormData(); |
228 for (const auto& it : documents_to_synthetic_form_map_) { | 198 parsed_forms_.clear(); |
229 const WebFrame* document_frame = it.first.frame(); | 199 initial_select_values_.clear(); |
230 if (!document_frame || document_frame == &frame) | 200 initial_checked_state_.clear(); |
231 documents_to_delete.push_back(it.first); | |
232 } | |
233 | |
234 for (const auto& it : documents_to_delete) | |
235 documents_to_synthetic_form_map_.erase(it); | |
236 | |
237 parsed_forms_[&frame].clear(); | |
238 RemoveOldElements(frame, &initial_select_values_); | |
239 RemoveOldElements(frame, &initial_checked_state_); | |
240 } | 201 } |
241 | 202 |
242 bool FormCache::ClearFormWithElement(const WebFormControlElement& element) { | 203 bool FormCache::ClearFormWithElement(const WebFormControlElement& element) { |
243 WebFormElement form_element = element.form(); | 204 WebFormElement form_element = element.form(); |
244 if (form_element.isNull()) | 205 if (form_element.isNull()) |
245 return false; | 206 return false; |
246 | 207 |
247 std::vector<WebFormControlElement> control_elements = | 208 std::vector<WebFormControlElement> control_elements = |
248 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); | 209 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); |
249 for (size_t i = 0; i < control_elements.size(); ++i) { | 210 for (size_t i = 0; i < control_elements.size(); ++i) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 } | 253 } |
293 | 254 |
294 return true; | 255 return true; |
295 } | 256 } |
296 | 257 |
297 bool FormCache::ShowPredictions(const FormDataPredictions& form) { | 258 bool FormCache::ShowPredictions(const FormDataPredictions& form) { |
298 DCHECK_EQ(form.data.fields.size(), form.fields.size()); | 259 DCHECK_EQ(form.data.fields.size(), form.fields.size()); |
299 | 260 |
300 std::vector<WebFormControlElement> control_elements; | 261 std::vector<WebFormControlElement> control_elements; |
301 | 262 |
302 // First check the synthetic forms. | 263 // First check the synthetic form. |
303 bool found_synthetic_form = false; | 264 bool found_synthetic_form = false; |
304 for (const auto& it : documents_to_synthetic_form_map_) { | 265 if (form.data.SameFormAs(synthetic_form_)) { |
305 const FormData& form_data = it.second; | |
306 if (!form_data.SameFormAs(form.data)) | |
307 continue; | |
308 | |
309 found_synthetic_form = true; | 266 found_synthetic_form = true; |
310 WebDocument document = it.first; | 267 WebDocument document = frame_.document(); |
311 control_elements = | 268 control_elements = |
312 GetUnownedAutofillableFormFieldElements(document.all(), nullptr); | 269 GetUnownedAutofillableFormFieldElements(document.all(), nullptr); |
313 break; | |
314 } | 270 } |
315 | 271 |
316 if (!found_synthetic_form) { | 272 if (!found_synthetic_form) { |
317 // Find the real form by searching through the WebDocuments. | 273 // Find the real form by searching through the WebDocuments. |
318 bool found_form = false; | 274 bool found_form = false; |
319 WebFormElement form_element; | 275 WebFormElement form_element; |
320 for (const auto& it : documents_to_synthetic_form_map_) { | 276 WebVector<WebFormElement> web_forms; |
321 WebVector<WebFormElement> web_forms; | 277 frame_.document().forms(web_forms); |
322 it.first.forms(web_forms); | |
323 | 278 |
324 for (size_t i = 0; i < web_forms.size(); ++i) { | 279 for (size_t i = 0; i < web_forms.size(); ++i) { |
325 form_element = web_forms[i]; | 280 form_element = web_forms[i]; |
326 | 281 // Note: matching on the form name here which is not guaranteed to be |
327 // Note: matching on the form name here which is not guaranteed to be | 282 // unique for the page, nor is it guaranteed to be non-empty. Ideally, |
328 // unique for the page, nor is it guaranteed to be non-empty. Ideally, | 283 // we would have a way to uniquely identify the form cross-process. For |
329 // we would have a way to uniquely identify the form cross-process. For | 284 // now, we'll check form name and form action for identity. |
330 // now, we'll check form name and form action for identity. | 285 // Also note that WebString() == WebString(string16()) does not evaluate |
331 // Also note that WebString() == WebString(string16()) does not evaluate | 286 // to |true| -- WebKit distinguishes between a "null" string (lhs) and |
332 // to |true| -- WebKit distinguishes between a "null" string (lhs) and | 287 // an "empty" string (rhs). We don't want that distinction, so forcing |
333 // an "empty" string (rhs). We don't want that distinction, so forcing | 288 // to string16. |
334 // to string16. | 289 base::string16 element_name = GetFormIdentifier(form_element); |
335 base::string16 element_name = GetFormIdentifier(form_element); | 290 GURL action(form_element.document().completeURL(form_element.action())); |
336 GURL action(form_element.document().completeURL(form_element.action())); | 291 if (element_name == form.data.name && action == form.data.action) { |
337 if (element_name == form.data.name && action == form.data.action) { | 292 found_form = true; |
338 found_form = true; | 293 control_elements = |
339 control_elements = | 294 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); |
340 ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); | 295 break; |
341 break; | |
342 } | |
343 } | 296 } |
344 } | 297 } |
345 | 298 |
346 if (!found_form) | 299 if (!found_form) |
347 return false; | 300 return false; |
348 } | 301 } |
349 | 302 |
350 if (control_elements.size() != form.fields.size()) { | 303 if (control_elements.size() != form.fields.size()) { |
351 // Keep things simple. Don't show predictions for forms that were modified | 304 // Keep things simple. Don't show predictions for forms that were modified |
352 // between page load and the server's response to our query. | 305 // between page load and the server's response to our query. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 std::make_pair(input_element, input_element.isChecked())); | 361 std::make_pair(input_element, input_element.isChecked())); |
409 } else { | 362 } else { |
410 ++num_editable_elements; | 363 ++num_editable_elements; |
411 } | 364 } |
412 } | 365 } |
413 } | 366 } |
414 return num_editable_elements; | 367 return num_editable_elements; |
415 } | 368 } |
416 | 369 |
417 } // namespace autofill | 370 } // namespace autofill |
OLD | NEW |