diff options
Diffstat (limited to 'chrome/browser/autofill')
9 files changed, 457 insertions, 20 deletions
diff --git a/chrome/browser/autofill/autofill_external_delegate.cc b/chrome/browser/autofill/autofill_external_delegate.cc index 6d0a6f3..8c0bcdd 100644 --- a/chrome/browser/autofill/autofill_external_delegate.cc +++ b/chrome/browser/autofill/autofill_external_delegate.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,8 +17,10 @@ AutofillExternalDelegate::~AutofillExternalDelegate() { } AutofillExternalDelegate::AutofillExternalDelegate( - TabContentsWrapper* tab_contents_wrapper) + TabContentsWrapper* tab_contents_wrapper, + AutofillManager* autofill_manager) : tab_contents_wrapper_(tab_contents_wrapper), + autofill_manager_(autofill_manager), autofill_query_id_(0), display_warning_if_disabled_(false), has_shown_autofill_popup_for_current_edit_(false) { @@ -41,7 +43,7 @@ void AutofillExternalDelegate::OnQuery(int query_id, display_warning_if_disabled_ = display_warning_if_disabled; autofill_query_id_ = query_id; - OnQueryPlatformSpecific(query_id, form, field); + OnQueryPlatformSpecific(query_id, form, field, bounds); } void AutofillExternalDelegate::DidEndTextFieldEditing() { @@ -134,7 +136,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned( // in an autofill_external_delegate_YOUROS.cc. Currently there are // none, so all platforms use the default. -#if !defined(OS_ANDROID) +#if !defined(OS_ANDROID) && !defined(TOOLKIT_GTK) AutofillExternalDelegate* AutofillExternalDelegate::Create( TabContentsWrapper*, AutofillManager*) { diff --git a/chrome/browser/autofill/autofill_external_delegate.h b/chrome/browser/autofill/autofill_external_delegate.h index 4890565..20d15bb 100644 --- a/chrome/browser/autofill/autofill_external_delegate.h +++ b/chrome/browser/autofill/autofill_external_delegate.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -76,7 +76,8 @@ class AutofillExternalDelegate { void DidEndTextFieldEditing(); protected: - explicit AutofillExternalDelegate(TabContentsWrapper* tab_contents_wrapper); + explicit AutofillExternalDelegate(TabContentsWrapper* tab_contents_wrapper, + AutofillManager* autofill_manager); // Displays the the Autofill results to the user with an external // Autofill popup that lives completely in the browser. The suggestions @@ -89,13 +90,14 @@ class AutofillExternalDelegate { int separator_index) = 0; // Handle instance specific OnQueryCode. - virtual void OnQueryPlatformSpecific( - int query_id, - const webkit::forms::FormData& form, - const webkit::forms::FormField& field) = 0; + virtual void OnQueryPlatformSpecific(int query_id, + const webkit::forms::FormData& form, + const webkit::forms::FormField& field, + const gfx::Rect& bounds) = 0; private: TabContentsWrapper* tab_contents_wrapper_; // weak; owns me. + AutofillManager* autofill_manager_; // weak. // The ID of the last request sent for form field Autofill. Used to ignore // out of date responses. diff --git a/chrome/browser/autofill/autofill_external_delegate_gtk.cc b/chrome/browser/autofill/autofill_external_delegate_gtk.cc new file mode 100644 index 0000000..e39b72e --- /dev/null +++ b/chrome/browser/autofill/autofill_external_delegate_gtk.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/autofill_external_delegate_gtk.h" + +#include "chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_view.h" +#include "content/public/browser/web_contents.h" + +AutofillExternalDelegate* AutofillExternalDelegate::Create( + TabContentsWrapper* tab_contents_wrapper, + AutofillManager* autofill_manager) { + return new AutofillExternalDelegateGtk(tab_contents_wrapper, + autofill_manager); +} + +AutofillExternalDelegateGtk::AutofillExternalDelegateGtk( + TabContentsWrapper* tab_contents_wrapper, + AutofillManager* autofill_manager) + : AutofillExternalDelegate(tab_contents_wrapper, autofill_manager), + web_contents_(tab_contents_wrapper->web_contents()) { + tab_native_view_ = web_contents_->GetView()->GetNativeView(); +} + +AutofillExternalDelegateGtk::~AutofillExternalDelegateGtk() { +} + +void AutofillExternalDelegateGtk::OnQueryPlatformSpecific( + int query_id, + const webkit::forms::FormData& form, + const webkit::forms::FormField& field, + const gfx::Rect& bounds) { + CreateViewIfNeeded(); + view_->set_element_bounds(bounds); +} + +void AutofillExternalDelegateGtk::ApplyAutofillSuggestions( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids, + int separator_index) { + view_->Show(autofill_values, + autofill_labels, + autofill_icons, + autofill_unique_ids, + separator_index); +} + +void AutofillExternalDelegateGtk::HideAutofillPopup() { + if (!view_.get()) + return; + + view_->Hide(); + view_.reset(); + + GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_); + g_signal_handler_disconnect(toplevel, event_handler_id_); +} + +void AutofillExternalDelegateGtk::CreateViewIfNeeded() { + if (view_.get()) + return; + + view_.reset(new AutofillPopupViewGtk(web_contents_, + tab_native_view_)); + + GtkWidget* toplevel = gtk_widget_get_toplevel(tab_native_view_); + if (!g_signal_handler_is_connected(toplevel, event_handler_id_)) { + event_handler_id_ = g_signal_connect( + toplevel, + "focus-out-event", + G_CALLBACK(HandleViewFocusOutThunk), + this); + } +} + +gboolean AutofillExternalDelegateGtk::HandleViewFocusOut(GtkWidget* sender, + GdkEventFocus* event) { + HideAutofillPopup(); + + return TRUE; +} diff --git a/chrome/browser/autofill/autofill_external_delegate_gtk.h b/chrome/browser/autofill/autofill_external_delegate_gtk.h new file mode 100644 index 0000000..31e2fd0 --- /dev/null +++ b/chrome/browser/autofill/autofill_external_delegate_gtk.h @@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_GTK_H_ +#define CHROME_BROWSER_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_GTK_H_ +#pragma once + +#include <gtk/gtk.h> + +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/autofill/autofill_external_delegate.h" +#include "ui/base/gtk/gtk_signal.h" +#include "ui/gfx/native_widget_types.h" + +class AutofillPopupViewGtk; + +namespace content { +class WebContents; +} + +class AutofillExternalDelegateGtk : public AutofillExternalDelegate { + public: + AutofillExternalDelegateGtk(TabContentsWrapper* tab_contents_wrapper, + AutofillManager* autofill_manager); + + virtual ~AutofillExternalDelegateGtk(); + + // AutofillExternalDelegate implementation. + virtual void HideAutofillPopup() OVERRIDE; + + protected: + // AutofillExternalDelegate implementations. + virtual void OnQueryPlatformSpecific( + int query_id, + const webkit::forms::FormData& form, + const webkit::forms::FormField& field, + const gfx::Rect& bounds) OVERRIDE; + virtual void ApplyAutofillSuggestions( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids, + int separator_index) OVERRIDE; + + private: + // Create a valid view to display the autofill results if one doesn't + // currently exist. + void CreateViewIfNeeded(); + + CHROMEGTK_CALLBACK_1(AutofillExternalDelegateGtk, gboolean, + HandleViewFocusOut, GdkEventFocus*); + + scoped_ptr<AutofillPopupViewGtk> view_; + + content::WebContents* web_contents_; // Weak reference. + gfx::NativeView tab_native_view_; // Weak reference. + + // The handler value for the focus out event, allows us to block and unblock + // it as needed. + gulong event_handler_id_; + + DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateGtk); +}; + +#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_GTK_H_ diff --git a/chrome/browser/autofill/autofill_external_delegate_unittest.cc b/chrome/browser/autofill/autofill_external_delegate_unittest.cc new file mode 100644 index 0000000..f9e6f6c --- /dev/null +++ b/chrome/browser/autofill/autofill_external_delegate_unittest.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/string16.h" +#include "chrome/browser/autofill/autofill_external_delegate.h" +#include "chrome/browser/autofill/autofill_manager.h" +#include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h" +#include "chrome/test/base/testing_profile.h" +#include "content/test/test_browser_thread.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/rect.h" +#include "webkit/forms/form_data.h" +#include "webkit/forms/form_field.h" + +using content::BrowserThread; +using testing::_; +using webkit::forms::FormData; +using webkit::forms::FormField; + +namespace { + +class MockAutofillExternalDelegate : public AutofillExternalDelegate { + public: + explicit MockAutofillExternalDelegate(TabContentsWrapper* wrapper, + AutofillManager* autofill_manager) + : AutofillExternalDelegate(wrapper, autofill_manager) {} + virtual ~MockAutofillExternalDelegate() {} + + virtual void HideAutofillPopup() OVERRIDE {} + + MOCK_METHOD5(ApplyAutofillSuggestions, void( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids, + int separator_index)); + + MOCK_METHOD4(OnQueryPlatformSpecific, + void(int query_id, + const webkit::forms::FormData& form, + const webkit::forms::FormField& field, + const gfx::Rect& bounds)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockAutofillExternalDelegate); +}; + +} // namespace + +class AutofillExternalDelegateTest : public TabContentsWrapperTestHarness { + public: + AutofillExternalDelegateTest() + : ui_thread_(BrowserThread::UI, &message_loop_) {} + virtual ~AutofillExternalDelegateTest() {} + + virtual void SetUp() OVERRIDE { + TabContentsWrapperTestHarness::SetUp(); + autofill_manager_ = new AutofillManager(contents_wrapper()); + } + + protected: + scoped_refptr<AutofillManager> autofill_manager_; + + private: + content::TestBrowserThread ui_thread_; + + DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateTest); +}; + +// Test that our external delegate called the virtual methods at the right time. +TEST_F(AutofillExternalDelegateTest, TestExternalDelegateVirtualCalls) { + MockAutofillExternalDelegate external_delegate(contents_wrapper(), + autofill_manager_); + const int kQueryId = 5; + const FormData form; + FormField field; + field.is_focusable = true; + field.should_autocomplete = true; + const gfx::Rect bounds; + + EXPECT_CALL(external_delegate, + OnQueryPlatformSpecific(kQueryId, form, field, bounds)); + + // This should call OnQueryPlatform specific. + external_delegate.OnQuery(kQueryId, form, field, bounds, false); + + + EXPECT_CALL(external_delegate, ApplyAutofillSuggestions(_, _, _, _, _)); + + // This should call ApplyAutofillSuggestions. + std::vector<string16> autofill_item; + autofill_item.push_back(string16()); + std::vector<int> autofill_ids; + autofill_ids.push_back(1); + external_delegate.OnSuggestionsReturned(kQueryId, + autofill_item, + autofill_item, + autofill_item, + autofill_ids); +} diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc index 22abbf0..ee42ca3 100644 --- a/chrome/browser/autofill/autofill_manager_unittest.cc +++ b/chrome/browser/autofill/autofill_manager_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -2864,8 +2864,9 @@ namespace { class MockAutofillExternalDelegate : public AutofillExternalDelegate { public: - explicit MockAutofillExternalDelegate(TabContentsWrapper* wrapper) - : AutofillExternalDelegate(wrapper) {} + explicit MockAutofillExternalDelegate(TabContentsWrapper* wrapper, + AutofillManager* autofill_manager) + : AutofillExternalDelegate(wrapper, autofill_manager) {} virtual ~MockAutofillExternalDelegate() {} MOCK_METHOD5(OnQuery, void(int query_id, @@ -2883,10 +2884,10 @@ class MockAutofillExternalDelegate : public AutofillExternalDelegate { const std::vector<int>& autofill_unique_ids, int separator_index) OVERRIDE {} - virtual void OnQueryPlatformSpecific( - int query_id, - const webkit::forms::FormData& form, - const webkit::forms::FormField& field) OVERRIDE {} + virtual void OnQueryPlatformSpecific(int query_id, + const webkit::forms::FormData& form, + const webkit::forms::FormField& field, + const gfx::Rect& bounds) OVERRIDE {} private: DISALLOW_COPY_AND_ASSIGN(MockAutofillExternalDelegate); @@ -2896,7 +2897,8 @@ class MockAutofillExternalDelegate : public AutofillExternalDelegate { // Test our external delegate is called at the right time. TEST_F(AutofillManagerTest, TestExternalDelegate) { - MockAutofillExternalDelegate external_delegate(contents_wrapper()); + MockAutofillExternalDelegate external_delegate(contents_wrapper(), + autofill_manager_); EXPECT_CALL(external_delegate, OnQuery(_, _, _, _, _)); autofill_manager_->SetExternalDelegate(&external_delegate); @@ -2910,8 +2912,8 @@ TEST_F(AutofillManagerTest, TestExternalDelegate) { autofill_manager_->SetExternalDelegate(NULL); } -#if defined(OS_ANDROID) -// Only OS_ANDROID defines an external delegate, but prerequisites for +#if defined(OS_ANDROID) || defined(TOOLKIT_GTK) +// OS_ANDROID defines an external delegate, but prerequisites for // landing autofill_external_delegate_android.cc in the Chromium tree // have not themselves landed. diff --git a/chrome/browser/autofill/autofill_popup_view.cc b/chrome/browser/autofill/autofill_popup_view.cc new file mode 100644 index 0000000..9a2ea79 --- /dev/null +++ b/chrome/browser/autofill/autofill_popup_view.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/autofill_popup_view.h" + +#include "content/public/browser/web_contents.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" + +AutofillPopupView::AutofillPopupView(content::WebContents* web_contents) { + registrar_.Add(this, + content::NOTIFICATION_WEB_CONTENTS_HIDDEN, + content::Source<content::WebContents>(web_contents)); + registrar_.Add( + this, + content::NOTIFICATION_NAV_ENTRY_COMMITTED, + content::Source<content::NavigationController>( + &(web_contents->GetController()))); +} + +AutofillPopupView::~AutofillPopupView() {} + +void AutofillPopupView::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + if (type == content::NOTIFICATION_WEB_CONTENTS_HIDDEN + || type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) + Hide(); +} diff --git a/chrome/browser/autofill/autofill_popup_view.h b/chrome/browser/autofill/autofill_popup_view.h new file mode 100644 index 0000000..bde5cd2 --- /dev/null +++ b/chrome/browser/autofill/autofill_popup_view.h @@ -0,0 +1,54 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ +#define CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_observer.h" +#include "ui/gfx/rect.h" + +namespace content { +class WebContents; +} + +class AutofillPopupView : public content::NotificationObserver { + public: + explicit AutofillPopupView(content::WebContents* web_contents); + virtual ~AutofillPopupView(); + + // Hide the popup from view. + virtual void Hide() = 0; + + // Display the autofill popup and fill it in with the values passed in. + virtual void Show(const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids, + int separator_index) = 0; + + + void set_element_bounds(const gfx::Rect& bounds) { + element_bounds_ = bounds; + } + + const gfx::Rect& element_bounds() { return element_bounds_; } + + private: + // content::NotificationObserver method override. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // A scoped container for notification registries. + content::NotificationRegistrar registrar_; + + // The bounds of the text element that is the focus of the Autofill. + gfx::Rect element_bounds_; +}; + +#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ diff --git a/chrome/browser/autofill/autofill_popup_view_browsertest.cc b/chrome/browser/autofill/autofill_popup_view_browsertest.cc new file mode 100644 index 0000000..52f6421 --- /dev/null +++ b/chrome/browser/autofill/autofill_popup_view_browsertest.cc @@ -0,0 +1,87 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/autofill_popup_view.h" + +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/page_navigator.h" +#include "content/public/common/url_constants.h" +#include "content/test/browser_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +class TestAutofillPopupView : public AutofillPopupView { + public: + explicit TestAutofillPopupView(content::WebContents* web_contents) + : AutofillPopupView(web_contents) {} + virtual ~TestAutofillPopupView() {} + + MOCK_METHOD0(Hide, void()); + + virtual void Show(const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids, + int separator_index) OVERRIDE {} +}; + +class AutofillPopupViewBrowserTest : public InProcessBrowserTest { + public: + AutofillPopupViewBrowserTest() {} + virtual ~AutofillPopupViewBrowserTest() {} + + protected: + scoped_ptr<TestAutofillPopupView> autofill_popup_view_; +}; + + +#if defined(OS_WIN) +// http://crbug.com/109269 +#define MAYBE_SwitchTabAndHideAutofillPopup \ + DISABLED_SwitchTabAndHideAutofillPopup +#else +#define MAYBE_SwitchTabAndHideAutofillPopup SwitchTabAndHideAutofillPopup +#endif +IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, + MAYBE_SwitchTabAndHideAutofillPopup) { + content::WebContents* web_contents = browser()->GetSelectedWebContents(); + TestAutofillPopupView autofill_popup_view(web_contents); + EXPECT_CALL(autofill_popup_view, Hide()); + + ui_test_utils::WindowedNotificationObserver observer( + content::NOTIFICATION_WEB_CONTENTS_HIDDEN, + content::Source<content::WebContents>(web_contents)); + browser()->AddSelectedTabWithURL(GURL(chrome::kAboutBlankURL), + content::PAGE_TRANSITION_START_PAGE); + observer.Wait(); + + // The mock verifies that the call was made. +} + +IN_PROC_BROWSER_TEST_F(InProcessBrowserTest, + TestPageNavigationHidingAutofillPopup) { + content::WebContents* web_contents = browser()->GetSelectedWebContents(); + TestAutofillPopupView autofill_popup_view(web_contents); + EXPECT_CALL(autofill_popup_view, Hide()); + + ui_test_utils::WindowedNotificationObserver observer( + content::NOTIFICATION_NAV_ENTRY_COMMITTED, + content::Source<content::NavigationController>( + &(web_contents->GetController()))); + browser()->OpenURL(content::OpenURLParams( + GURL(chrome::kAboutBlankURL), content::Referrer(), + CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false)); + browser()->OpenURL(content::OpenURLParams( + GURL(chrome::kAboutCrashURL), content::Referrer(), + CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false)); + observer.Wait(); + + // The mock verifies that the call was made. +} |