Commit b96a1d1a authored by dbeam@chromium.org's avatar dbeam@chromium.org

[autofill] Fill in values on a successful run of interactive autocomplete.

R=estade@chromium.org,isherman@chromium.org
TBR=jschuh@chromium.org
BUG=157661

Review URL: https://codereview.chromium.org/11348273

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170581 0039d316-1c4b-4281-b951-d872f2087c98
parent 557a6080
......@@ -789,13 +789,12 @@ void AutofillManager::ReturnAutocompleteData(const FormStructure* result) {
return;
if (!result) {
host->Send(new AutofillMsg_RequestAutocompleteFinished(
host->GetRoutingID(), WebKit::WebFormElement::AutocompleteResultError));
} else {
// TODO(estade): implement non-failure case.
host->Send(new AutofillMsg_RequestAutocompleteFinished(
host->GetRoutingID(), WebKit::WebFormElement::AutocompleteResultError));
host->Send(new AutofillMsg_RequestAutocompleteError(host->GetRoutingID()));
return;
}
host->Send(new AutofillMsg_RequestAutocompleteSuccess(host->GetRoutingID(),
result->ToFormData()));
}
void AutofillManager::OnLoadedServerPredictions(
......
......@@ -522,7 +522,7 @@ bool FormStructure::IsAutofillable(bool require_method_post) const {
// TODO(ramankk): Remove this check once we have better way of identifying the
// cases to trigger experimental form filling.
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalFormFilling))
switches::kEnableExperimentalFormFilling))
return true;
if (autofill_count() < kRequiredFillableFields)
......@@ -545,7 +545,7 @@ bool FormStructure::ShouldBeParsed(bool require_method_post) const {
// TODO(ramankk): Remove this check once we have better way of identifying the
// cases to trigger experimental form filling.
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalFormFilling))
switches::kEnableExperimentalFormFilling))
return true;
if (field_count() < kRequiredFillableFields)
......@@ -814,6 +814,21 @@ std::string FormStructure::server_experiment_id() const {
return server_experiment_id_;
}
FormData FormStructure::ToFormData() const {
// |data.user_submitted| will always be false.
FormData data;
data.name = form_name_;
data.origin = source_url_;
data.action = target_url_;
data.method = ASCIIToUTF16(method_ == POST ? "POST" : "GET");
for (size_t i = 0; i < fields_.size(); ++i) {
data.fields.push_back(FormFieldData(*fields_[i]));
}
return data;
}
bool FormStructure::operator==(const FormData& form) const {
// TODO(jhawkins): Is this enough to differentiate a form?
if (form_name_ == form.name &&
......
......@@ -145,6 +145,10 @@ class FormStructure {
virtual std::string server_experiment_id() const;
// Returns a FormData containing the data this form structure knows about.
// |user_submitted| is currently always false.
FormData ToFormData() const;
bool operator==(const FormData& form) const;
bool operator!=(const FormData& form) const;
......
......@@ -2063,3 +2063,34 @@ TEST(FormStructureTest, CheckFormSignature) {
std::string("https://login.facebook.com&login_form&email&first")),
form_structure->FormSignature());
}
TEST(FormStructureTest, ToFormData) {
FormData form;
form.name = ASCIIToUTF16("the-name");
form.method = ASCIIToUTF16("POST");
form.origin = GURL("http://cool.com");
form.action = form.origin.Resolve("/login");
FormFieldData field;
field.label = ASCIIToUTF16("username");
field.name = ASCIIToUTF16("username");
field.form_control_type = "text";
form.fields.push_back(field);
field.label = ASCIIToUTF16("password");
field.name = ASCIIToUTF16("password");
field.form_control_type = "password";
form.fields.push_back(field);
field.label = string16();
field.name = ASCIIToUTF16("Submit");
field.form_control_type = "submit";
form.fields.push_back(field);
EXPECT_EQ(form, FormStructure(form).ToFormData());
// Currently |FormStructure(form_data)ToFormData().user_submitted| is always
// false. This forces a future author that changes this to update this test.
form.user_submitted = true;
EXPECT_NE(form, FormStructure(form).ToFormData());
}
......@@ -134,9 +134,16 @@ IPC_MESSAGE_ROUTED1(AutofillMsg_AcceptPasswordAutofillSuggestion,
IPC_MESSAGE_ROUTED1(AutofillMsg_FormNotBlacklisted,
content::PasswordForm /* form checked */)
// Sent when interactive autocomplete finishes.
IPC_MESSAGE_ROUTED1(AutofillMsg_RequestAutocompleteFinished,
WebKit::WebFormElement::AutocompleteResult /* result */)
// Sent when requestAutocomplete() succeeds. Tells the renderer to Autofill the
// form that requested autocomplete with the |form_data| values input by the
// user.
IPC_MESSAGE_ROUTED1(AutofillMsg_RequestAutocompleteSuccess,
FormData /* form_data */)
// Sent when requestAutocomplete() fails. Currently, this happens when a form is
// requested to be autocompleted with no input or select tags with autocomplete
// attributes.
IPC_MESSAGE_ROUTED0(AutofillMsg_RequestAutocompleteError);
// Autofill messages sent from the renderer to the browser.
......
......@@ -30,3 +30,7 @@ bool FormData::operator==(const FormData& form) const {
user_submitted == form.user_submitted &&
fields == form.fields);
}
bool FormData::operator!=(const FormData& form) const {
return !operator==(form);
}
......@@ -32,6 +32,7 @@ struct FormData {
// Used by FormStructureTest.
bool operator==(const FormData& form) const;
bool operator!=(const FormData& form) const;
};
#endif // CHROME_COMMON_FORM_DATA_H__
......@@ -158,8 +158,10 @@ bool AutofillAgent::OnMessageReceived(const IPC::Message& message) {
OnAcceptDataListSuggestion)
IPC_MESSAGE_HANDLER(AutofillMsg_AcceptPasswordAutofillSuggestion,
OnAcceptPasswordAutofillSuggestion)
IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteFinished,
OnRequestAutocompleteFinished)
IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteSuccess,
OnRequestAutocompleteSuccess)
IPC_MESSAGE_HANDLER(AutofillMsg_RequestAutocompleteError,
OnRequestAutocompleteError)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
......@@ -331,8 +333,8 @@ void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
if (did_set_node_text_) {
did_set_node_text_ = false;
return;
did_set_node_text_ = false;
return;
}
// We post a task for doing the Autofill as the caret position is not set
......@@ -589,14 +591,22 @@ void AutofillAgent::OnAcceptPasswordAutofillSuggestion(const string16& value) {
DCHECK(handled);
}
void AutofillAgent::OnRequestAutocompleteFinished(
void AutofillAgent::FinishAutocompleteRequest(
WebFormElement::AutocompleteResult result) {
DCHECK(!in_flight_request_form_.isNull());
in_flight_request_form_.finishRequestAutocomplete(result);
in_flight_request_form_.reset();
}
void AutofillAgent::OnRequestAutocompleteSuccess(const FormData& form_data) {
FillFormIncludingNonFocusableElements(form_data, in_flight_request_form_);
FinishAutocompleteRequest(WebFormElement::AutocompleteResultSuccess);
}
void AutofillAgent::OnRequestAutocompleteError() {
FinishAutocompleteRequest(WebFormElement::AutocompleteResultError);
}
void AutofillAgent::ShowSuggestions(const WebInputElement& element,
bool autofill_on_empty_values,
bool requires_caret_at_end,
......
......@@ -112,7 +112,11 @@ class AutofillAgent : public content::RenderViewObserver,
void OnAcceptPasswordAutofillSuggestion(const string16& value);
// For interactive autocomplete.
void OnRequestAutocompleteFinished(
void OnRequestAutocompleteSuccess(const FormData& form_data);
void OnRequestAutocompleteError();
// Called when an autocomplete request succeeds or fails with the |result|.
void FinishAutocompleteRequest(
WebKit::WebFormElement::AutocompleteResult result);
// Called in a posted task by textFieldDidChange() to work-around a WebKit bug
......
......@@ -413,15 +413,16 @@ void GetOptionStringsFromElement(const WebSelectElement& select_element,
}
// The callback type used by |ForEachMatchingFormField()|.
typedef void (*Callback)(WebKit::WebFormControlElement*,
const FormFieldData*,
bool);
typedef void (*Callback)(const FormFieldData&,
bool, /* is_initiating_element */
WebKit::WebFormControlElement*);
// For each autofillable field in |data| that matches a field in the |form|,
// the |callback| is invoked with the corresponding |form| field data.
void ForEachMatchingFormField(const WebFormElement& form_element,
const WebElement& initiating_element,
const FormData& data,
bool only_focusable_elements,
Callback callback) {
std::vector<WebFormControlElement> control_elements;
ExtractAutofillableElements(form_element, autofill::REQUIRE_AUTOCOMPLETE,
......@@ -466,20 +467,20 @@ void ForEachMatchingFormField(const WebFormElement& form_element,
}
if (!element->isEnabled() || element->isReadOnly() ||
!element->isFocusable())
(only_focusable_elements && !element->isFocusable()))
continue;
callback(element, &data.fields[i], is_initiating_element);
callback(data.fields[i], is_initiating_element, element);
}
}
// Sets the |field|'s value to the value in |data|.
// Also sets the "autofilled" attribute, causing the background to be yellow.
void FillFormField(WebKit::WebFormControlElement* field,
const FormFieldData* data,
bool is_initiating_node) {
void FillFormField(const FormFieldData& data,
bool is_initiating_node,
WebKit::WebFormControlElement* field) {
// Nothing to fill.
if (data->value.empty())
if (data.value.empty())
return;
WebInputElement* input_element = toWebInputElement(field);
......@@ -487,7 +488,7 @@ void FillFormField(WebKit::WebFormControlElement* field,
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
input_element->setValue(
data->value.substr(0, input_element->maxLength()), true);
data.value.substr(0, input_element->maxLength()), true);
input_element->setAutofilled(true);
if (is_initiating_node) {
int length = input_element->value().length();
......@@ -498,8 +499,8 @@ void FillFormField(WebKit::WebFormControlElement* field,
} else {
DCHECK(IsSelectElement(*field));
WebSelectElement select_element = field->to<WebSelectElement>();
if (select_element.value() != data->value) {
select_element.setValue(data->value);
if (select_element.value() != data.value) {
select_element.setValue(data.value);
select_element.dispatchFormControlChangeEvent();
}
}
......@@ -507,11 +508,11 @@ void FillFormField(WebKit::WebFormControlElement* field,
// Sets the |field|'s "suggested" (non JS visible) value to the value in |data|.
// Also sets the "autofilled" attribute, causing the background to be yellow.
void PreviewFormField(WebKit::WebFormControlElement* field,
const FormFieldData* data,
bool is_initiating_node) {
void PreviewFormField(const FormFieldData& data,
bool is_initiating_node,
WebKit::WebFormControlElement* field) {
// Nothing to preview.
if (data->value.empty())
if (data.value.empty())
return;
// Only preview input fields.
......@@ -522,7 +523,7 @@ void PreviewFormField(WebKit::WebFormControlElement* field,
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
input_element->setSuggestedValue(
data->value.substr(0, input_element->maxLength()));
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.
......@@ -820,6 +821,19 @@ void FillForm(const FormData& form, const WebInputElement& element) {
ForEachMatchingFormField(form_element,
element,
form,
true, /* only_focusable_elements */
&FillFormField);
}
void FillFormIncludingNonFocusableElements(const FormData& form_data,
const WebFormElement& form_element) {
if (form_element.isNull())
return;
ForEachMatchingFormField(form_element,
WebInputElement(),
form_data,
false, /* only_focusable_elements */
&FillFormField);
}
......@@ -831,6 +845,7 @@ void PreviewForm(const FormData& form, const WebInputElement& element) {
ForEachMatchingFormField(form_element,
element,
form,
true, /* only_focusable_elements */
&PreviewFormField);
}
......
......@@ -20,7 +20,7 @@ class WebInputElement;
namespace autofill {
// A bit field mask for form requirements.
// A bit field mask for form or form element requirements.
enum RequirementsMask {
REQUIRE_NONE = 0, // No requirements.
REQUIRE_AUTOCOMPLETE = 1, // Require that autocomplete != off.
......@@ -98,6 +98,12 @@ bool FindFormAndFieldForInputElement(const WebKit::WebInputElement& element,
void FillForm(const FormData& form,
const WebKit::WebInputElement& element);
// Fills focusable and non-focusable form control elements within |form_element|
// with field data from |form_data|.
void FillFormIncludingNonFocusableElements(
const FormData& form_data,
const WebKit::WebFormElement& form_element);
// Previews the form represented by |form|. |element| is the input element that
// initiated the preview process.
void PreviewForm(const FormData& form,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment