diff options
author | petersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-08 02:13:09 +0000 |
---|---|---|
committer | petersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-08 02:13:09 +0000 |
commit | d893ab9643e5284db08087bc7514f59e37d6b319 (patch) | |
tree | 862077a3e8acbb010157f8c3bdd45e95d7e40ecb | |
parent | bab654788c013d4cdf3900fc43927e159362b5ed (diff) | |
download | chromium_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.cc | 56 | ||||
-rw-r--r-- | chrome/browser/autofill_manager.h | 28 | ||||
-rw-r--r-- | chrome/browser/render_view_host.cc | 38 | ||||
-rw-r--r-- | chrome/browser/render_view_host.h | 6 | ||||
-rw-r--r-- | chrome/browser/render_view_host_delegate.h | 14 | ||||
-rw-r--r-- | chrome/browser/web_contents.cc | 11 | ||||
-rw-r--r-- | chrome/browser/web_contents.h | 2 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 7 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 7 | ||||
-rw-r--r-- | webkit/glue/webframeloaderclient_impl.cc | 44 |
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); |