summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorziran.sun@samsung.com <ziran.sun@samsung.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-25 01:15:15 +0000
committerziran.sun@samsung.com <ziran.sun@samsung.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-25 01:15:15 +0000
commite9d29d39eed9ca4d46850436927e5d5e3bc39488 (patch)
treef93649569b303ca4d3beacb1f9feb0117cb34040
parent315df95ab4d89a80b798791b7198a54af5e5c437 (diff)
downloadchromium_src-e9d29d39eed9ca4d46850436927e5d5e3bc39488.zip
chromium_src-e9d29d39eed9ca4d46850436927e5d5e3bc39488.tar.gz
chromium_src-e9d29d39eed9ca4d46850436927e5d5e3bc39488.tar.bz2
Add supports that allow Autofill to be initiated from textarea field
Handling both keyboard and mouse events in textarea that initiate autofill preview and fill form actions. Add test cases from browser tests aspect to cover page click and findformfieldfortextarea cases. BUG=332557 Review URL: https://codereview.chromium.org/204343004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@259076 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/renderer/autofill/autofill_renderer_browsertest.cc4
-rw-r--r--chrome/renderer/autofill/form_autofill_browsertest.cc202
-rw-r--r--chrome/renderer/autofill/page_click_tracker_browsertest.cc130
-rw-r--r--components/autofill/content/renderer/autofill_agent.cc129
-rw-r--r--components/autofill/content/renderer/autofill_agent.h23
-rw-r--r--components/autofill/content/renderer/form_autofill_util.cc137
-rw-r--r--components/autofill/content/renderer/form_autofill_util.h18
-rw-r--r--components/autofill/content/renderer/form_cache.cc2
-rw-r--r--components/autofill/content/renderer/form_cache.h3
-rw-r--r--components/autofill/content/renderer/page_click_listener.h14
-rw-r--r--components/autofill/content/renderer/page_click_tracker.cc34
-rw-r--r--components/autofill/content/renderer/password_autofill_agent.cc4
-rw-r--r--components/autofill/core/browser/autocomplete_history_manager.cc4
-rw-r--r--components/autofill/core/browser/autocomplete_history_manager.h1
-rw-r--r--components/autofill/core/browser/autocomplete_history_manager_unittest.cc42
-rw-r--r--components/autofill/core/browser/autofill_manager.cc3
16 files changed, 523 insertions, 227 deletions
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index ba2d19b..85c2c66 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -148,7 +148,7 @@ TEST_F(AutofillRendererTest, ShowAutofillWarning) {
// Simulate attempting to Autofill the form from the first element, which
// specifies autocomplete="off". This should still trigger an IPC which
// shouldn't display warnings.
- autofill_agent_->InputElementClicked(firstname, true, true);
+ autofill_agent_->FormControlElementClicked(firstname, true);
const IPC::Message* message1 = render_thread_->sink().GetFirstMessageMatching(
AutofillHostMsg_QueryFormFieldAutofill::ID);
EXPECT_NE(static_cast<IPC::Message*>(NULL), message1);
@@ -162,7 +162,7 @@ TEST_F(AutofillRendererTest, ShowAutofillWarning) {
// does not specify autocomplete="off". This should trigger an IPC that will
// show warnings, as we *do* show warnings for elements that don't themselves
// set autocomplete="off", but for which the form does.
- autofill_agent_->InputElementClicked(middlename, true, true);
+ autofill_agent_->FormControlElementClicked(middlename, true);
const IPC::Message* message2 = render_thread_->sink().GetFirstMessageMatching(
AutofillHostMsg_QueryFormFieldAutofill::ID);
ASSERT_NE(static_cast<IPC::Message*>(NULL), message2);
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index 419545d..4fa945fe 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -159,7 +159,7 @@ class FormAutofillTest : public ChromeRenderViewTest {
}
typedef void (*FillFormFunction)(const FormData& form,
- const WebInputElement& element);
+ const WebFormControlElement& element);
typedef WebString (*GetValueFunction)(WebFormControlElement element);
@@ -187,10 +187,10 @@ class FormAutofillTest : public ChromeRenderViewTest {
FormData form_data;
FormFieldData field;
EXPECT_TRUE(
- FindFormAndFieldForInputElement(input_element,
- &form_data,
- &field,
- autofill::REQUIRE_AUTOCOMPLETE));
+ FindFormAndFieldForFormControlElement(input_element,
+ &form_data,
+ &field,
+ autofill::REQUIRE_AUTOCOMPLETE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form_data.name);
EXPECT_EQ(GURL(web_frame->document().url()), form_data.origin);
EXPECT_EQ(GURL("http://buh.com"), form_data.action);
@@ -258,7 +258,7 @@ class FormAutofillTest : public ChromeRenderViewTest {
static void FillFormIncludingNonFocusableElementsWrapper(
const FormData& form,
- const WebInputElement& element) {
+ const WebFormControlElement& element) {
FillFormIncludingNonFocusableElements(form, element.form());
}
@@ -1002,7 +1002,7 @@ TEST_F(FormAutofillTest, WebFormElementToFormDataAutocomplete) {
}
}
-TEST_F(FormAutofillTest, FindForm) {
+TEST_F(FormAutofillTest, FindFormForInputElement) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
" <INPUT type=\"text\" id=\"firstname\" value=\"John\"/>"
" <INPUT type=\"text\" id=\"lastname\" value=\"Smith\"/>"
@@ -1027,8 +1027,10 @@ TEST_F(FormAutofillTest, FindForm) {
// Find the form and verify it's the correct form.
FormData form;
FormFieldData field;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form, &field,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -1062,8 +1064,11 @@ TEST_F(FormAutofillTest, FindForm) {
// Try again, but require autocomplete.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form2, &field2,
- autofill::REQUIRE_AUTOCOMPLETE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+ input_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_AUTOCOMPLETE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -1088,6 +1093,109 @@ TEST_F(FormAutofillTest, FindForm) {
EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[2]);
}
+TEST_F(FormAutofillTest, FindFormForTextAreaElement) {
+ LoadHTML("<FORM name=\"TestForm\" action=\"http://buh.com\" method=\"post\">"
+ " <INPUT type=\"text\" id=\"firstname\" value=\"John\"/>"
+ " <INPUT type=\"text\" id=\"lastname\" value=\"Smith\"/>"
+ " <INPUT type=\"text\" id=\"email\" value=\"john@example.com\""
+ "autocomplete=\"off\" />"
+ " <TEXTAREA id=\"street-address\">"
+ "123 Fantasy Ln.&#10;"
+ "Apt. 42"
+ "</TEXTAREA>"
+ " <INPUT type=\"submit\" name=\"reply-send\" value=\"Send\"/>"
+ "</FORM>");
+
+ WebFrame* web_frame = GetMainFrame();
+ ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame);
+
+ FormCache form_cache;
+ std::vector<FormData> forms;
+ form_cache.ExtractForms(*web_frame, &forms);
+ ASSERT_EQ(1U, forms.size());
+
+ // Get the textarea element we want to find.
+ WebElement element = web_frame->document().getElementById("street-address");
+ WebTextAreaElement textarea_element = element.to<WebTextAreaElement>();
+
+ // Find the form and verify it's the correct form.
+ FormData form;
+ FormFieldData field;
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(textarea_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
+ EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
+ EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
+ EXPECT_EQ(GURL("http://buh.com"), form.action);
+
+ const std::vector<FormFieldData>& fields = form.fields;
+ ASSERT_EQ(4U, fields.size());
+
+ FormFieldData expected;
+
+ expected.name = ASCIIToUTF16("firstname");
+ expected.value = ASCIIToUTF16("John");
+ expected.form_control_type = "text";
+ expected.max_length = WebInputElement::defaultMaxLength();
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]);
+
+ expected.name = ASCIIToUTF16("lastname");
+ expected.value = ASCIIToUTF16("Smith");
+ expected.form_control_type = "text";
+ expected.max_length = WebInputElement::defaultMaxLength();
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]);
+
+ expected.name = ASCIIToUTF16("email");
+ expected.value = ASCIIToUTF16("john@example.com");
+ expected.autocomplete_attribute = "off";
+ expected.form_control_type = "text";
+ expected.max_length = WebInputElement::defaultMaxLength();
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]);
+ expected.autocomplete_attribute = std::string(); // reset
+
+ expected.name = ASCIIToUTF16("street-address");
+ expected.value = ASCIIToUTF16("123 Fantasy Ln.\nApt. 42");
+ expected.form_control_type = "textarea";
+ expected.max_length = 0;
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[3]);
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, field);
+
+ // Try again, but require autocomplete.
+ FormData form2;
+ FormFieldData field2;
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+ textarea_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_AUTOCOMPLETE));
+ EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
+ EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
+ EXPECT_EQ(GURL("http://buh.com"), form2.action);
+
+ const std::vector<FormFieldData>& fields2 = form2.fields;
+ ASSERT_EQ(3U, fields2.size());
+
+ expected.name = ASCIIToUTF16("firstname");
+ expected.value = ASCIIToUTF16("John");
+ expected.form_control_type = "text";
+ expected.max_length = WebInputElement::defaultMaxLength();
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[0]);
+
+ expected.name = ASCIIToUTF16("lastname");
+ expected.value = ASCIIToUTF16("Smith");
+ expected.form_control_type = "text";
+ expected.max_length = WebInputElement::defaultMaxLength();
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[1]);
+
+ expected.name = ASCIIToUTF16("street-address");
+ expected.value = ASCIIToUTF16("123 Fantasy Ln.\nApt. 42");
+ expected.form_control_type = "textarea";
+ expected.max_length = 0;
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[2]);
+ EXPECT_FORM_FIELD_DATA_EQUALS(expected, field);
+}
+
// Test regular FillForm function.
TEST_F(FormAutofillTest, FillForm) {
static const AutofillFieldCase field_cases[] = {
@@ -2109,8 +2217,10 @@ TEST_F(FormAutofillTest, FillFormMaxLength) {
// Find the form that contains the input element.
FormData form;
FormFieldData field;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form, &field,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2145,8 +2255,10 @@ TEST_F(FormAutofillTest, FillFormMaxLength) {
// Find the newly-filled form that contains the input element.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
@@ -2202,8 +2314,10 @@ TEST_F(FormAutofillTest, FillFormNegativeMaxLength) {
// Find the form that contains the input element.
FormData form;
FormFieldData field;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form, &field,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2233,8 +2347,10 @@ TEST_F(FormAutofillTest, FillFormNegativeMaxLength) {
// Find the newly-filled form that contains the input element.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
@@ -2279,8 +2395,10 @@ TEST_F(FormAutofillTest, FillFormEmptyName) {
// Find the form that contains the input element.
FormData form;
FormFieldData field;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form, &field,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2310,8 +2428,10 @@ TEST_F(FormAutofillTest, FillFormEmptyName) {
// Find the newly-filled form that contains the input element.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
@@ -2365,8 +2485,10 @@ TEST_F(FormAutofillTest, FillFormEmptyFormNames) {
// Find the form that contains the input element.
FormData form;
FormFieldData field;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form, &field,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(base::string16(), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -2399,8 +2521,10 @@ TEST_F(FormAutofillTest, FillFormEmptyFormNames) {
// Find the newly-filled form that contains the input element.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(base::string16(), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
@@ -2584,8 +2708,10 @@ TEST_F(FormAutofillTest, FillFormNonEmptyField) {
// Find the form that contains the input element.
FormData form;
FormFieldData field;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form, &field,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form,
+ &field,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form.name);
EXPECT_EQ(GURL(web_frame->document().url()), form.origin);
EXPECT_EQ(GURL("http://buh.com"), form.action);
@@ -2626,8 +2752,10 @@ TEST_F(FormAutofillTest, FillFormNonEmptyField) {
// Find the newly-filled form that contains the input element.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(input_element, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
@@ -2701,8 +2829,10 @@ TEST_F(FormAutofillTest, ClearFormWithNode) {
// Verify the form is cleared.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(firstname, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(firstname,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
@@ -2803,8 +2933,10 @@ TEST_F(FormAutofillTest, ClearFormWithNodeContainingSelectOne) {
// Verify the form is cleared.
FormData form2;
FormFieldData field2;
- EXPECT_TRUE(FindFormAndFieldForInputElement(firstname, &form2, &field2,
- autofill::REQUIRE_NONE));
+ EXPECT_TRUE(FindFormAndFieldForFormControlElement(firstname,
+ &form2,
+ &field2,
+ autofill::REQUIRE_NONE));
EXPECT_EQ(ASCIIToUTF16("TestForm"), form2.name);
EXPECT_EQ(GURL(web_frame->document().url()), form2.origin);
EXPECT_EQ(GURL("http://buh.com"), form2.action);
diff --git a/chrome/renderer/autofill/page_click_tracker_browsertest.cc b/chrome/renderer/autofill/page_click_tracker_browsertest.cc
index b549615..4c5c818 100644
--- a/chrome/renderer/autofill/page_click_tracker_browsertest.cc
+++ b/chrome/renderer/autofill/page_click_tracker_browsertest.cc
@@ -10,6 +10,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
+#include "third_party/WebKit/public/web/WebTextAreaElement.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -19,38 +20,34 @@ namespace autofill {
class TestPageClickListener : public PageClickListener {
public:
TestPageClickListener()
- : input_element_clicked_called_(false),
- input_element_lost_focus_called_(false),
- was_focused_(false),
- is_focused_(false) {
+ : form_control_element_clicked_called_(false),
+ form_control_element_lost_focus_called_(false),
+ was_focused_(false) {
}
- virtual void InputElementClicked(const blink::WebInputElement& element,
- bool was_focused,
- bool is_focused) OVERRIDE {
- input_element_clicked_called_ = true;
- element_clicked_ = element;
+ virtual void FormControlElementClicked(
+ const blink::WebFormControlElement& element,
+ bool was_focused) OVERRIDE {
+ form_control_element_clicked_called_ = true;
+ form_control_element_clicked_ = element;
was_focused_ = was_focused;
- is_focused_ = is_focused;
}
- virtual void InputElementLostFocus() OVERRIDE {
- input_element_lost_focus_called_ = true;
+ virtual void FormControlElementLostFocus() OVERRIDE {
+ form_control_element_lost_focus_called_ = true;
}
void ClearResults() {
- input_element_clicked_called_ = false;
- input_element_lost_focus_called_ = false;
- element_clicked_.reset();
+ form_control_element_clicked_called_ = false;
+ form_control_element_lost_focus_called_ = false;
+ form_control_element_clicked_.reset();
was_focused_ = false;
- is_focused_ = false;
}
- bool input_element_clicked_called_;
- bool input_element_lost_focus_called_;
- blink::WebInputElement element_clicked_;
+ bool form_control_element_clicked_called_;
+ bool form_control_element_lost_focus_called_;
+ blink::WebFormControlElement form_control_element_clicked_;
bool was_focused_;
- bool is_focused_;
};
class PageClickTrackerTest : public content::RenderViewTest {
@@ -65,17 +62,22 @@ class PageClickTrackerTest : public content::RenderViewTest {
LoadHTML("<form>"
" <input type='text' id='text_1'></input><br>"
" <input type='text' id='text_2'></input><br>"
+ " <textarea id='textarea_1'></textarea><br>"
+ " <textarea id='textarea_2'></textarea><br>"
" <input type='button' id='button'></input><br>"
"</form>");
GetWebWidget()->resize(blink::WebSize(500, 500));
GetWebWidget()->setFocus(true);
blink::WebDocument document = view_->GetWebView()->mainFrame()->document();
text_ = document.getElementById("text_1");
+ textarea_ = document.getElementById("textarea_1");
ASSERT_FALSE(text_.isNull());
+ ASSERT_FALSE(textarea_.isNull());
}
virtual void TearDown() OVERRIDE {
text_.reset();
+ textarea_.reset();
test_listener_.ClearResults();
page_click_tracker_.reset();
content::RenderViewTest::TearDown();
@@ -100,29 +102,51 @@ class PageClickTrackerTest : public content::RenderViewTest {
scoped_ptr<PageClickTracker> page_click_tracker_;
TestPageClickListener test_listener_;
blink::WebElement text_;
+ blink::WebElement textarea_;
};
-// Tests that PageClickTracker does notify correctly when a node is clicked.
+// Tests that PageClickTracker does notify correctly when an input
+// node is clicked.
TEST_F(PageClickTrackerTest, PageClickTrackerInputClicked) {
// Click the text field once.
EXPECT_TRUE(SimulateElementClick("text_1"));
- EXPECT_TRUE(test_listener_.input_element_clicked_called_);
+ EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
EXPECT_FALSE(test_listener_.was_focused_);
- EXPECT_TRUE(test_listener_.is_focused_);
- EXPECT_TRUE(text_ == test_listener_.element_clicked_);
+ EXPECT_TRUE(text_ == test_listener_.form_control_element_clicked_);
test_listener_.ClearResults();
// Click the text field again to test that was_focused_ is set correctly.
EXPECT_TRUE(SimulateElementClick("text_1"));
- EXPECT_TRUE(test_listener_.input_element_clicked_called_);
+ EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
EXPECT_TRUE(test_listener_.was_focused_);
- EXPECT_TRUE(test_listener_.is_focused_);
- EXPECT_TRUE(text_ == test_listener_.element_clicked_);
+ EXPECT_TRUE(text_ == test_listener_.form_control_element_clicked_);
test_listener_.ClearResults();
// Click the button, no notification should happen (this is not a text-input).
EXPECT_TRUE(SimulateElementClick("button"));
- EXPECT_FALSE(test_listener_.input_element_clicked_called_);
+ EXPECT_FALSE(test_listener_.form_control_element_clicked_called_);
+}
+
+// Tests that PageClickTracker does notify correctly when a textarea
+// node is clicked.
+TEST_F(PageClickTrackerTest, PageClickTrackerTextAreaClicked) {
+ // Click the textarea field once.
+ EXPECT_TRUE(SimulateElementClick("textarea_1"));
+ EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
+ EXPECT_FALSE(test_listener_.was_focused_);
+ EXPECT_TRUE(textarea_ == test_listener_.form_control_element_clicked_);
+ test_listener_.ClearResults();
+
+ // Click the textarea field again to test that was_focused_ is set correctly.
+ EXPECT_TRUE(SimulateElementClick("textarea_1"));
+ EXPECT_TRUE(test_listener_.form_control_element_clicked_called_);
+ EXPECT_TRUE(test_listener_.was_focused_);
+ EXPECT_TRUE(textarea_ == test_listener_.form_control_element_clicked_);
+ test_listener_.ClearResults();
+
+ // Click the button, no notification should happen (this is not a text-input).
+ EXPECT_TRUE(SimulateElementClick("button"));
+ EXPECT_FALSE(test_listener_.form_control_element_clicked_called_);
}
TEST_F(PageClickTrackerTest, PageClickTrackerInputFocusLost) {
@@ -130,35 +154,73 @@ TEST_F(PageClickTrackerTest, PageClickTrackerInputFocusLost) {
EXPECT_NE(text_, text_.document().focusedElement());
SendKeyPress(ui::VKEY_TAB);
EXPECT_EQ(text_, text_.document().focusedElement());
- EXPECT_FALSE(test_listener_.input_element_lost_focus_called_);
+ EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
// Click a button and ensure that the lost focus notification was sent,
// even though focus was gained without the mouse.
EXPECT_TRUE(SimulateElementClick("button"));
- EXPECT_TRUE(test_listener_.input_element_lost_focus_called_);
+ EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
test_listener_.ClearResults();
// Click a text field and test that no lost focus notifications are sent.
EXPECT_TRUE(SimulateElementClick("text_1"));
- EXPECT_FALSE(test_listener_.input_element_lost_focus_called_);
+ EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
test_listener_.ClearResults();
// Select another text field to test that the notifcation for the
// first text field losing focus is sent.
EXPECT_TRUE(SimulateElementClick("text_2"));
- EXPECT_TRUE(test_listener_.input_element_lost_focus_called_);
+ EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
test_listener_.ClearResults();
// Click the button, a notification should happen since a text field has
// lost focus.
EXPECT_TRUE(SimulateElementClick("button"));
- EXPECT_TRUE(test_listener_.input_element_lost_focus_called_);
+ EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
test_listener_.ClearResults();
// Click on a text field while the button has focus and ensure no lost focus
// notification is sent.
EXPECT_TRUE(SimulateElementClick("text_1"));
- EXPECT_FALSE(test_listener_.input_element_lost_focus_called_);
+ EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
+}
+
+TEST_F(PageClickTrackerTest, PageClickTrackerTextAreaFocusLost) {
+ // Gain focus on the textare field by using tab.
+ EXPECT_NE(textarea_, textarea_.document().focusedElement());
+ SendKeyPress(ui::VKEY_TAB);
+ SendKeyPress(ui::VKEY_TAB);
+ SendKeyPress(ui::VKEY_TAB);
+ EXPECT_EQ(textarea_, textarea_.document().focusedElement());
+ EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
+
+ // Click a button and ensure that the lost focus notification was sent,
+ // even though focus was gained without the mouse.
+ EXPECT_TRUE(SimulateElementClick("button"));
+ EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
+ test_listener_.ClearResults();
+
+ // Click a textarea field and test that no lost focus notifications are sent.
+ EXPECT_TRUE(SimulateElementClick("textarea_1"));
+ EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
+ test_listener_.ClearResults();
+
+ // Select another textarea field to test that the notifcation for the
+ // first textarea field losing focus is sent.
+ EXPECT_TRUE(SimulateElementClick("textarea_2"));
+ EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
+ test_listener_.ClearResults();
+
+ // Click the button, a notification should happen since a textarea field has
+ // lost focus.
+ EXPECT_TRUE(SimulateElementClick("button"));
+ EXPECT_TRUE(test_listener_.form_control_element_lost_focus_called_);
+ test_listener_.ClearResults();
+
+ // Click on a textarea field while the button has focus and ensure no lost
+ // focus notification is sent.
+ EXPECT_TRUE(SimulateElementClick("textarea_1"));
+ EXPECT_FALSE(test_listener_.form_control_element_lost_focus_called_);
}
} // namespace autofill
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index c3c9239..8fab856 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -41,6 +41,7 @@
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebOptionElement.h"
+#include "third_party/WebKit/public/web/WebTextAreaElement.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/keycodes/keyboard_codes.h"
@@ -56,6 +57,7 @@ using blink::WebKeyboardEvent;
using blink::WebNode;
using blink::WebOptionElement;
using blink::WebString;
+using blink::WebTextAreaElement;
using blink::WebVector;
namespace autofill {
@@ -296,14 +298,18 @@ void AutofillAgent::setIgnoreTextChanges(bool ignore) {
ignore_text_changes_ = ignore;
}
-void AutofillAgent::InputElementClicked(const WebInputElement& element,
- bool was_focused,
- bool is_focused) {
+void AutofillAgent::FormControlElementClicked(
+ const WebFormControlElement& element,
+ bool was_focused) {
+ const WebInputElement* input_element = toWebInputElement(&element);
+ if (!input_element && !IsTextAreaElement(element))
+ return;
+
if (was_focused)
ShowSuggestions(element, true, false, true, false);
}
-void AutofillAgent::InputElementLostFocus() {
+void AutofillAgent::FormControlElementLostFocus() {
HidePopup();
}
@@ -313,10 +319,19 @@ void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
Send(new AutofillHostMsg_DidEndTextFieldEditing(routing_id()));
}
+// TODO(ziran.sun): This function is to be removed once next Blink roll is done
void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
+ const WebFormControlElement control_element =
+ element.toConst<WebFormControlElement>();
+ textFieldDidChange(control_element);
+}
+
+void AutofillAgent::textFieldDidChange(const WebFormControlElement& element) {
if (ignore_text_changes_)
return;
+ DCHECK(toWebInputElement(&element) || IsTextAreaElement(element));
+
if (did_set_node_text_) {
did_set_node_text_ = false;
return;
@@ -333,27 +348,34 @@ void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
element));
}
-void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
+void AutofillAgent::TextFieldDidChangeImpl(
+ const WebFormControlElement& element) {
// If the element isn't focused then the changes don't matter. This check is
// required to properly handle IME interactions.
if (!element.focused())
return;
- if (password_generation_agent_ &&
- password_generation_agent_->TextDidChangeInTextField(element)) {
- return;
- }
+ const WebInputElement* input_element = toWebInputElement(&element);
+ if (input_element) {
+ if (password_generation_agent_ &&
+ password_generation_agent_->TextDidChangeInTextField(*input_element)) {
+ return;
+ }
- if (password_autofill_agent_->TextDidChangeInTextField(element)) {
- element_ = element;
- return;
+ if (password_autofill_agent_->TextDidChangeInTextField(*input_element)) {
+ element_ = element;
+ return;
+ }
}
ShowSuggestions(element, false, true, false, false);
FormData form;
FormFieldData field;
- if (FindFormAndFieldForInputElement(element, &form, &field, REQUIRE_NONE)) {
+ if (FindFormAndFieldForFormControlElement(element,
+ &form,
+ &field,
+ REQUIRE_NONE)) {
Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field,
base::TimeTicks::Now()));
}
@@ -377,14 +399,16 @@ void AutofillAgent::openTextDataListChooser(const WebInputElement& element) {
void AutofillAgent::AcceptDataListSuggestion(
const base::string16& suggested_value) {
+ WebInputElement* input_element = toWebInputElement(&element_);
+ DCHECK(input_element);
base::string16 new_value = suggested_value;
// If this element takes multiple values then replace the last part with
// the suggestion.
- if (element_.isMultiple() &&
- element_.formControlType() == WebString::fromUTF8("email")) {
+ if (input_element->isMultiple() &&
+ input_element->formControlType() == WebString::fromUTF8("email")) {
std::vector<base::string16> parts;
- base::SplitStringDontTrim(element_.editingValue(), ',', &parts);
+ base::SplitStringDontTrim(input_element->editingValue(), ',', &parts);
if (parts.size() == 0)
parts.push_back(base::string16());
@@ -401,7 +425,7 @@ void AutofillAgent::AcceptDataListSuggestion(
new_value = JoinString(parts, ',');
}
- FillFieldWithValue(new_value, &element_);
+ FillFieldWithValue(new_value, input_element);
}
void AutofillAgent::OnFieldTypePredictionsAvailable(
@@ -451,11 +475,15 @@ void AutofillAgent::OnClearPreviewedForm() {
}
void AutofillAgent::OnFillFieldWithValue(const base::string16& value) {
- FillFieldWithValue(value, &element_);
+ WebInputElement* input_element = toWebInputElement(&element_);
+ if (input_element)
+ FillFieldWithValue(value, input_element);
}
void AutofillAgent::OnPreviewFieldWithValue(const base::string16& value) {
- PreviewFieldWithValue(value, &element_);
+ WebInputElement* input_element = toWebInputElement(&element_);
+ if (input_element)
+ PreviewFieldWithValue(value, input_element);
}
void AutofillAgent::OnAcceptDataListSuggestion(const base::string16& value) {
@@ -489,17 +517,26 @@ void AutofillAgent::OnRequestAutocompleteResult(
in_flight_request_form_.reset();
}
-void AutofillAgent::ShowSuggestions(const WebInputElement& element,
+void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
bool autofill_on_empty_values,
bool requires_caret_at_end,
bool display_warning_if_disabled,
bool datalist_only) {
- if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() ||
- element.isPasswordField())
- return;
- if (!datalist_only && !element.suggestedValue().isEmpty())
+ if (!element.isEnabled() || element.isReadOnly())
return;
+ const WebInputElement* input_element = toWebInputElement(&element);
+ if (input_element) {
+ if (!input_element->isTextField() || input_element->isPasswordField())
+ return;
+ if (!datalist_only && !input_element->suggestedValue().isEmpty())
+ return;
+ } else {
+ DCHECK(IsTextAreaElement(element));
+ if (!element.toConst<WebTextAreaElement>().suggestedValue().isEmpty())
+ return;
+ }
+
// Don't attempt to autofill with values that are too large or if filling
// criteria are not met.
WebString value = element.editingValue();
@@ -515,7 +552,8 @@ void AutofillAgent::ShowSuggestions(const WebInputElement& element,
}
element_ = element;
- if (password_autofill_agent_->ShowSuggestions(element)) {
+ if (input_element &&
+ password_autofill_agent_->ShowSuggestions(*input_element)) {
is_popup_possibly_visible_ = true;
return;
}
@@ -535,12 +573,15 @@ void AutofillAgent::ShowSuggestions(const WebInputElement& element,
datalist_only);
}
-void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
- bool display_warning_if_disabled,
- bool datalist_only) {
+void AutofillAgent::QueryAutofillSuggestions(
+ const WebFormControlElement& element,
+ bool display_warning_if_disabled,
+ bool datalist_only) {
if (!element.document().frame())
return;
+ DCHECK(toWebInputElement(&element) || IsTextAreaElement(element));
+
static int query_counter = 0;
autofill_query_id_ = query_counter++;
display_warning_if_disabled_ = display_warning_if_disabled;
@@ -555,7 +596,8 @@ void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
FormData form;
FormFieldData field;
- if (!FindFormAndFieldForInputElement(element, &form, &field, requirements)) {
+ if (!FindFormAndFieldForFormControlElement(element, &form, &field,
+ requirements)) {
// If we didn't find the cached form, at least let autocomplete have a shot
// at providing suggestions.
WebFormControlElementToFormField(element, EXTRACT_VALUE, &field);
@@ -566,21 +608,24 @@ void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
gfx::RectF bounding_box_scaled =
GetScaledBoundingBox(web_view_->pageScaleFactor(), &element_);
- // Find the datalist values and send them to the browser process.
- std::vector<base::string16> data_list_values;
- std::vector<base::string16> data_list_labels;
- GetDataListSuggestions(element_,
- datalist_only,
- &data_list_values,
- &data_list_labels);
- TrimStringVectorForIPC(&data_list_values);
- TrimStringVectorForIPC(&data_list_labels);
+ const WebInputElement* input_element = toWebInputElement(&element);
+ if (input_element) {
+ // Find the datalist values and send them to the browser process.
+ std::vector<base::string16> data_list_values;
+ std::vector<base::string16> data_list_labels;
+ GetDataListSuggestions(*input_element,
+ datalist_only,
+ &data_list_values,
+ &data_list_labels);
+ TrimStringVectorForIPC(&data_list_values);
+ TrimStringVectorForIPC(&data_list_labels);
+
+ Send(new AutofillHostMsg_SetDataList(routing_id(),
+ data_list_values,
+ data_list_labels));
+ }
is_popup_possibly_visible_ = true;
- Send(new AutofillHostMsg_SetDataList(routing_id(),
- data_list_values,
- data_list_labels));
-
Send(new AutofillHostMsg_QueryFormFieldAutofill(routing_id(),
autofill_query_id_,
form,
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 5c327db4..6ecd273 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -18,6 +18,7 @@
#include "components/autofill/core/common/forms_seen_state.h"
#include "content/public/renderer/render_view_observer.h"
#include "third_party/WebKit/public/web/WebAutofillClient.h"
+#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
@@ -68,16 +69,20 @@ class AutofillAgent : public content::RenderViewObserver,
virtual void OrientationChangeEvent(int orientation) OVERRIDE;
// PageClickListener:
- virtual void InputElementClicked(const blink::WebInputElement& element,
- bool was_focused,
- bool is_focused) OVERRIDE;
- virtual void InputElementLostFocus() OVERRIDE;
+ virtual void FormControlElementClicked(
+ const blink::WebFormControlElement& element,
+ bool was_focused) OVERRIDE;
+ virtual void FormControlElementLostFocus() OVERRIDE;
// blink::WebAutofillClient:
virtual void textFieldDidEndEditing(
const blink::WebInputElement& element) OVERRIDE;
+ // TODO(ziran.sun): To be removed once next Blink roll is done
virtual void textFieldDidChange(
- const blink::WebInputElement& element) OVERRIDE;
+ const blink::WebInputElement& element);
+ // TODO(ziran.sun): OVERRIDE this function once next Blink roll is done
+ virtual void textFieldDidChange(
+ const blink::WebFormControlElement& element);
virtual void textFieldDidReceiveKeyDown(
const blink::WebInputElement& element,
const blink::WebKeyboardEvent& event) OVERRIDE;
@@ -113,7 +118,7 @@ class AutofillAgent : public content::RenderViewObserver,
// Called in a posted task by textFieldDidChange() to work-around a WebKit bug
// http://bugs.webkit.org/show_bug.cgi?id=16976
- void TextFieldDidChangeImpl(const blink::WebInputElement& element);
+ void TextFieldDidChangeImpl(const blink::WebFormControlElement& element);
// Shows the autofill suggestions for |element|.
// This call is asynchronous and may or may not lead to the showing of a
@@ -129,7 +134,7 @@ class AutofillAgent : public content::RenderViewObserver,
// |datalist_only| specifies whether all of <datalist> suggestions and no
// autofill suggestions are shown. |autofill_on_empty_values| and
// |requires_caret_at_end| are ignored if |datalist_only| is true.
- void ShowSuggestions(const blink::WebInputElement& element,
+ void ShowSuggestions(const blink::WebFormControlElement& element,
bool autofill_on_empty_values,
bool requires_caret_at_end,
bool display_warning_if_disabled,
@@ -137,7 +142,7 @@ class AutofillAgent : public content::RenderViewObserver,
// Queries the browser for Autocomplete and Autofill suggestions for the given
// |element|.
- void QueryAutofillSuggestions(const blink::WebInputElement& element,
+ void QueryAutofillSuggestions(const blink::WebFormControlElement& element,
bool display_warning_if_disabled,
bool datalist_only);
@@ -174,7 +179,7 @@ class AutofillAgent : public content::RenderViewObserver,
int autofill_query_id_;
// The element corresponding to the last request sent for form field Autofill.
- blink::WebInputElement element_;
+ blink::WebFormControlElement element_;
// The form element currently requesting an interactive autocomplete.
blink::WebFormElement in_flight_request_form_;
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index c9c6f87..7054a90b 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -507,10 +507,9 @@ void ForEachMatchingFormField(const WebFormElement& form_element,
// i.e. the field the user is currently editing and interacting with.
const WebInputElement* input_element = toWebInputElement(element);
if (!force_override && !is_initiating_element &&
- ((IsAutofillableInputElement(input_element) &&
- !input_element->value().isEmpty()) ||
- (IsTextAreaElement(*element) &&
- !element->toConst<WebTextAreaElement>().value().isEmpty())))
+ ((IsAutofillableInputElement(input_element) ||
+ IsTextAreaElement(*element)) &&
+ !element->value().isEmpty()))
continue;
if (((filters & FILTER_DISABLED_ELEMENTS) && !element->isEnabled()) ||
@@ -539,28 +538,24 @@ void FillFormField(const FormFieldData& data,
// returns the default maxlength value.
input_element->setValue(
data.value.substr(0, input_element->maxLength()), true);
- if (is_initiating_node) {
- int length = input_element->value().length();
- input_element->setSelectionRange(length, length);
- // Clear the current IME composition (the underline), if there is one.
- input_element->document().frame()->unmarkText();
- }
- } else if (IsTextAreaElement(*field)) {
- WebTextAreaElement text_area = field->to<WebTextAreaElement>();
- if (text_area.value() != data.value) {
- text_area.setValue(data.value);
- text_area.dispatchFormControlChangeEvent();
- }
- } else if (IsSelectElement(*field)) {
- WebSelectElement select_element = field->to<WebSelectElement>();
- if (select_element.value() != data.value) {
- select_element.setValue(data.value);
- select_element.dispatchFormControlChangeEvent();
+ } else if (IsTextAreaElement(*field) || IsSelectElement(*field)) {
+ if (field->value() != data.value) {
+ field->setValue(data.value);
+ field->dispatchFormControlChangeEvent();
}
} else {
DCHECK(IsCheckableElement(input_element));
input_element->setChecked(data.is_checked, true);
}
+
+ if (is_initiating_node &&
+ ((IsTextInput(input_element) || IsMonthInput(input_element)) ||
+ IsTextAreaElement(*field))) {
+ int length = field->value().length();
+ field->setSelectionRange(length, length);
+ // Clear the current IME composition (the underline), if there is one.
+ field->document().frame()->unmarkText();
+ }
}
// Sets the |field|'s "suggested" (non JS visible) value to the value in |data|.
@@ -582,17 +577,18 @@ void PreviewFormField(const FormFieldData& data,
input_element->setSuggestedValue(
data.value.substr(0, input_element->maxLength()));
input_element->setAutofilled(true);
- if (is_initiating_node) {
- // Select the part of the text that the user didn't type.
- input_element->setSelectionRange(
- input_element->value().length(),
- input_element->suggestedValue().length());
- }
} else if (IsTextAreaElement(*field)) {
- WebTextAreaElement textarea = field->to<WebTextAreaElement>();
- textarea.setSuggestedValue(data.value);
+ field->setSuggestedValue(data.value);
field->setAutofilled(true);
}
+
+ if (is_initiating_node &&
+ (IsTextInput(input_element) || IsTextAreaElement(*field))) {
+ // Select the part of the text that the user didn't type.
+ int start = field->value().length();
+ int end = field->suggestedValue().length();
+ field->setSelectionRange(start, end);
+ }
}
std::string RetrievalMethodToString(
@@ -772,17 +768,21 @@ void WebFormControlElementToFormField(const WebFormControlElement& element,
return;
const WebInputElement* input_element = toWebInputElement(&element);
+ if (IsAutofillableInputElement(input_element) ||
+ IsTextAreaElement(element)) {
+ field->is_autofilled = element.isAutofilled();
+ field->is_focusable = element.isFocusable();
+ field->should_autocomplete = element.autoComplete();
+ field->text_direction = element.directionForFormData() ==
+ "rtl" ? base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
+ }
+
if (IsAutofillableInputElement(input_element)) {
if (IsTextInput(input_element))
field->max_length = input_element->maxLength();
- field->is_autofilled = input_element->isAutofilled();
- field->is_focusable = input_element->isFocusable();
field->is_checkable = IsCheckableElement(input_element);
field->is_checked = input_element->isChecked();
- field->should_autocomplete = input_element->autoComplete();
- field->text_direction = input_element->directionForFormData() == "rtl" ?
- base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
} else if (IsTextAreaElement(element)) {
// Nothing more to do in this case.
} else if (extract_mask & EXTRACT_OPTIONS) {
@@ -797,16 +797,10 @@ void WebFormControlElementToFormField(const WebFormControlElement& element,
if (!(extract_mask & EXTRACT_VALUE))
return;
- base::string16 value;
- if (IsAutofillableInputElement(input_element)) {
- value = input_element->value();
- } else if (IsTextAreaElement(element)) {
- value = element.toConst<WebTextAreaElement>().value();
- } else {
- DCHECK(IsSelectElement(element));
- const WebSelectElement select_element = element.toConst<WebSelectElement>();
- value = select_element.value();
+ base::string16 value = element.value();
+ if (IsSelectElement(element)) {
+ const WebSelectElement select_element = element.toConst<WebSelectElement>();
// Convert the |select_element| value to text if requested.
if (extract_mask & EXTRACT_OPTION_TEXT) {
WebVector<WebElement> list_items = select_element.listItems();
@@ -971,10 +965,10 @@ bool WebFormElementToFormData(
return true;
}
-bool FindFormAndFieldForInputElement(const WebInputElement& element,
- FormData* form,
- FormFieldData* field,
- RequirementsMask requirements) {
+bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element,
+ FormData* form,
+ FormFieldData* field,
+ RequirementsMask requirements) {
if (!IsAutofillableElement(element))
return false;
@@ -992,7 +986,7 @@ bool FindFormAndFieldForInputElement(const WebInputElement& element,
field);
}
-void FillForm(const FormData& form, const WebInputElement& element) {
+void FillForm(const FormData& form, const WebFormControlElement& element) {
WebFormElement form_element = element.form();
if (form_element.isNull())
return;
@@ -1033,7 +1027,7 @@ void FillFormForAllElements(const FormData& form_data,
&FillFormField);
}
-void PreviewForm(const FormData& form, const WebInputElement& element) {
+void PreviewForm(const FormData& form, const WebFormControlElement& element) {
WebFormElement form_element = element.form();
if (form_element.isNull())
return;
@@ -1046,7 +1040,7 @@ void PreviewForm(const FormData& form, const WebInputElement& element) {
&PreviewFormField);
}
-bool ClearPreviewedFormWithElement(const WebInputElement& element,
+bool ClearPreviewedFormWithElement(const WebFormControlElement& element,
bool was_autofilled) {
WebFormElement form_element = element.form();
if (form_element.isNull())
@@ -1074,39 +1068,28 @@ bool ClearPreviewedFormWithElement(const WebInputElement& element,
if(!control_element.isAutofilled())
continue;
- if ((IsTextInput(input_element) &&
- input_element->suggestedValue().isEmpty()) ||
- (IsMonthInput(input_element) &&
- input_element->suggestedValue().isEmpty()) ||
- (IsTextAreaElement(control_element) &&
- control_element.to<WebTextAreaElement>().suggestedValue().isEmpty()))
+ if ((IsTextInput(input_element) ||
+ IsMonthInput(input_element) ||
+ IsTextAreaElement(control_element)) &&
+ control_element.suggestedValue().isEmpty())
continue;
// Clear the suggested value. For the initiating node, also restore the
// original value.
- if (IsTextInput(input_element) || IsMonthInput(input_element)) {
- input_element->setSuggestedValue(WebString());
- bool is_initiating_node = (element == *input_element);
- if (is_initiating_node)
- input_element->setAutofilled(was_autofilled);
- else
- input_element->setAutofilled(false);
-
- // Clearing the suggested value in the focused node (above) can cause
- // selection to be lost. We force selection range to restore the text
- // cursor.
+ if (IsTextInput(input_element) || IsMonthInput(input_element) ||
+ IsTextAreaElement(control_element)) {
+ control_element.setSuggestedValue(WebString());
+ bool is_initiating_node = (element == control_element);
if (is_initiating_node) {
- int length = input_element->value().length();
- input_element->setSelectionRange(length, length);
- }
- } else if (IsTextAreaElement(control_element)) {
- WebTextAreaElement text_area = control_element.to<WebTextAreaElement>();
- text_area.setSuggestedValue(WebString());
- bool is_initiating_node = (element == text_area);
- if (is_initiating_node)
control_element.setAutofilled(was_autofilled);
- else
+ // Clearing the suggested value in the focused node (above) can cause
+ // selection to be lost. We force selection range to restore the text
+ // cursor.
+ int length = control_element.value().length();
+ control_element.setSelectionRange(length, length);
+ } else {
control_element.setAutofilled(false);
+ }
}
}
@@ -1184,7 +1167,7 @@ bool IsWebElementEmpty(const blink::WebElement& element) {
return true;
}
-gfx::RectF GetScaledBoundingBox(float scale, WebInputElement* element) {
+gfx::RectF GetScaledBoundingBox(float scale, WebFormControlElement* element) {
gfx::Rect bounding_box(element->boundsInViewportSpace());
return gfx::RectF(bounding_box.x() * scale,
bounding_box.y() * scale,
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index f3384f1..0f0f6c2 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -116,15 +116,16 @@ bool WebFormElementToFormData(
// Finds the form that contains |element| and returns it in |form|. Fills
// |field| with the |FormField| representation for element.
// Returns false if the form is not found or cannot be serialized.
-bool FindFormAndFieldForInputElement(const blink::WebInputElement& element,
- FormData* form,
- FormFieldData* field,
- RequirementsMask requirements);
+bool FindFormAndFieldForFormControlElement(
+ const blink::WebFormControlElement& element,
+ FormData* form,
+ FormFieldData* field,
+ RequirementsMask requirements);
// Fills the form represented by |form|. |element| is the input element that
// initiated the auto-fill process.
void FillForm(const FormData& form,
- const blink::WebInputElement& element);
+ const blink::WebFormControlElement& element);
// Fills focusable and non-focusable form control elements within |form_element|
// with field data from |form_data|.
@@ -141,13 +142,13 @@ void FillFormForAllElements(
// Previews the form represented by |form|. |element| is the input element that
// initiated the preview process.
void PreviewForm(const FormData& form,
- const blink::WebInputElement& element);
+ const blink::WebFormControlElement& element);
// Clears the placeholder values and the auto-filled background for any fields
// in the form containing |node| that have been previewed. Resets the
// autofilled state of |node| to |was_autofilled|. Returns false if the form is
// not found.
-bool ClearPreviewedFormWithElement(const blink::WebInputElement& element,
+bool ClearPreviewedFormWithElement(const blink::WebFormControlElement& element,
bool was_autofilled);
// Returns true if |form| has any auto-filled fields.
@@ -169,7 +170,8 @@ bool IsWebpageEmpty(const blink::WebFrame* frame);
bool IsWebElementEmpty(const blink::WebElement& element);
// Return a gfx::RectF that is the bounding box for |element| scaled by |scale|.
-gfx::RectF GetScaledBoundingBox(float scale, blink::WebInputElement* element);
+gfx::RectF GetScaledBoundingBox(float scale,
+ blink::WebFormControlElement* element);
} // namespace autofill
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc
index 431979e..d9acf37 100644
--- a/components/autofill/content/renderer/form_cache.cc
+++ b/components/autofill/content/renderer/form_cache.cc
@@ -179,7 +179,7 @@ void FormCache::ResetFrame(const WebFrame& frame) {
RemoveOldElements(frame, &initial_checked_state_);
}
-bool FormCache::ClearFormWithElement(const WebInputElement& element) {
+bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
WebFormElement form_element = element.form();
if (form_element.isNull())
return false;
diff --git a/components/autofill/content/renderer/form_cache.h b/components/autofill/content/renderer/form_cache.h
index 3cb2525..1f97d073 100644
--- a/components/autofill/content/renderer/form_cache.h
+++ b/components/autofill/content/renderer/form_cache.h
@@ -13,6 +13,7 @@
namespace blink {
class WebDocument;
+class WebFormControlElement;
class WebFormElement;
class WebFrame;
class WebInputElement;
@@ -50,7 +51,7 @@ class FormCache {
// Clears the values of all input elements in the form that contains
// |element|. Returns false if the form is not found.
- bool ClearFormWithElement(const blink::WebInputElement& element);
+ bool ClearFormWithElement(const blink::WebFormControlElement& element);
// For each field in the |form|, sets the field's placeholder text to the
// field's overall predicted type. Also sets the title to include the field's
diff --git a/components/autofill/content/renderer/page_click_listener.h b/components/autofill/content/renderer/page_click_listener.h
index 1fc7862..4582ea5 100644
--- a/components/autofill/content/renderer/page_click_listener.h
+++ b/components/autofill/content/renderer/page_click_listener.h
@@ -6,7 +6,7 @@
#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_PAGE_CLICK_LISTENER_H_
namespace blink {
-class WebInputElement;
+class WebFormControlElement;
}
namespace autofill {
@@ -19,13 +19,13 @@ class PageClickListener {
// Notification that |element| was clicked.
// |was_focused| is true if |element| had focus BEFORE the click.
// |is_focused| is true if |element| has focus AFTER the click was processed.
- virtual void InputElementClicked(const blink::WebInputElement& element,
- bool was_focused,
- bool is_focused) = 0;
+ virtual void FormControlElementClicked(
+ const blink::WebFormControlElement& element,
+ bool was_focused) = 0;
- // If the previously focused element was an input field, listeners are
- // informed that the text field has lost its focus.
- virtual void InputElementLostFocus() = 0;
+ // If the previously focused element was an input field or a textarea,
+ // listeners are informed that the text field has lost its focus.
+ virtual void FormControlElementLostFocus() = 0;
protected:
virtual ~PageClickListener() {}
diff --git a/components/autofill/content/renderer/page_click_tracker.cc b/components/autofill/content/renderer/page_click_tracker.cc
index 59adae1..8938826 100644
--- a/components/autofill/content/renderer/page_click_tracker.cc
+++ b/components/autofill/content/renderer/page_click_tracker.cc
@@ -13,6 +13,7 @@
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebTextAreaElement.h"
#include "third_party/WebKit/public/web/WebView.h"
using blink::WebDOMEvent;
@@ -25,6 +26,7 @@ using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebNode;
using blink::WebString;
+using blink::WebTextAreaElement;
using blink::WebView;
namespace {
@@ -43,6 +45,18 @@ const WebInputElement GetTextWebInputElement(const WebNode& node) {
return *input;
}
+// Casts |node| to a WebTextAreaElement.
+// Returns an empty (isNull()) WebTextAreaElement if |node| is not a
+// textarea field.
+const WebTextAreaElement GetTextWebTextAreaElement(const WebNode& node) {
+ if (!node.isElementNode())
+ return WebTextAreaElement();
+ const WebElement element = node.toConst<WebElement>();
+ if (!element.hasTagName("textarea"))
+ return WebTextAreaElement();
+ return element.toConst<WebTextAreaElement>();
+}
+
// Checks to see if a text field was the previously selected node and is now
// losing its focus.
bool DidSelectedTextFieldLoseFocus(const WebNode& newly_clicked_node) {
@@ -50,7 +64,8 @@ bool DidSelectedTextFieldLoseFocus(const WebNode& newly_clicked_node) {
newly_clicked_node.document().focusedElement();
if (focused_element.isNull() ||
- GetTextWebInputElement(focused_element).isNull())
+ (GetTextWebInputElement(focused_element).isNull() &&
+ GetTextWebTextAreaElement(focused_element).isNull()))
return false;
return focused_element != newly_clicked_node;
@@ -82,14 +97,18 @@ void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) {
return;
}
- // We are only interested in text field clicks.
+ // We are only interested in text field and textarea field clicks.
const WebInputElement input_element =
GetTextWebInputElement(last_node_clicked_);
- if (input_element.isNull())
+ const WebTextAreaElement textarea_element =
+ GetTextWebTextAreaElement(last_node_clicked_);
+ if (input_element.isNull() && textarea_element.isNull())
return;
- bool is_focused = (last_node_clicked_ == render_view()->GetFocusedElement());
- listener_->InputElementClicked(input_element, was_focused_, is_focused);
+ if (!input_element.isNull())
+ listener_->FormControlElementClicked(input_element, was_focused_);
+ else if (!textarea_element.isNull())
+ listener_->FormControlElementClicked(textarea_element, was_focused_);
}
void PageClickTracker::DidFinishDocumentLoad(blink::WebFrame* frame) {
@@ -132,7 +151,8 @@ void PageClickTracker::handleEvent(const WebDOMEvent& event) {
HandleTextFieldMaybeLosingFocus(node);
// We are only interested in text field clicks.
- if (GetTextWebInputElement(node).isNull())
+ if (GetTextWebInputElement(node).isNull() &&
+ GetTextWebTextAreaElement(node).isNull())
return;
last_node_clicked_ = node;
@@ -142,7 +162,7 @@ void PageClickTracker::handleEvent(const WebDOMEvent& event) {
void PageClickTracker::HandleTextFieldMaybeLosingFocus(
const WebNode& newly_clicked_node) {
if (DidSelectedTextFieldLoseFocus(newly_clicked_node))
- listener_->InputElementLostFocus();
+ listener_->FormControlElementLostFocus();
}
} // namespace autofill
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index df80562..cf74e81 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -637,7 +637,7 @@ void PasswordAutofillAgent::OnFillPasswordForm(
FormData form;
FormFieldData field;
- FindFormAndFieldForInputElement(
+ FindFormAndFieldForFormControlElement(
username_element, &form, &field, REQUIRE_NONE);
Send(new AutofillHostMsg_AddPasswordFormMapping(
routing_id(),
@@ -699,7 +699,7 @@ bool PasswordAutofillAgent::ShowSuggestionPopup(
FormData form;
FormFieldData field;
- FindFormAndFieldForInputElement(
+ FindFormAndFieldForFormControlElement(
user_input, &form, &field, REQUIRE_NONE);
blink::WebInputElement selected_element = user_input;
diff --git a/components/autofill/core/browser/autocomplete_history_manager.cc b/components/autofill/core/browser/autocomplete_history_manager.cc
index 6562157..d473763 100644
--- a/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -81,6 +81,7 @@ void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
int query_id,
const base::string16& name,
const base::string16& prefix,
+ const std::string form_control_type,
const std::vector<base::string16>& autofill_values,
const std::vector<base::string16>& autofill_labels,
const std::vector<base::string16>& autofill_icons,
@@ -92,7 +93,8 @@ void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
autofill_labels_ = autofill_labels;
autofill_icons_ = autofill_icons;
autofill_unique_ids_ = autofill_unique_ids;
- if (!manager_delegate_->IsAutocompleteEnabled()) {
+ if (!manager_delegate_->IsAutocompleteEnabled() ||
+ form_control_type == "textarea") {
SendSuggestions(NULL);
return;
}
diff --git a/components/autofill/core/browser/autocomplete_history_manager.h b/components/autofill/core/browser/autocomplete_history_manager.h
index cb234db..50ad599 100644
--- a/components/autofill/core/browser/autocomplete_history_manager.h
+++ b/components/autofill/core/browser/autocomplete_history_manager.h
@@ -39,6 +39,7 @@ class AutocompleteHistoryManager : public WebDataServiceConsumer {
int query_id,
const base::string16& name,
const base::string16& prefix,
+ const std::string form_control_type,
const std::vector<base::string16>& autofill_values,
const std::vector<base::string16>& autofill_labels,
const std::vector<base::string16>& autofill_icons,
diff --git a/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
index c26c5f5..6379f07 100644
--- a/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -225,4 +225,46 @@ TEST_F(AutocompleteHistoryManagerTest, ExternalDelegate) {
autocomplete_history_manager.SendSuggestions(NULL);
}
+// Verify that no autocomplete suggestion is returned for textarea.
+TEST_F(AutocompleteHistoryManagerTest, NoAutocompleteSuggestionsForTextarea) {
+ TestAutocompleteHistoryManager autocomplete_history_manager(
+ autofill_driver_.get(), manager_delegate_.get());
+
+ scoped_ptr<AutofillManager> autofill_manager(new AutofillManager(
+ autofill_driver_.get(),
+ manager_delegate_.get(),
+ "en-US",
+ AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER));
+
+ MockAutofillExternalDelegate external_delegate(autofill_manager.get(),
+ autofill_driver_.get());
+ autocomplete_history_manager.SetExternalDelegate(&external_delegate);
+
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.method = ASCIIToUTF16("POST");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+ form.user_submitted = true;
+
+ FormFieldData field;
+ test::CreateTestFormField("Address", "address", "", "textarea", &field);
+
+ EXPECT_CALL(external_delegate,
+ OnSuggestionsReturned(0,
+ std::vector<base::string16>(),
+ std::vector<base::string16>(),
+ std::vector<base::string16>(),
+ std::vector<int>()));
+ autocomplete_history_manager.OnGetAutocompleteSuggestions(
+ 0,
+ field.name,
+ field.value,
+ field.form_control_type,
+ std::vector<base::string16>(),
+ std::vector<base::string16>(),
+ std::vector<base::string16>(),
+ std::vector<int>());
+}
+
} // namespace autofill
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 96f7eb2..80902aa7 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -450,7 +450,8 @@ void AutofillManager::OnQueryFormFieldAutofill(int query_id,
// hand off what we generated and they will send the results back to the
// renderer.
autocomplete_history_manager_->OnGetAutocompleteSuggestions(
- query_id, field.name, field.value, values, labels, icons, unique_ids);
+ query_id, field.name, field.value, field.form_control_type, values,
+ labels, icons, unique_ids);
}
void AutofillManager::FillOrPreviewForm(