| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_autofill_util.h" | 5 #include "chrome/renderer/autofill/form_autofill_util.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_vector.h" | 10 #include "base/memory/scoped_vector.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 using WebKit::WebNode; | 35 using WebKit::WebNode; |
| 36 using WebKit::WebNodeList; | 36 using WebKit::WebNodeList; |
| 37 using WebKit::WebOptionElement; | 37 using WebKit::WebOptionElement; |
| 38 using WebKit::WebSelectElement; | 38 using WebKit::WebSelectElement; |
| 39 using WebKit::WebString; | 39 using WebKit::WebString; |
| 40 using WebKit::WebVector; | 40 using WebKit::WebVector; |
| 41 | 41 |
| 42 namespace { | 42 namespace { |
| 43 | 43 |
| 44 using autofill::ExtractAutofillableElements; | 44 using autofill::ExtractAutofillableElements; |
| 45 using autofill::IsAutofillableInputElement; |
| 46 using autofill::IsCheckboxElement; |
| 47 using autofill::IsRadioButtonElement; |
| 48 using autofill::IsSelectElement; |
| 45 using autofill::IsTextInput; | 49 using autofill::IsTextInput; |
| 46 using autofill::IsSelectElement; | |
| 47 | 50 |
| 48 // The maximum length allowed for form data. | 51 // The maximum length allowed for form data. |
| 49 const size_t kMaxDataLength = 1024; | 52 const size_t kMaxDataLength = 1024; |
| 50 | 53 |
| 51 bool IsOptionElement(const WebElement& element) { | 54 bool IsOptionElement(const WebElement& element) { |
| 52 return element.hasTagName("option"); | 55 return element.hasTagName("option"); |
| 53 } | 56 } |
| 54 | 57 |
| 55 bool IsScriptElement(const WebElement& element) { | 58 bool IsScriptElement(const WebElement& element) { |
| 56 return element.hasTagName("script"); | 59 return element.hasTagName("script"); |
| 57 } | 60 } |
| 58 | 61 |
| 59 bool IsNoScriptElement(const WebElement& element) { | 62 bool IsNoScriptElement(const WebElement& element) { |
| 60 return element.hasTagName("noscript"); | 63 return element.hasTagName("noscript"); |
| 61 } | 64 } |
| 62 | 65 |
| 63 bool HasTagName(const WebNode& node, const WebKit::WebString& tag) { | 66 bool HasTagName(const WebNode& node, const WebKit::WebString& tag) { |
| 64 return node.isElementNode() && node.toConst<WebElement>().hasTagName(tag); | 67 return node.isElementNode() && node.toConst<WebElement>().hasTagName(tag); |
| 65 } | 68 } |
| 66 | 69 |
| 67 bool IsAutofillableElement(const WebFormControlElement& element) { | 70 bool IsAutofillableElement(const WebFormControlElement& element) { |
| 68 const WebInputElement* input_element = toWebInputElement(&element); | 71 const WebInputElement* input_element = toWebInputElement(&element); |
| 69 return IsTextInput(input_element) || IsSelectElement(element); | 72 return IsAutofillableInputElement(input_element) || IsSelectElement(element); |
| 70 } | 73 } |
| 71 | 74 |
| 72 // Appends |suffix| to |prefix| so that any intermediary whitespace is collapsed | 75 // Appends |suffix| to |prefix| so that any intermediary whitespace is collapsed |
| 73 // to a single space. If |force_whitespace| is true, then the resulting string | 76 // to a single space. If |force_whitespace| is true, then the resulting string |
| 74 // is guaranteed to have a space between |prefix| and |suffix|. Otherwise, the | 77 // is guaranteed to have a space between |prefix| and |suffix|. Otherwise, the |
| 75 // result includes a space only if |prefix| has trailing whitespace or |suffix| | 78 // result includes a space only if |prefix| has trailing whitespace or |suffix| |
| 76 // has leading whitespace. | 79 // has leading whitespace. |
| 77 // A few examples: | 80 // A few examples: |
| 78 // * CombineAndCollapseWhitespace("foo", "bar", false) -> "foobar" | 81 // * CombineAndCollapseWhitespace("foo", "bar", false) -> "foobar" |
| 79 // * CombineAndCollapseWhitespace("foo", "bar", true) -> "foo bar" | 82 // * CombineAndCollapseWhitespace("foo", "bar", true) -> "foo bar" |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 // popup. I (isherman) am not aware of any such websites, and so am | 454 // popup. I (isherman) am not aware of any such websites, and so am |
| 452 // optimistically including a NOTREACHED(). If you ever trip this check, | 455 // optimistically including a NOTREACHED(). If you ever trip this check, |
| 453 // please file a bug against me. | 456 // please file a bug against me. |
| 454 NOTREACHED(); | 457 NOTREACHED(); |
| 455 continue; | 458 continue; |
| 456 } | 459 } |
| 457 | 460 |
| 458 bool is_initiating_element = (*element == initiating_element); | 461 bool is_initiating_element = (*element == initiating_element); |
| 459 | 462 |
| 460 const WebInputElement* input_element = toWebInputElement(element); | 463 const WebInputElement* input_element = toWebInputElement(element); |
| 461 if (IsTextInput(input_element)) { | 464 if (IsAutofillableInputElement(input_element)) { |
| 462 // Only autofill empty fields and the field that initiated the filling, | 465 // Only autofill empty fields and the field that initiated the filling, |
| 463 // i.e. the field the user is currently editing and interacting with. | 466 // i.e. the field the user is currently editing and interacting with. |
| 464 if (!is_initiating_element && !input_element->value().isEmpty()) | 467 if (!is_initiating_element && IsTextInput(input_element) && |
| 468 !input_element->value().isEmpty()) |
| 465 continue; | 469 continue; |
| 466 } | 470 } |
| 467 | 471 |
| 468 if (!element->isEnabled() || element->isReadOnly() || | 472 if (!element->isEnabled() || element->isReadOnly() || |
| 469 !element->isFocusable()) | 473 !element->isFocusable()) |
| 470 continue; | 474 continue; |
| 471 | 475 |
| 472 callback(element, &data.fields[i], is_initiating_element); | 476 callback(element, &data.fields[i], is_initiating_element); |
| 473 } | 477 } |
| 474 } | 478 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 488 // returns the default maxlength value. | 492 // returns the default maxlength value. |
| 489 input_element->setValue( | 493 input_element->setValue( |
| 490 data->value.substr(0, input_element->maxLength()), true); | 494 data->value.substr(0, input_element->maxLength()), true); |
| 491 input_element->setAutofilled(true); | 495 input_element->setAutofilled(true); |
| 492 if (is_initiating_node) { | 496 if (is_initiating_node) { |
| 493 int length = input_element->value().length(); | 497 int length = input_element->value().length(); |
| 494 input_element->setSelectionRange(length, length); | 498 input_element->setSelectionRange(length, length); |
| 495 // Clear the current IME composition (the underline), if there is one. | 499 // Clear the current IME composition (the underline), if there is one. |
| 496 input_element->document().frame()->unmarkText(); | 500 input_element->document().frame()->unmarkText(); |
| 497 } | 501 } |
| 498 } else { | 502 } else if (IsSelectElement(*field)) { |
| 499 DCHECK(IsSelectElement(*field)); | |
| 500 WebSelectElement select_element = field->to<WebSelectElement>(); | 503 WebSelectElement select_element = field->to<WebSelectElement>(); |
| 501 if (select_element.value() != data->value) { | 504 if (select_element.value() != data->value) { |
| 502 select_element.setValue(data->value); | 505 select_element.setValue(data->value); |
| 503 select_element.dispatchFormControlChangeEvent(); | 506 select_element.dispatchFormControlChangeEvent(); |
| 504 } | 507 } |
| 508 } else { |
| 509 DCHECK(IsRadioButtonElement(input_element) || |
| 510 IsCheckboxElement(input_element)); |
| 511 input_element->setChecked(data->is_checked, true); |
| 505 } | 512 } |
| 506 } | 513 } |
| 507 | 514 |
| 508 // Sets the |field|'s "suggested" (non JS visible) value to the value in |data|. | 515 // Sets the |field|'s "suggested" (non JS visible) value to the value in |data|. |
| 509 // Also sets the "autofilled" attribute, causing the background to be yellow. | 516 // Also sets the "autofilled" attribute, causing the background to be yellow. |
| 510 void PreviewFormField(WebKit::WebFormControlElement* field, | 517 void PreviewFormField(WebKit::WebFormControlElement* field, |
| 511 const FormFieldData* data, | 518 const FormFieldData* data, |
| 512 bool is_initiating_node) { | 519 bool is_initiating_node) { |
| 513 // Nothing to preview. | 520 // Nothing to preview. |
| 514 if (data->value.empty()) | 521 if (data->value.empty()) |
| 515 return; | 522 return; |
| 516 | 523 |
| 517 // Only preview input fields. | 524 // Only preview input fields. |
| 518 WebInputElement* input_element = toWebInputElement(field); | 525 WebInputElement* input_element = toWebInputElement(field); |
| 526 // Don't preview checkboxes and radio buttons, as there is no provision for |
| 527 // setSuggestedCheckedValue in WebInputElement. |
| 519 if (!IsTextInput(input_element)) | 528 if (!IsTextInput(input_element)) |
| 520 return; | 529 return; |
| 521 | 530 |
| 522 // If the maxlength attribute contains a negative value, maxLength() | 531 // If the maxlength attribute contains a negative value, maxLength() |
| 523 // returns the default maxlength value. | 532 // returns the default maxlength value. |
| 524 input_element->setSuggestedValue( | 533 input_element->setSuggestedValue( |
| 525 data->value.substr(0, input_element->maxLength())); | 534 data->value.substr(0, input_element->maxLength())); |
| 526 input_element->setAutofilled(true); | 535 input_element->setAutofilled(true); |
| 527 if (is_initiating_node) { | 536 if (is_initiating_node) { |
| 528 // Select the part of the text that the user didn't type. | 537 // Select the part of the text that the user didn't type. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 543 if (!element) | 552 if (!element) |
| 544 return false; | 553 return false; |
| 545 | 554 |
| 546 return element->isTextField() && !element->isPasswordField(); | 555 return element->isTextField() && !element->isPasswordField(); |
| 547 } | 556 } |
| 548 | 557 |
| 549 bool IsSelectElement(const WebFormControlElement& element) { | 558 bool IsSelectElement(const WebFormControlElement& element) { |
| 550 return element.formControlType() == ASCIIToUTF16("select-one"); | 559 return element.formControlType() == ASCIIToUTF16("select-one"); |
| 551 } | 560 } |
| 552 | 561 |
| 562 bool IsCheckboxElement(const WebInputElement* element) { |
| 563 if (!element) |
| 564 return false; |
| 565 |
| 566 return element->formControlType() == ASCIIToUTF16("checkbox"); |
| 567 } |
| 568 |
| 569 bool IsRadioButtonElement(const WebInputElement* element) { |
| 570 if (!element) |
| 571 return false; |
| 572 |
| 573 return element->formControlType() == ASCIIToUTF16("radio"); |
| 574 } |
| 575 |
| 576 bool IsAutofillableInputElement(const WebInputElement* element) { |
| 577 return IsTextInput(element) || IsCheckboxElement(element) || |
| 578 IsRadioButtonElement(element); |
| 579 } |
| 580 |
| 553 const string16 GetFormIdentifier(const WebFormElement& form) { | 581 const string16 GetFormIdentifier(const WebFormElement& form) { |
| 554 string16 identifier = form.name(); | 582 string16 identifier = form.name(); |
| 555 if (identifier.empty()) | 583 if (identifier.empty()) |
| 556 identifier = form.getAttribute(WebString("id")); | 584 identifier = form.getAttribute(WebString("id")); |
| 557 | 585 |
| 558 return identifier; | 586 return identifier; |
| 559 } | 587 } |
| 560 | 588 |
| 561 // Fills |autofillable_elements| with all the auto-fillable form control | 589 // Fills |autofillable_elements| with all the auto-fillable form control |
| 562 // elements in |form_element|. | 590 // elements in |form_element|. |
| 563 void ExtractAutofillableElements( | 591 void ExtractAutofillableElements( |
| 564 const WebFormElement& form_element, | 592 const WebFormElement& form_element, |
| 565 RequirementsMask requirements, | 593 RequirementsMask requirements, |
| 566 std::vector<WebFormControlElement>* autofillable_elements) { | 594 std::vector<WebFormControlElement>* autofillable_elements) { |
| 567 WebVector<WebFormControlElement> control_elements; | 595 WebVector<WebFormControlElement> control_elements; |
| 568 form_element.getFormControlElements(control_elements); | 596 form_element.getFormControlElements(control_elements); |
| 569 | 597 |
| 570 autofillable_elements->clear(); | 598 autofillable_elements->clear(); |
| 571 for (size_t i = 0; i < control_elements.size(); ++i) { | 599 for (size_t i = 0; i < control_elements.size(); ++i) { |
| 572 WebFormControlElement element = control_elements[i]; | 600 WebFormControlElement element = control_elements[i]; |
| 573 if (!IsAutofillableElement(element)) | 601 if (!IsAutofillableElement(element)) |
| 574 continue; | 602 continue; |
| 575 | 603 |
| 576 if (requirements & REQUIRE_AUTOCOMPLETE) { | 604 if (requirements & REQUIRE_AUTOCOMPLETE) { |
| 577 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete | 605 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete |
| 578 // attribute for select control elements, but it probably should. | 606 // attribute for select control elements, but it probably should. |
| 579 WebInputElement* input_element = toWebInputElement(&control_elements[i]); | 607 WebInputElement* input_element = toWebInputElement(&control_elements[i]); |
| 580 if (IsTextInput(input_element) && !input_element->autoComplete()) | 608 if (IsAutofillableInputElement(input_element) && |
| 609 !input_element->autoComplete()) |
| 581 continue; | 610 continue; |
| 582 } | 611 } |
| 583 | 612 |
| 584 autofillable_elements->push_back(element); | 613 autofillable_elements->push_back(element); |
| 585 } | 614 } |
| 586 } | 615 } |
| 587 | 616 |
| 588 void WebFormControlElementToFormField(const WebFormControlElement& element, | 617 void WebFormControlElementToFormField(const WebFormControlElement& element, |
| 589 ExtractMask extract_mask, | 618 ExtractMask extract_mask, |
| 590 FormFieldData* field) { | 619 FormFieldData* field) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 602 // Discard overly long attribute values to avoid DOS-ing the browser | 631 // Discard overly long attribute values to avoid DOS-ing the browser |
| 603 // process. However, send over a default string to indicate that the | 632 // process. However, send over a default string to indicate that the |
| 604 // attribute was present. | 633 // attribute was present. |
| 605 field->autocomplete_attribute = "x-max-data-length-exceeded"; | 634 field->autocomplete_attribute = "x-max-data-length-exceeded"; |
| 606 } | 635 } |
| 607 | 636 |
| 608 if (!IsAutofillableElement(element)) | 637 if (!IsAutofillableElement(element)) |
| 609 return; | 638 return; |
| 610 | 639 |
| 611 const WebInputElement* input_element = toWebInputElement(&element); | 640 const WebInputElement* input_element = toWebInputElement(&element); |
| 612 if (IsTextInput(input_element)) { | 641 if (IsAutofillableInputElement(input_element)) { |
| 613 field->max_length = input_element->maxLength(); | 642 field->max_length = input_element->maxLength(); |
| 614 field->is_autofilled = input_element->isAutofilled(); | 643 field->is_autofilled = input_element->isAutofilled(); |
| 615 field->is_focusable = input_element->isFocusable(); | 644 field->is_focusable = input_element->isFocusable(); |
| 616 field->should_autocomplete = input_element->autoComplete(); | 645 field->should_autocomplete = input_element->autoComplete(); |
| 646 if (IsRadioButtonElement(input_element) || |
| 647 IsCheckboxElement(input_element)) { |
| 648 field->is_checkable = true; |
| 649 } |
| 617 } else if (extract_mask & EXTRACT_OPTIONS) { | 650 } else if (extract_mask & EXTRACT_OPTIONS) { |
| 618 // Set option strings on the field if available. | 651 // Set option strings on the field if available. |
| 619 DCHECK(IsSelectElement(element)); | 652 DCHECK(IsSelectElement(element)); |
| 620 const WebSelectElement select_element = element.toConst<WebSelectElement>(); | 653 const WebSelectElement select_element = element.toConst<WebSelectElement>(); |
| 621 GetOptionStringsFromElement(select_element, | 654 GetOptionStringsFromElement(select_element, |
| 622 &field->option_values, | 655 &field->option_values, |
| 623 &field->option_contents); | 656 &field->option_contents); |
| 624 } | 657 } |
| 625 | 658 |
| 626 if (!(extract_mask & EXTRACT_VALUE)) | 659 if (!(extract_mask & EXTRACT_VALUE)) |
| 627 return; | 660 return; |
| 628 | 661 |
| 629 string16 value; | 662 string16 value; |
| 630 if (IsTextInput(input_element)) { | 663 if (IsAutofillableInputElement(input_element)) { |
| 631 value = input_element->value(); | 664 value = input_element->value(); |
| 632 } else { | 665 } else { |
| 633 DCHECK(IsSelectElement(element)); | 666 DCHECK(IsSelectElement(element)); |
| 634 const WebSelectElement select_element = element.toConst<WebSelectElement>(); | 667 const WebSelectElement select_element = element.toConst<WebSelectElement>(); |
| 635 value = select_element.value(); | 668 value = select_element.value(); |
| 636 | 669 |
| 637 // Convert the |select_element| value to text if requested. | 670 // Convert the |select_element| value to text if requested. |
| 638 if (extract_mask & EXTRACT_OPTION_TEXT) { | 671 if (extract_mask & EXTRACT_OPTION_TEXT) { |
| 639 WebVector<WebElement> list_items = select_element.listItems(); | 672 WebVector<WebElement> list_items = select_element.listItems(); |
| 640 for (size_t i = 0; i < list_items.size(); ++i) { | 673 for (size_t i = 0; i < list_items.size(); ++i) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 // requirements and thus will be in the resulting |form|. | 730 // requirements and thus will be in the resulting |form|. |
| 698 std::vector<bool> fields_extracted(control_elements.size(), false); | 731 std::vector<bool> fields_extracted(control_elements.size(), false); |
| 699 | 732 |
| 700 for (size_t i = 0; i < control_elements.size(); ++i) { | 733 for (size_t i = 0; i < control_elements.size(); ++i) { |
| 701 const WebFormControlElement& control_element = control_elements[i]; | 734 const WebFormControlElement& control_element = control_elements[i]; |
| 702 | 735 |
| 703 if (!IsAutofillableElement(control_element)) | 736 if (!IsAutofillableElement(control_element)) |
| 704 continue; | 737 continue; |
| 705 | 738 |
| 706 const WebInputElement* input_element = toWebInputElement(&control_element); | 739 const WebInputElement* input_element = toWebInputElement(&control_element); |
| 707 if (requirements & REQUIRE_AUTOCOMPLETE && IsTextInput(input_element) && | 740 if (requirements & REQUIRE_AUTOCOMPLETE && |
| 741 IsAutofillableInputElement(input_element) && |
| 708 !input_element->autoComplete()) | 742 !input_element->autoComplete()) |
| 709 continue; | 743 continue; |
| 710 | 744 |
| 711 // Create a new FormFieldData, fill it out and map it to the field's name. | 745 // Create a new FormFieldData, fill it out and map it to the field's name. |
| 712 FormFieldData* form_field = new FormFieldData; | 746 FormFieldData* form_field = new FormFieldData; |
| 713 WebFormControlElementToFormField(control_element, extract_mask, form_field); | 747 WebFormControlElementToFormField(control_element, extract_mask, form_field); |
| 714 form_fields.push_back(form_field); | 748 form_fields.push_back(form_field); |
| 715 // TODO(jhawkins): A label element is mapped to a form control element's id. | 749 // TODO(jhawkins): A label element is mapped to a form control element's id. |
| 716 // field->name() will contain the id only if the name does not exist. Add | 750 // field->name() will contain the id only if the name does not exist. Add |
| 717 // an id() method to WebFormControlElement and use that here. | 751 // an id() method to WebFormControlElement and use that here. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 WebFormElement form_element = element.form(); | 873 WebFormElement form_element = element.form(); |
| 840 if (form_element.isNull()) | 874 if (form_element.isNull()) |
| 841 return false; | 875 return false; |
| 842 | 876 |
| 843 std::vector<WebFormControlElement> control_elements; | 877 std::vector<WebFormControlElement> control_elements; |
| 844 ExtractAutofillableElements(form_element, REQUIRE_AUTOCOMPLETE, | 878 ExtractAutofillableElements(form_element, REQUIRE_AUTOCOMPLETE, |
| 845 &control_elements); | 879 &control_elements); |
| 846 for (size_t i = 0; i < control_elements.size(); ++i) { | 880 for (size_t i = 0; i < control_elements.size(); ++i) { |
| 847 // Only text input elements can be previewed. | 881 // Only text input elements can be previewed. |
| 848 WebInputElement* input_element = toWebInputElement(&control_elements[i]); | 882 WebInputElement* input_element = toWebInputElement(&control_elements[i]); |
| 849 if (!IsTextInput(input_element)) | 883 if (!IsAutofillableInputElement(input_element)) |
| 850 continue; | 884 continue; |
| 851 | 885 |
| 852 // If the input element is not auto-filled, we did not preview it, so there | 886 // If the input element is not auto-filled, we did not preview it, so there |
| 853 // is nothing to reset. | 887 // is nothing to reset. |
| 854 if (!input_element->isAutofilled()) | 888 if (!input_element->isAutofilled()) |
| 855 continue; | 889 continue; |
| 856 | 890 |
| 857 // There might be unrelated elements in this form which have already been | 891 // There might be unrelated elements in this form which have already been |
| 858 // auto-filled. For example, the user might have already filled the address | 892 // auto-filled. For example, the user might have already filled the address |
| 859 // part of a form and now be dealing with the credit card section. We only | 893 // part of a form and now be dealing with the credit card section. We only |
| (...skipping 25 matching lines...) Expand all Loading... |
| 885 bool FormWithElementIsAutofilled(const WebInputElement& element) { | 919 bool FormWithElementIsAutofilled(const WebInputElement& element) { |
| 886 WebFormElement form_element = element.form(); | 920 WebFormElement form_element = element.form(); |
| 887 if (form_element.isNull()) | 921 if (form_element.isNull()) |
| 888 return false; | 922 return false; |
| 889 | 923 |
| 890 std::vector<WebFormControlElement> control_elements; | 924 std::vector<WebFormControlElement> control_elements; |
| 891 ExtractAutofillableElements(form_element, REQUIRE_AUTOCOMPLETE, | 925 ExtractAutofillableElements(form_element, REQUIRE_AUTOCOMPLETE, |
| 892 &control_elements); | 926 &control_elements); |
| 893 for (size_t i = 0; i < control_elements.size(); ++i) { | 927 for (size_t i = 0; i < control_elements.size(); ++i) { |
| 894 WebInputElement* input_element = toWebInputElement(&control_elements[i]); | 928 WebInputElement* input_element = toWebInputElement(&control_elements[i]); |
| 895 if (!IsTextInput(input_element)) | 929 if (!IsAutofillableInputElement(input_element)) |
| 896 continue; | 930 continue; |
| 897 | 931 |
| 898 if (input_element->isAutofilled()) | 932 if (input_element->isAutofilled()) |
| 899 return true; | 933 return true; |
| 900 } | 934 } |
| 901 | 935 |
| 902 return false; | 936 return false; |
| 903 } | 937 } |
| 904 | 938 |
| 905 } // namespace autofill | 939 } // namespace autofill |
| OLD | NEW |