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

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: merge 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
« no previous file with comments | « components/autofill/content/renderer/form_cache.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/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
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
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
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
OLDNEW
« no previous file with comments | « components/autofill/content/renderer/form_cache.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698