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