summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-08 02:13:09 +0000
committerpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-08 02:13:09 +0000
commitd893ab9643e5284db08087bc7514f59e37d6b319 (patch)
tree862077a3e8acbb010157f8c3bdd45e95d7e40ecb
parentbab654788c013d4cdf3900fc43927e159362b5ed (diff)
downloadchromium_src-d893ab9643e5284db08087bc7514f59e37d6b319.zip
chromium_src-d893ab9643e5284db08087bc7514f59e37d6b319.tar.gz
chromium_src-d893ab9643e5284db08087bc7514f59e37d6b319.tar.bz2
Entries in a form get recorded when the user submits the form. Database and pop-up menu talk to each other. Pop-up menu appears containing suggestions.
Review URL: http://codereview.chromium.org/9462 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5058 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autofill_manager.cc56
-rw-r--r--chrome/browser/autofill_manager.h28
-rw-r--r--chrome/browser/render_view_host.cc38
-rw-r--r--chrome/browser/render_view_host.h6
-rw-r--r--chrome/browser/render_view_host_delegate.h14
-rw-r--r--chrome/browser/web_contents.cc11
-rw-r--r--chrome/browser/web_contents.h2
-rw-r--r--chrome/renderer/render_view.cc7
-rw-r--r--chrome/renderer/render_view.h7
-rw-r--r--webkit/glue/webframeloaderclient_impl.cc44
10 files changed, 140 insertions, 73 deletions
diff --git a/chrome/browser/autofill_manager.cc b/chrome/browser/autofill_manager.cc
index af8589b..9493992 100644
--- a/chrome/browser/autofill_manager.cc
+++ b/chrome/browser/autofill_manager.cc
@@ -8,15 +8,21 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/web_contents.h"
-AutofillManager::~AutofillManager() {
- ClearPendingQuery();
+AutofillManager::AutofillManager(WebContents* web_contents) :
+ web_contents_(web_contents),
+ pending_query_handle_(0),
+ node_id_(0),
+ request_id_(0) {
+ form_autofill_enabled_.Init(prefs::kFormAutofillEnabled,
+ profile()->GetPrefs(), NULL);
}
-void AutofillManager::ClearPendingQuery() {
- pending_query_name_.clear();
- pending_query_prefix_.clear();
+AutofillManager::~AutofillManager() {
+ CancelPendingQuery();
+}
- if (query_is_pending_) {
+void AutofillManager::CancelPendingQuery() {
+ if (pending_query_handle_) {
WebDataService* web_data_service =
profile()->GetWebDataService(Profile::EXPLICIT_ACCESS);
if (!web_data_service) {
@@ -26,7 +32,10 @@ void AutofillManager::ClearPendingQuery() {
web_data_service->CancelRequest(pending_query_handle_);
}
pending_query_handle_ = 0;
- query_is_pending_ = false;
+}
+
+Profile* AutofillManager::profile() {
+ return web_contents_->profile();
}
void AutofillManager::AutofillFormSubmitted(const AutofillForm& form) {
@@ -35,7 +44,12 @@ void AutofillManager::AutofillFormSubmitted(const AutofillForm& form) {
void AutofillManager::FetchValuesForName(const std::wstring& name,
const std::wstring& prefix,
- int limit) {
+ int limit,
+ int64 node_id,
+ int request_id) {
+ if (!*form_autofill_enabled_)
+ return;
+
WebDataService* web_data_service =
profile()->GetWebDataService(Profile::EXPLICIT_ACCESS);
if (!web_data_service) {
@@ -43,17 +57,22 @@ void AutofillManager::FetchValuesForName(const std::wstring& name,
return;
}
- ClearPendingQuery();
+ CancelPendingQuery();
+
+ node_id_ = node_id;
+ request_id_ = request_id;
pending_query_handle_ = web_data_service->
GetFormValuesForElementName(name, prefix, limit, this);
- pending_query_name_ = name;
- pending_query_prefix_ = prefix;
}
void AutofillManager::OnWebDataServiceRequestDone(WebDataService::Handle h,
const WDTypedResult* result) {
- DCHECK(query_is_pending_);
+ DCHECK(pending_query_handle_);
+ pending_query_handle_ = 0;
+
+ if (!*form_autofill_enabled_)
+ return;
DCHECK(result);
if (!result)
@@ -61,18 +80,27 @@ void AutofillManager::OnWebDataServiceRequestDone(WebDataService::Handle h,
switch (result->GetType()) {
case AUTOFILL_VALUE_RESULT: {
+ RenderViewHost* host = web_contents_->render_view_host();
+ if (!host)
+ return;
+ const WDResult<std::vector<std::wstring> >* r =
+ static_cast<const WDResult<std::vector<std::wstring> >*>(result);
+ std::vector<std::wstring> suggestions = r->GetValue();
+ host->AutofillSuggestionsReturned(suggestions, node_id_, request_id_, -1);
break;
}
+
default:
NOTREACHED();
break;
}
-
- ClearPendingQuery();
}
void AutofillManager::StoreFormEntriesInWebDatabase(
const AutofillForm& form) {
+ if (!*form_autofill_enabled_)
+ return;
+
if (profile()->IsOffTheRecord())
return;
diff --git a/chrome/browser/autofill_manager.h b/chrome/browser/autofill_manager.h
index fac533f..72a04d4 100644
--- a/chrome/browser/autofill_manager.h
+++ b/chrome/browser/autofill_manager.h
@@ -9,22 +9,22 @@
#include <string>
#include "chrome/browser/webdata/web_data_service.h"
-#include "chrome/browser/web_contents.h"
+#include "chrome/common/pref_member.h"
#include "webkit/glue/autofill_form.h"
class Profile;
+class WebContents;
// Per-tab autofill manager. Handles receiving form data from the renderer and
// the storing and retrieving of form data through WebDataService.
class AutofillManager : public WebDataServiceConsumer {
public:
- explicit AutofillManager(WebContents* web_contents)
- : query_is_pending_(false), web_contents_(web_contents) {}
+ explicit AutofillManager(WebContents* web_contents);
virtual ~AutofillManager();
- void ClearPendingQuery();
+ void CancelPendingQuery();
- Profile* profile() { return web_contents_->profile(); }
+ Profile* profile();
// Called when a form is submitted (i.e. when the user hits the submit button)
// to store the form entries in the profile's sql database.
@@ -32,8 +32,11 @@ class AutofillManager : public WebDataServiceConsumer {
// Starts a query into the database for the values corresponding to name.
// OnWebDataServiceRequestDone gets called when the query completes.
- void FetchValuesForName(const std::wstring& name, const std::wstring& prefix,
- int limit);
+ void FetchValuesForName(const std::wstring& name,
+ const std::wstring& prefix,
+ int limit,
+ int64 node_id,
+ int request_id);
// WebDataServiceConsumer implementation.
virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
@@ -43,14 +46,15 @@ class AutofillManager : public WebDataServiceConsumer {
void StoreFormEntriesInWebDatabase(const AutofillForm& form);
WebContents* web_contents_;
-
+
+ BooleanPrefMember form_autofill_enabled_;
+
// When the manager makes a request from WebDataService, the database
- // is queried on another thread, we record the query in this map until we
+ // is queried on another thread, we record the query handle until we
// get called back.
- bool query_is_pending_;
WebDataService::Handle pending_query_handle_;
- std::wstring pending_query_name_;
- std::wstring pending_query_prefix_;
+ int64 node_id_;
+ int request_id_;
DISALLOW_COPY_AND_ASSIGN(AutofillManager);
};
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc
index 71c9574..d6b7f74 100644
--- a/chrome/browser/render_view_host.cc
+++ b/chrome/browser/render_view_host.cc
@@ -1233,37 +1233,15 @@ void RenderViewHost::OnQueryFormFieldAutofill(const std::wstring& field_name,
const std::wstring& user_text,
int64 node_id,
int request_id) {
- // TODO(jcampan): this is where the suggestions should be queried from the
- // database. The sample code commented below is left here in the meantime for
- // testing purpose.
-#ifndef TEST_AUTOFILL
- static std::vector<std::wstring>* suggestions = NULL;
- if (!suggestions) {
- suggestions = new std::vector<std::wstring>();
- suggestions->push_back(L"Alice");
- suggestions->push_back(L"Jay");
- suggestions->push_back(L"Jason");
- suggestions->push_back(L"Jasmine");
- suggestions->push_back(L"Jamel");
- suggestions->push_back(L"Jamelo");
- suggestions->push_back(L"Volvo");
- suggestions->push_back(L"Volswagen");
- }
-
+ delegate_->GetAutofillSuggestions(field_name, user_text, node_id, request_id);
+}
- std::vector<std::wstring> result;
- for (std::vector<std::wstring>::iterator iter = suggestions->begin();
- iter != suggestions->end(); ++iter) {
- if (StartsWith(*iter, user_text, false))
- result.push_back(*iter);
- }
- Send(new ViewMsg_AutofillSuggestions(routing_id_,
- node_id, request_id, result, 0));
-#else
- Send(new ViewMsg_AutofillSuggestions(routing_id_,
- node_id, request_id,
- std::vector<std::wstring>(), 0));
-#endif
+void RenderViewHost::AutofillSuggestionsReturned(
+ const std::vector<std::wstring>& suggestions,
+ int64 node_id, int request_id, int default_suggestion_index) {
+ Send(new ViewMsg_AutofillSuggestions(routing_id_, node_id,
+ request_id, suggestions, -1));
+ // Default index -1 means no default suggestion.
}
void RenderViewHost::NotifyRendererUnresponsive() {
diff --git a/chrome/browser/render_view_host.h b/chrome/browser/render_view_host.h
index 6c9fede..3638f9b 100644
--- a/chrome/browser/render_view_host.h
+++ b/chrome/browser/render_view_host.h
@@ -392,6 +392,12 @@ class RenderViewHost : public RenderWidgetHost {
// as a popup.
void DisassociateFromPopupCount();
+ // Called by the AutofillManager when the list of suggestions is ready.
+ void AutofillSuggestionsReturned(const std::vector<std::wstring>& suggestions,
+ int64 node_id,
+ int request_id,
+ int default_suggestion_index);
+
protected:
// Overridden from RenderWidgetHost:
virtual void UnhandledInputEvent(const WebInputEvent& event);
diff --git a/chrome/browser/render_view_host_delegate.h b/chrome/browser/render_view_host_delegate.h
index 4230438..63e2eaa 100644
--- a/chrome/browser/render_view_host_delegate.h
+++ b/chrome/browser/render_view_host_delegate.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "chrome/browser/autofill_manager.h"
#include "chrome/common/render_messages.h"
#include "webkit/glue/webpreferences.h"
@@ -283,10 +284,21 @@ class RenderViewHostDelegate {
// Password forms have been detected in the page.
virtual void PasswordFormsSeen(const std::vector<PasswordForm>& forms) { }
-
+
// Forms fillable by autofill have been detected in the page.
virtual void AutofillFormSubmitted(const AutofillForm& form) { }
+ // Called to retrieve a list of suggestions from the web database given
+ // the name of the field |field_name| and what the user has already typed in
+ // the field |user_text|. Appeals to the database thead to perform the query.
+ // When the database thread is finished, the autofill manager retrieves the
+ // calling RenderViewHost and then passes the vector of suggestions to
+ // RenderViewHost::AutofillSuggestionsReturned.
+ virtual void GetAutofillSuggestions(const std::wstring& field_name,
+ const std::wstring& user_text,
+ int64 node_id,
+ int request_id) { }
+
// Notification that the page has an OpenSearch description document.
virtual void PageHasOSDD(RenderViewHost* render_view_host,
int32 page_id, const GURL& doc_url,
diff --git a/chrome/browser/web_contents.cc b/chrome/browser/web_contents.cc
index 0c37ae0..acd9338 100644
--- a/chrome/browser/web_contents.cc
+++ b/chrome/browser/web_contents.cc
@@ -134,8 +134,13 @@ const wchar_t* kPrefsToObserve[] = {
// no font is specified or a CSS generic family (serif or sans-serif)
// is not specified.
};
+
const int kPrefsToObserveLength = arraysize(kPrefsToObserve);
+// Limit on the number of suggestions to appear in the pop-up menu under an
+// text input element in a form.
+const int kMaxAutofillMenuItems = 6;
+
void InitWebContentsClass() {
static bool web_contents_class_initialized = false;
if (!web_contents_class_initialized) {
@@ -1131,6 +1136,12 @@ void WebContents::AutofillFormSubmitted(
GetAutofillManager()->AutofillFormSubmitted(form);
}
+void WebContents::GetAutofillSuggestions(const std::wstring& field_name,
+ const std::wstring& user_text, int64 node_id, int request_id) {
+ GetAutofillManager()->FetchValuesForName(field_name, user_text,
+ kMaxAutofillMenuItems, node_id, request_id);
+}
+
// Checks to see if we should generate a keyword based on the OSDD, and if
// necessary uses TemplateURLFetcher to download the OSDD and create a keyword.
void WebContents::PageHasOSDD(RenderViewHost* render_view_host,
diff --git a/chrome/browser/web_contents.h b/chrome/browser/web_contents.h
index 8e06a1a..8b59d6b 100644
--- a/chrome/browser/web_contents.h
+++ b/chrome/browser/web_contents.h
@@ -290,6 +290,8 @@ class WebContents : public TabContents,
IPC::Message* reply_msg);
virtual void PasswordFormsSeen(const std::vector<PasswordForm>& forms);
virtual void AutofillFormSubmitted(const AutofillForm& form);
+ virtual void GetAutofillSuggestions(const std::wstring& field_name,
+ const std::wstring& user_text, int64 node_id, int request_id);
virtual void PageHasOSDD(RenderViewHost* render_view_host,
int32 page_id, const GURL& url, bool autodetected);
virtual void InspectElementReply(int num_resources);
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index cbae9d0..c0d4c55 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -1681,7 +1681,7 @@ void RenderView::QueryFormFieldAutofill(const std::wstring& field_name,
void RenderView::OnReceivedAutofillSuggestions(
int64 node_id,
int request_id,
- const std::vector<std::wstring> suggestions,
+ const std::vector<std::wstring>& suggestions,
int default_suggestion_index) {
if (!webview() || request_id != form_field_autofill_request_id_)
return;
@@ -2311,6 +2311,11 @@ void RenderView::OnPasswordFormsSeen(WebView* webview,
Send(new ViewHostMsg_PasswordFormsSeen(routing_id_, forms));
}
+void RenderView::OnAutofillFormSubmitted(WebView* webview,
+ const AutofillForm& form) {
+ Send(new ViewHostMsg_AutofillFormSubmitted(routing_id_, form));
+}
+
WebHistoryItem* RenderView::GetHistoryEntryAtOffset(int offset) {
// Our history list is kept in the browser process on the UI thread. Since
// we can't make a sync IPC call to that thread without risking deadlock,
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 8484afd..936a1bf 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -249,6 +249,9 @@ class RenderView : public RenderWidget, public WebViewDelegate,
virtual void OnPasswordFormsSeen(WebView* webview,
const std::vector<PasswordForm>& forms);
+ virtual void OnAutofillFormSubmitted(WebView* webview,
+ const AutofillForm& form);
+
virtual void ReportFindInPageMatchCount(int count, int request_id,
bool final_update);
virtual void ReportFindInPageSelection(int request_id,
@@ -465,8 +468,8 @@ class RenderView : public RenderWidget, public WebViewDelegate,
void OnReceivedAutofillSuggestions(
int64 node_id,
int request_id,
- const std::vector<std::wstring> suggestions,
- int default_suggestion_index);
+ const std::vector<std::wstring>& suggestions,
+ int default_suggestions_index);
#ifdef CHROME_PERSONALIZATION
void OnPersonalizationEvent(std::string event_name, std::string event_args);
diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc
index 6c50037..817993b 100644
--- a/webkit/glue/webframeloaderclient_impl.cc
+++ b/webkit/glue/webframeloaderclient_impl.cc
@@ -42,6 +42,7 @@ MSVC_POP_WARNING();
#if defined(OS_WIN)
#include "webkit/activex_shim/activex_shared.h"
#endif
+#include "webkit/glue/autofill_form.h"
#include "webkit/glue/alt_404_page_resource_fetcher.h"
#include "webkit/glue/autocomplete_input_listener.h"
#include "webkit/glue/form_autocomplete_listener.h"
@@ -343,7 +344,8 @@ void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() {
PassRefPtr<WebCore::HTMLCollection> forms =
webframe_->frame()->document()->forms();
- std::vector<PasswordForm> actions;
+ std::vector<PasswordForm> passwordForms;
+
unsigned int form_count = forms->length();
for (unsigned int i = 0; i < form_count; ++i) {
// Strange but true, sometimes item can be NULL.
@@ -357,18 +359,21 @@ void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() {
continue;
std::set<std::wstring> password_related_fields;
- scoped_ptr<PasswordForm> data(
+ scoped_ptr<PasswordForm> passwordFormPtr(
PasswordFormDomManager::CreatePasswordForm(form));
- if (data.get()) {
- actions.push_back(*data);
+
+ if (passwordFormPtr.get()) {
+ passwordForms.push_back(*passwordFormPtr);
+
// Let's remember the names of password related fields so we do not
// autofill them with the regular form autofill.
- if (!data->username_element.empty())
- password_related_fields.insert(data->username_element);
- DCHECK(!data->password_element.empty());
- password_related_fields.insert(data->password_element);
- if (!data->old_password_element.empty())
- password_related_fields.insert(data->old_password_element);
+
+ if (!passwordFormPtr->username_element.empty())
+ password_related_fields.insert(passwordFormPtr->username_element);
+ DCHECK(!passwordFormPtr->password_element.empty());
+ password_related_fields.insert(passwordFormPtr->password_element);
+ if (!passwordFormPtr->old_password_element.empty())
+ password_related_fields.insert(passwordFormPtr->old_password_element);
}
// Now let's register for any text input.
@@ -378,8 +383,8 @@ void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() {
}
}
- if (d && (actions.size() > 0))
- d->OnPasswordFormsSeen(webview, actions);
+ if (d && (passwordForms.size() > 0))
+ d->OnPasswordFormsSeen(webview, passwordForms);
if (d)
d->DidFinishDocumentLoadForFrame(webview, webframe_);
}
@@ -1003,7 +1008,7 @@ void WebFrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError&)
}
void WebFrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction function,
- PassRefPtr<FormState> form_ref) {
+ PassRefPtr<FormState> form_ref) {
SearchableFormData* form_data = SearchableFormData::Create(form_ref->form());
WebDocumentLoaderImpl* loader = static_cast<WebDocumentLoaderImpl*>(
webframe_->frame()->loader()->provisionalDocumentLoader());
@@ -1015,6 +1020,19 @@ void WebFrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction function,
// Don't free the PasswordFormData, the loader will do that.
loader->set_password_form_data(pass_data);
+ WebViewImpl* webview = webframe_->webview_impl();
+ WebViewDelegate* d = webview->delegate();
+
+ // Unless autocomplete=off, record what the user put in it for future
+ // autofilling.
+ if (form_ref->form()->autoComplete()) {
+ scoped_ptr<AutofillForm> autofill_form(
+ AutofillForm::CreateAutofillForm(form_ref->form()));
+ if (autofill_form.get()) {
+ d->OnAutofillFormSubmitted(webview, *autofill_form);
+ }
+ }
+
loader->set_form_submit(true);
(webframe_->frame()->loader()->*function)(PolicyUse);