| 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 |