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