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/form_manager.h" | 5 #include "chrome/renderer/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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 if (!child_text.empty()) | 65 if (!child_text.empty()) |
66 element_text = element_text + child_text; | 66 element_text = element_text + child_text; |
67 | 67 |
68 string16 sibling_text = FindChildTextInner(node.nextSibling()); | 68 string16 sibling_text = FindChildTextInner(node.nextSibling()); |
69 if (!sibling_text.empty()) | 69 if (!sibling_text.empty()) |
70 element_text = element_text + sibling_text; | 70 element_text = element_text + sibling_text; |
71 | 71 |
72 return element_text; | 72 return element_text; |
73 } | 73 } |
74 | 74 |
75 // Returns the node value of the first decendant of |element| that is a | 75 // Returns the node value of the first descendant of |element| that is a |
76 // non-empty text node. "Non-empty" in this case means non-empty after the | 76 // non-empty text node. "Non-empty" in this case means non-empty after the |
77 // whitespace has been stripped. | 77 // whitespace has been stripped. |
78 string16 FindChildText(const WebElement& element) { | 78 string16 FindChildText(const WebElement& element) { |
79 WebNode child = element.firstChild(); | 79 WebNode child = element.firstChild(); |
80 return FindChildTextInner(child); | 80 return FindChildTextInner(child); |
81 } | 81 } |
82 | 82 |
83 // Helper for |InferLabelForElement()| that infers a label, if possible, from | 83 // Helper for |InferLabelForElement()| that infers a label, if possible, from |
84 // a previous node of |element|. | 84 // a previous node of |element|. |
85 string16 InferLabelFromPrevious( | 85 string16 InferLabelFromPrevious( |
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 return true; | 509 return true; |
510 } | 510 } |
511 } | 511 } |
512 } | 512 } |
513 | 513 |
514 return false; | 514 return false; |
515 } | 515 } |
516 | 516 |
517 bool FormManager::FillForm(const FormData& form) { | 517 bool FormManager::FillForm(const FormData& form) { |
518 FormElement* form_element = NULL; | 518 FormElement* form_element = NULL; |
519 | 519 if (!FindCachedFormElement(form, &form_element)) |
520 for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin(); | |
521 iter != form_elements_map_.end(); ++iter) { | |
522 const WebFrame* frame = iter->first; | |
523 | |
524 for (std::vector<FormElement*>::iterator form_iter = iter->second.begin(); | |
525 form_iter != iter->second.end(); ++form_iter) { | |
526 // TODO(dhollowa): matching on form name here which is not guaranteed to | |
527 // be unique for the page, nor is it guaranteed to be non-empty. Need to | |
528 // find a way to uniquely identify the form cross-process. For now we'll | |
529 // check form name and form action for identity. | |
530 // http://crbug.com/37990 test file sample8.html. | |
531 // Also note that WebString() == WebString(string16()) does not seem to | |
532 // evaluate to |true| for some reason TBD, so forcing to string16. | |
533 string16 element_name((*form_iter)->form_element.name()); | |
534 GURL action( | |
535 frame->document().completeURL((*form_iter)->form_element.action())); | |
536 if (element_name == form.name && action == form.action) { | |
537 form_element = *form_iter; | |
538 break; | |
539 } | |
540 } | |
541 } | |
542 | |
543 if (!form_element) | |
544 return false; | 520 return false; |
545 | 521 |
546 // It's possible that the site has injected fields into the form after the | 522 ForEachMatchingFormField( |
547 // page has loaded, so we can't assert that the size of the cached control | 523 form_element, form, NewCallback(this, &FormManager::FillFormField)); |
548 // elements is equal to the size of the fields in |form|. Fortunately, the | |
549 // one case in the wild where this happens, paypal.com signup form, the fields | |
550 // are appended to the end of the form and are not visible. | |
551 | |
552 for (size_t i = 0, j = 0; | |
553 i < form_element->control_elements.size() && j < form.fields.size(); | |
554 ++i) { | |
555 // Once again, empty WebString != empty string16, so we have to explicitly | |
556 // check for this case. | |
557 if (form_element->control_elements[i].nameForAutofill().length() == 0 && | |
558 form.fields[j].name().empty()) | |
559 continue; | |
560 | |
561 size_t k = j; | |
562 while (k < form.fields.size() && | |
563 form_element->control_elements[i].nameForAutofill() != | |
564 form.fields[k].name()) { | |
565 k++; | |
566 } | |
567 if (k >= form.fields.size()) | |
568 continue; | |
569 | |
570 WebFormControlElement* element = &form_element->control_elements[i]; | |
571 | |
572 // It's possible that nameForAutofill() is empty if the form control | |
573 // element has no name or ID. In that case, iter->nameForAutofill() must | |
574 // also be empty. | |
575 if (form.fields[k].name().empty()) | |
576 DCHECK(element->nameForAutofill().isEmpty()); | |
577 else | |
578 DCHECK_EQ(form.fields[k].name(), element->nameForAutofill()); | |
579 | |
580 if (!form.fields[k].value().empty() && | |
581 element->formControlType() != WebString::fromUTF8("submit")) { | |
582 if (element->formControlType() == WebString::fromUTF8("text")) { | |
583 WebInputElement input_element = element->to<WebInputElement>(); | |
584 // If the maxlength attribute contains a negative value, maxLength() | |
585 // returns the default maxlength value. | |
586 input_element.setValue( | |
587 form.fields[k].value().substr(0, input_element.maxLength())); | |
588 input_element.setAutofilled(true); | |
589 } else if (element->formControlType() == | |
590 WebString::fromUTF8("select-one")) { | |
591 WebSelectElement select_element = | |
592 element->to<WebSelectElement>(); | |
593 select_element.setValue(form.fields[k].value()); | |
594 } | |
595 } | |
596 | |
597 // We found a matching form field so move on to the next. | |
598 ++j; | |
599 } | |
600 | 524 |
601 return true; | 525 return true; |
602 } | 526 } |
603 | 527 |
604 void FormManager::FillForms(const std::vector<webkit_glue::FormData>& forms) { | 528 void FormManager::FillForms(const std::vector<webkit_glue::FormData>& forms) { |
605 for (std::vector<webkit_glue::FormData>::const_iterator iter = forms.begin(); | 529 for (std::vector<webkit_glue::FormData>::const_iterator iter = forms.begin(); |
606 iter != forms.end(); ++iter) { | 530 iter != forms.end(); ++iter) { |
607 FillForm(*iter); | 531 FillForm(*iter); |
608 } | 532 } |
609 } | 533 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 } | 604 } |
681 | 605 |
682 // If we didn't find a label, check for definition list case. | 606 // If we didn't find a label, check for definition list case. |
683 if (inferred_label.empty()) { | 607 if (inferred_label.empty()) { |
684 inferred_label = InferLabelFromDefinitionList(element); | 608 inferred_label = InferLabelFromDefinitionList(element); |
685 } | 609 } |
686 | 610 |
687 return inferred_label; | 611 return inferred_label; |
688 } | 612 } |
689 | 613 |
| 614 bool FormManager::FindCachedFormElement(const FormData& form, |
| 615 FormElement** form_element) { |
| 616 for (WebFrameFormElementMap::iterator iter = form_elements_map_.begin(); |
| 617 iter != form_elements_map_.end(); ++iter) { |
| 618 const WebFrame* frame = iter->first; |
| 619 |
| 620 for (std::vector<FormElement*>::iterator form_iter = iter->second.begin(); |
| 621 form_iter != iter->second.end(); ++form_iter) { |
| 622 // TODO(dhollowa): matching on form name here which is not guaranteed to |
| 623 // be unique for the page, nor is it guaranteed to be non-empty. Need to |
| 624 // find a way to uniquely identify the form cross-process. For now we'll |
| 625 // check form name and form action for identity. |
| 626 // http://crbug.com/37990 test file sample8.html. |
| 627 // Also note that WebString() == WebString(string16()) does not seem to |
| 628 // evaluate to |true| for some reason TBD, so forcing to string16. |
| 629 string16 element_name((*form_iter)->form_element.name()); |
| 630 GURL action( |
| 631 frame->document().completeURL((*form_iter)->form_element.action())); |
| 632 if (element_name == form.name && action == form.action) { |
| 633 *form_element = *form_iter; |
| 634 return true; |
| 635 } |
| 636 } |
| 637 } |
| 638 |
| 639 return false; |
| 640 } |
| 641 |
| 642 void FormManager::ForEachMatchingFormField( |
| 643 FormElement* form, const FormData& data, Callback* callback) { |
| 644 // It's possible that the site has injected fields into the form after the |
| 645 // page has loaded, so we can't assert that the size of the cached control |
| 646 // elements is equal to the size of the fields in |form|. Fortunately, the |
| 647 // one case in the wild where this happens, paypal.com signup form, the fields |
| 648 // are appended to the end of the form and are not visible. |
| 649 for (size_t i = 0, j = 0; |
| 650 i < form->control_elements.size() && j < data.fields.size(); |
| 651 ++i) { |
| 652 WebFormControlElement* element = &form->control_elements[i]; |
| 653 WebString element_name = element->nameForAutofill(); |
| 654 |
| 655 // Empty WebString != empty string16, so we have to explicitly |
| 656 // check for this case. |
| 657 if (element_name.isEmpty() && data.fields[j].name().empty()) |
| 658 continue; |
| 659 |
| 660 // Search forward in the |form| for a corresponding field. |
| 661 size_t k = j; |
| 662 while (k < data.fields.size() && element_name != data.fields[k].name()) |
| 663 k++; |
| 664 |
| 665 if (k >= data.fields.size()) |
| 666 continue; |
| 667 |
| 668 DCHECK_EQ(data.fields[k].name(), element_name); |
| 669 callback->Run(element, &data.fields[k]); |
| 670 |
| 671 // We found a matching form field so move on to the next. |
| 672 ++j; |
| 673 } |
| 674 |
| 675 delete callback; |
| 676 } |
| 677 |
| 678 void FormManager::FillFormField(WebKit::WebFormControlElement* field, |
| 679 const FormField* data) { |
| 680 // Nothing to fill. |
| 681 if (data->value().empty()) |
| 682 return; |
| 683 |
| 684 if (field->formControlType() == WebString::fromUTF8("text")) { |
| 685 WebInputElement input_element = field->to<WebInputElement>(); |
| 686 |
| 687 // Don't auto-fill a field with autocomplete=off. |
| 688 if (!input_element.autoComplete()) |
| 689 return; |
| 690 |
| 691 // Don't overwrite a pre-existing value in the field. |
| 692 if (!input_element.value().isEmpty()) |
| 693 return; |
| 694 |
| 695 // If the maxlength attribute contains a negative value, maxLength() |
| 696 // returns the default maxlength value. |
| 697 input_element.setValue(data->value().substr(0, input_element.maxLength())); |
| 698 input_element.setAutofilled(true); |
| 699 } else if (field->formControlType() == WebString::fromUTF8("select-one")) { |
| 700 WebSelectElement select_element = field->to<WebSelectElement>(); |
| 701 select_element.setValue(data->value()); |
| 702 } |
| 703 } |
OLD | NEW |