Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: components/autofill/content/renderer/form_cache.cc

Issue 803673002: Autofill: one FormCache per WebFrame. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: better docs Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698