| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/renderer/autofill/form_manager.h" | 5 #include "chrome/renderer/autofill/form_manager.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/scoped_vector.h" | 8 #include "base/scoped_vector.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 void FormManager::WebFormControlElementToFormField( | 327 void FormManager::WebFormControlElementToFormField( |
| 328 const WebFormControlElement& element, | 328 const WebFormControlElement& element, |
| 329 ExtractMask extract_mask, | 329 ExtractMask extract_mask, |
| 330 FormField* field) { | 330 FormField* field) { |
| 331 DCHECK(field); | 331 DCHECK(field); |
| 332 DCHECK(!element.isNull()); | 332 DCHECK(!element.isNull()); |
| 333 | 333 |
| 334 // The label is not officially part of a WebFormControlElement; however, the | 334 // The label is not officially part of a WebFormControlElement; however, the |
| 335 // labels for all form control elements are scraped from the DOM and set in | 335 // labels for all form control elements are scraped from the DOM and set in |
| 336 // WebFormElementToFormData. | 336 // WebFormElementToFormData. |
| 337 field->set_name(element.nameForAutofill()); | 337 field->name = element.nameForAutofill(); |
| 338 field->set_form_control_type(element.formControlType()); | 338 field->form_control_type = element.formControlType(); |
| 339 | 339 |
| 340 if (!IsAutoFillableElement(element)) | 340 if (!IsAutoFillableElement(element)) |
| 341 return; | 341 return; |
| 342 | 342 |
| 343 const WebInputElement* input_element = toWebInputElement(&element); | 343 const WebInputElement* input_element = toWebInputElement(&element); |
| 344 if (IsTextInput(input_element)) { | 344 if (IsTextInput(input_element)) { |
| 345 field->set_max_length(input_element->maxLength()); | 345 field->max_length = input_element->maxLength(); |
| 346 field->set_autofilled(input_element->isAutofilled()); | 346 field->is_autofilled = input_element->isAutofilled(); |
| 347 } else if (extract_mask & EXTRACT_OPTIONS) { | 347 } else if (extract_mask & EXTRACT_OPTIONS) { |
| 348 // Set option strings on the field if available. | 348 // Set option strings on the field if available. |
| 349 DCHECK(IsSelectElement(element)); | 349 DCHECK(IsSelectElement(element)); |
| 350 const WebSelectElement select_element = element.toConst<WebSelectElement>(); | 350 const WebSelectElement select_element = element.toConst<WebSelectElement>(); |
| 351 std::vector<string16> option_strings; | 351 std::vector<string16> option_strings; |
| 352 GetOptionStringsFromElement(select_element, &option_strings); | 352 GetOptionStringsFromElement(select_element, &option_strings); |
| 353 field->set_option_strings(option_strings); | 353 field->option_strings = option_strings; |
| 354 } | 354 } |
| 355 | 355 |
| 356 if (!(extract_mask & EXTRACT_VALUE)) | 356 if (!(extract_mask & EXTRACT_VALUE)) |
| 357 return; | 357 return; |
| 358 | 358 |
| 359 string16 value; | 359 string16 value; |
| 360 if (IsTextInput(input_element)) { | 360 if (IsTextInput(input_element)) { |
| 361 value = input_element->value(); | 361 value = input_element->value(); |
| 362 } else { | 362 } else { |
| 363 DCHECK(IsSelectElement(element)); | 363 DCHECK(IsSelectElement(element)); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 380 } | 380 } |
| 381 } | 381 } |
| 382 | 382 |
| 383 // TODO(jhawkins): This is a temporary stop-gap measure designed to prevent | 383 // TODO(jhawkins): This is a temporary stop-gap measure designed to prevent |
| 384 // a malicious site from DOS'ing the browser with extremely large profile | 384 // a malicious site from DOS'ing the browser with extremely large profile |
| 385 // data. The correct solution is to parse this data asynchronously. | 385 // data. The correct solution is to parse this data asynchronously. |
| 386 // See http://crbug.com/49332. | 386 // See http://crbug.com/49332. |
| 387 if (value.size() > kMaxDataLength) | 387 if (value.size() > kMaxDataLength) |
| 388 value = value.substr(0, kMaxDataLength); | 388 value = value.substr(0, kMaxDataLength); |
| 389 | 389 |
| 390 field->set_value(value); | 390 field->value = value; |
| 391 } | 391 } |
| 392 | 392 |
| 393 // static | 393 // static |
| 394 string16 FormManager::LabelForElement(const WebFormControlElement& element) { | 394 string16 FormManager::LabelForElement(const WebFormControlElement& element) { |
| 395 // Don't scrape labels for elements we can't possibly autofill anyway. | 395 // Don't scrape labels for elements we can't possibly autofill anyway. |
| 396 if (!IsAutoFillableElement(element)) | 396 if (!IsAutoFillableElement(element)) |
| 397 return string16(); | 397 return string16(); |
| 398 | 398 |
| 399 WebNodeList labels = element.document().getElementsByTagName("label"); | 399 WebNodeList labels = element.document().getElementsByTagName("label"); |
| 400 for (unsigned i = 0; i < labels.length(); ++i) { | 400 for (unsigned i = 0; i < labels.length(); ++i) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) | 461 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) |
| 462 continue; | 462 continue; |
| 463 | 463 |
| 464 // Create a new FormField, fill it out and map it to the field's name. | 464 // Create a new FormField, fill it out and map it to the field's name. |
| 465 FormField* field = new FormField; | 465 FormField* field = new FormField; |
| 466 WebFormControlElementToFormField(control_element, extract_mask, field); | 466 WebFormControlElementToFormField(control_element, extract_mask, field); |
| 467 form_fields.push_back(field); | 467 form_fields.push_back(field); |
| 468 // TODO(jhawkins): A label element is mapped to a form control element's id. | 468 // TODO(jhawkins): A label element is mapped to a form control element's id. |
| 469 // field->name() will contain the id only if the name does not exist. Add | 469 // field->name() will contain the id only if the name does not exist. Add |
| 470 // an id() method to WebFormControlElement and use that here. | 470 // an id() method to WebFormControlElement and use that here. |
| 471 name_map[field->name()] = field; | 471 name_map[field->name] = field; |
| 472 fields_extracted[i] = true; | 472 fields_extracted[i] = true; |
| 473 } | 473 } |
| 474 | 474 |
| 475 // Don't extract field labels if we have no fields. | 475 // Don't extract field labels if we have no fields. |
| 476 if (form_fields.empty()) | 476 if (form_fields.empty()) |
| 477 return false; | 477 return false; |
| 478 | 478 |
| 479 // Loop through the label elements inside the form element. For each label | 479 // Loop through the label elements inside the form element. For each label |
| 480 // element, get the corresponding form control element, use the form control | 480 // element, get the corresponding form control element, use the form control |
| 481 // element's name as a key into the <name, FormField> map to find the | 481 // element's name as a key into the <name, FormField> map to find the |
| 482 // previously created FormField and set the FormField's label to the | 482 // previously created FormField and set the FormField's label to the |
| 483 // label.firstChild().nodeValue() of the label element. | 483 // label.firstChild().nodeValue() of the label element. |
| 484 WebNodeList labels = element.getElementsByTagName("label"); | 484 WebNodeList labels = element.getElementsByTagName("label"); |
| 485 for (unsigned i = 0; i < labels.length(); ++i) { | 485 for (unsigned i = 0; i < labels.length(); ++i) { |
| 486 WebLabelElement label = labels.item(i).to<WebLabelElement>(); | 486 WebLabelElement label = labels.item(i).to<WebLabelElement>(); |
| 487 WebFormControlElement field_element = | 487 WebFormControlElement field_element = |
| 488 label.correspondingControl().to<WebFormControlElement>(); | 488 label.correspondingControl().to<WebFormControlElement>(); |
| 489 if (field_element.isNull() || | 489 if (field_element.isNull() || |
| 490 !field_element.isFormControlElement() || | 490 !field_element.isFormControlElement() || |
| 491 field_element.formControlType() == WebString::fromUTF8("hidden")) | 491 field_element.formControlType() == WebString::fromUTF8("hidden")) |
| 492 continue; | 492 continue; |
| 493 | 493 |
| 494 std::map<string16, FormField*>::iterator iter = | 494 std::map<string16, FormField*>::iterator iter = |
| 495 name_map.find(field_element.nameForAutofill()); | 495 name_map.find(field_element.nameForAutofill()); |
| 496 if (iter != name_map.end()) | 496 if (iter != name_map.end()) |
| 497 iter->second->set_label(FindChildText(label)); | 497 iter->second->label = FindChildText(label); |
| 498 } | 498 } |
| 499 | 499 |
| 500 // Loop through the form control elements, extracting the label text from the | 500 // Loop through the form control elements, extracting the label text from the |
| 501 // DOM. We use the |fields_extracted| vector to make sure we assign the | 501 // DOM. We use the |fields_extracted| vector to make sure we assign the |
| 502 // extracted label to the correct field, as it's possible |form_fields| will | 502 // extracted label to the correct field, as it's possible |form_fields| will |
| 503 // not contain all of the elements in |control_elements|. | 503 // not contain all of the elements in |control_elements|. |
| 504 for (size_t i = 0, field_idx = 0; | 504 for (size_t i = 0, field_idx = 0; |
| 505 i < control_elements.size() && field_idx < form_fields.size(); ++i) { | 505 i < control_elements.size() && field_idx < form_fields.size(); ++i) { |
| 506 // This field didn't meet the requirements, so don't try to find a label for | 506 // This field didn't meet the requirements, so don't try to find a label for |
| 507 // it. | 507 // it. |
| 508 if (!fields_extracted[i]) | 508 if (!fields_extracted[i]) |
| 509 continue; | 509 continue; |
| 510 | 510 |
| 511 const WebFormControlElement& control_element = control_elements[i]; | 511 const WebFormControlElement& control_element = control_elements[i]; |
| 512 if (form_fields[field_idx]->label().empty()) | 512 if (form_fields[field_idx]->label.empty()) |
| 513 form_fields[field_idx]->set_label(InferLabelForElement(control_element)); | 513 form_fields[field_idx]->label = InferLabelForElement(control_element); |
| 514 | 514 |
| 515 ++field_idx; | 515 ++field_idx; |
| 516 } | 516 } |
| 517 | 517 |
| 518 // Copy the created FormFields into the resulting FormData object. | 518 // Copy the created FormFields into the resulting FormData object. |
| 519 for (ScopedVector<FormField>::const_iterator iter = form_fields.begin(); | 519 for (ScopedVector<FormField>::const_iterator iter = form_fields.begin(); |
| 520 iter != form_fields.end(); ++iter) { | 520 iter != form_fields.end(); ++iter) { |
| 521 form->fields.push_back(**iter); | 521 form->fields.push_back(**iter); |
| 522 } | 522 } |
| 523 | 523 |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 // one case in the wild where this happens, paypal.com signup form, the fields | 826 // one case in the wild where this happens, paypal.com signup form, the fields |
| 827 // are appended to the end of the form and are not visible. | 827 // are appended to the end of the form and are not visible. |
| 828 for (size_t i = 0, j = 0; | 828 for (size_t i = 0, j = 0; |
| 829 i < form->control_elements.size() && j < data.fields.size(); | 829 i < form->control_elements.size() && j < data.fields.size(); |
| 830 ++i) { | 830 ++i) { |
| 831 WebFormControlElement* element = &form->control_elements[i]; | 831 WebFormControlElement* element = &form->control_elements[i]; |
| 832 string16 element_name(element->nameForAutofill()); | 832 string16 element_name(element->nameForAutofill()); |
| 833 | 833 |
| 834 // Search forward in the |form| for a corresponding field. | 834 // Search forward in the |form| for a corresponding field. |
| 835 size_t k = j; | 835 size_t k = j; |
| 836 while (k < data.fields.size() && element_name != data.fields[k].name()) | 836 while (k < data.fields.size() && element_name != data.fields[k].name) |
| 837 k++; | 837 k++; |
| 838 | 838 |
| 839 if (k >= data.fields.size()) | 839 if (k >= data.fields.size()) |
| 840 continue; | 840 continue; |
| 841 | 841 |
| 842 DCHECK_EQ(data.fields[k].name(), element_name); | 842 DCHECK_EQ(data.fields[k].name, element_name); |
| 843 | 843 |
| 844 bool is_initiating_node = false; | 844 bool is_initiating_node = false; |
| 845 | 845 |
| 846 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or | 846 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or |
| 847 // REQUIRE_EMPTY, which both require text form control elements, so special- | 847 // REQUIRE_EMPTY, which both require text form control elements, so special- |
| 848 // case this type of element. | 848 // case this type of element. |
| 849 const WebInputElement* input_element = toWebInputElement(element); | 849 const WebInputElement* input_element = toWebInputElement(element); |
| 850 if (IsTextInput(input_element)) { | 850 if (IsTextInput(input_element)) { |
| 851 | 851 |
| 852 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete | 852 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete |
| (...skipping 20 matching lines...) Expand all Loading... |
| 873 ++j; | 873 ++j; |
| 874 } | 874 } |
| 875 | 875 |
| 876 delete callback; | 876 delete callback; |
| 877 } | 877 } |
| 878 | 878 |
| 879 void FormManager::FillFormField(WebFormControlElement* field, | 879 void FormManager::FillFormField(WebFormControlElement* field, |
| 880 const FormField* data, | 880 const FormField* data, |
| 881 bool is_initiating_node) { | 881 bool is_initiating_node) { |
| 882 // Nothing to fill. | 882 // Nothing to fill. |
| 883 if (data->value().empty()) | 883 if (data->value.empty()) |
| 884 return; | 884 return; |
| 885 | 885 |
| 886 WebInputElement* input_element = toWebInputElement(field); | 886 WebInputElement* input_element = toWebInputElement(field); |
| 887 if (IsTextInput(input_element)) { | 887 if (IsTextInput(input_element)) { |
| 888 // If the maxlength attribute contains a negative value, maxLength() | 888 // If the maxlength attribute contains a negative value, maxLength() |
| 889 // returns the default maxlength value. | 889 // returns the default maxlength value. |
| 890 input_element->setValue( | 890 input_element->setValue( |
| 891 data->value().substr(0, input_element->maxLength())); | 891 data->value.substr(0, input_element->maxLength())); |
| 892 input_element->setAutofilled(true); | 892 input_element->setAutofilled(true); |
| 893 if (is_initiating_node) { | 893 if (is_initiating_node) { |
| 894 int length = input_element->value().length(); | 894 int length = input_element->value().length(); |
| 895 input_element->setSelectionRange(length, length); | 895 input_element->setSelectionRange(length, length); |
| 896 } | 896 } |
| 897 } else { | 897 } else { |
| 898 DCHECK(IsSelectElement(*field)); | 898 DCHECK(IsSelectElement(*field)); |
| 899 WebSelectElement select_element = field->to<WebSelectElement>(); | 899 WebSelectElement select_element = field->to<WebSelectElement>(); |
| 900 select_element.setValue(data->value()); | 900 select_element.setValue(data->value); |
| 901 } | 901 } |
| 902 } | 902 } |
| 903 | 903 |
| 904 void FormManager::PreviewFormField(WebFormControlElement* field, | 904 void FormManager::PreviewFormField(WebFormControlElement* field, |
| 905 const FormField* data, | 905 const FormField* data, |
| 906 bool is_initiating_node) { | 906 bool is_initiating_node) { |
| 907 // Nothing to preview. | 907 // Nothing to preview. |
| 908 if (data->value().empty()) | 908 if (data->value.empty()) |
| 909 return; | 909 return; |
| 910 | 910 |
| 911 // Only preview input fields. | 911 // Only preview input fields. |
| 912 WebInputElement* input_element = toWebInputElement(field); | 912 WebInputElement* input_element = toWebInputElement(field); |
| 913 if (!IsTextInput(input_element)) | 913 if (!IsTextInput(input_element)) |
| 914 return; | 914 return; |
| 915 | 915 |
| 916 // If the maxlength attribute contains a negative value, maxLength() | 916 // If the maxlength attribute contains a negative value, maxLength() |
| 917 // returns the default maxlength value. | 917 // returns the default maxlength value. |
| 918 input_element->setSuggestedValue( | 918 input_element->setSuggestedValue( |
| 919 data->value().substr(0, input_element->maxLength())); | 919 data->value.substr(0, input_element->maxLength())); |
| 920 input_element->setAutofilled(true); | 920 input_element->setAutofilled(true); |
| 921 if (is_initiating_node) { | 921 if (is_initiating_node) { |
| 922 // Select the part of the text that the user didn't type. | 922 // Select the part of the text that the user didn't type. |
| 923 input_element->setSelectionRange(input_element->value().length(), | 923 input_element->setSelectionRange(input_element->value().length(), |
| 924 input_element->suggestedValue().length()); | 924 input_element->suggestedValue().length()); |
| 925 } | 925 } |
| 926 } | 926 } |
| 927 | 927 |
| 928 } // namespace autofill | 928 } // namespace autofill |
| OLD | NEW |