diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-05-09 14:22:11 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-05-09 15:11:45 +0000 |
commit | 2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c (patch) | |
tree | e75f511546c5fd1a173e87c1f9fb11d7ac8d1af3 /chromium/components/web_modal | |
parent | a4f3d46271c57e8155ba912df46a05559d14726e (diff) | |
download | qtwebengine-chromium-2ddb2d3e14eef3de7dbd0cef553d669b9ac2361c.tar.gz |
BASELINE: Update Chromium to 51.0.2704.41
Also adds in all smaller components by reversing logic for exclusion.
Change-Id: Ibf90b506e7da088ea2f65dcf23f2b0992c504422
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'chromium/components/web_modal')
17 files changed, 1152 insertions, 0 deletions
diff --git a/chromium/components/web_modal/BUILD.gn b/chromium/components/web_modal/BUILD.gn new file mode 100644 index 00000000000..839715efbd2 --- /dev/null +++ b/chromium/components/web_modal/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright 2014 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. + +static_library("web_modal") { + sources = [ + "modal_dialog_host.cc", + "modal_dialog_host.h", + "single_web_contents_dialog_manager.h", + "web_contents_modal_dialog_host.cc", + "web_contents_modal_dialog_host.h", + "web_contents_modal_dialog_manager.cc", + "web_contents_modal_dialog_manager.h", + "web_contents_modal_dialog_manager_delegate.cc", + "web_contents_modal_dialog_manager_delegate.h", + ] + + deps = [ + "//base", + "//content/public/browser", + "//net", + "//skia", + "//ui/gfx", + "//ui/gfx/geometry", + ] +} + +static_library("test_support") { + testonly = true + sources = [ + "test_web_contents_modal_dialog_host.cc", + "test_web_contents_modal_dialog_host.h", + "test_web_contents_modal_dialog_manager_delegate.cc", + "test_web_contents_modal_dialog_manager_delegate.h", + ] + + public_deps = [ + ":web_modal", + ] + deps = [ + "//base", + "//ui/gfx", + "//ui/gfx/geometry", + ] +} + +if (!is_android && !is_ios) { + source_set("unit_tests") { + testonly = true + + sources = [ + "web_contents_modal_dialog_manager_unittest.cc", + ] + + deps = [ + ":test_support", + ":web_modal", + "//base", + "//content/test:test_support", + "//testing/gtest", + ] + } +} diff --git a/chromium/components/web_modal/DEPS b/chromium/components/web_modal/DEPS new file mode 100644 index 00000000000..3539cc43913 --- /dev/null +++ b/chromium/components/web_modal/DEPS @@ -0,0 +1,6 @@ +include_rules = [ + "+content/public/browser", + "+content/public/test", + "+net/base", + "+ui/gfx", +] diff --git a/chromium/components/web_modal/OWNERS b/chromium/components/web_modal/OWNERS new file mode 100644 index 00000000000..12a9b0975ce --- /dev/null +++ b/chromium/components/web_modal/OWNERS @@ -0,0 +1 @@ +wittman@chromium.org diff --git a/chromium/components/web_modal/modal_dialog_host.cc b/chromium/components/web_modal/modal_dialog_host.cc new file mode 100644 index 00000000000..61ddbc29a74 --- /dev/null +++ b/chromium/components/web_modal/modal_dialog_host.cc @@ -0,0 +1,15 @@ +// Copyright 2013 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 "components/web_modal/modal_dialog_host.h" + +namespace web_modal { + +ModalDialogHostObserver::~ModalDialogHostObserver() { +} + +ModalDialogHost::~ModalDialogHost() { +} + +} // namespace web_modal diff --git a/chromium/components/web_modal/modal_dialog_host.h b/chromium/components/web_modal/modal_dialog_host.h new file mode 100644 index 00000000000..c7842b3da32 --- /dev/null +++ b/chromium/components/web_modal/modal_dialog_host.h @@ -0,0 +1,44 @@ +// Copyright 2013 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 COMPONENTS_WEB_MODAL_MODAL_DIALOG_HOST_H_ +#define COMPONENTS_WEB_MODAL_MODAL_DIALOG_HOST_H_ + +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Point; +class Size; +} // namespace gfx + +namespace web_modal { + +// Observer to be implemented to update modal dialogs when the host indicates +// their position needs to be changed. +class ModalDialogHostObserver { + public: + virtual ~ModalDialogHostObserver(); + + virtual void OnPositionRequiresUpdate() = 0; + virtual void OnHostDestroying() = 0; +}; + +// Interface for supporting positioning of modal dialogs over a window/widget. +class ModalDialogHost { + public: + virtual ~ModalDialogHost(); + + // Returns the view against which the dialog is positioned and parented. + virtual gfx::NativeView GetHostView() const = 0; + // Gets the position for the dialog in coordinates relative to the host view. + virtual gfx::Point GetDialogPosition(const gfx::Size& size) = 0; + + // Add/remove observer. + virtual void AddObserver(ModalDialogHostObserver* observer) = 0; + virtual void RemoveObserver(ModalDialogHostObserver* observer) = 0; +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_MODAL_DIALOG_HOST_H_ diff --git a/chromium/components/web_modal/single_web_contents_dialog_manager.h b/chromium/components/web_modal/single_web_contents_dialog_manager.h new file mode 100644 index 00000000000..7d85368409d --- /dev/null +++ b/chromium/components/web_modal/single_web_contents_dialog_manager.h @@ -0,0 +1,80 @@ +// Copyright 2014 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 COMPONENTS_WEB_MODAL_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_H_ +#define COMPONENTS_WEB_MODAL_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_H_ + +#include "base/macros.h" +#include "ui/gfx/native_widget_types.h" + +namespace content { +class WebContents; +} // namespace content + +namespace web_modal { + +class WebContentsModalDialogHost; + +// Interface from SingleWebContentsDialogManager to +// WebContentsModalDialogManager. +class SingleWebContentsDialogManagerDelegate { + public: + SingleWebContentsDialogManagerDelegate() {} + virtual ~SingleWebContentsDialogManagerDelegate() {} + + virtual content::WebContents* GetWebContents() const = 0; + + // Notify the delegate that the dialog is closing. The native + // manager will be deleted before the end of this call. + virtual void WillClose(gfx::NativeWindow dialog) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SingleWebContentsDialogManagerDelegate); +}; + +// Provides an interface for platform-specific UI implementation for the web +// contents modal dialog. Each object will manage a single dialog window +// during its lifecycle. +// +// Implementation classes should accept a dialog window at construction time +// and register to be notified when the dialog is closing, so that it can +// notify its delegate (WillClose method). +class SingleWebContentsDialogManager { + public: + virtual ~SingleWebContentsDialogManager() {} + + // Makes the web contents modal dialog visible. Only one web contents modal + // dialog is shown at a time per tab. + virtual void Show() = 0; + + // Hides the web contents modal dialog without closing it. + virtual void Hide() = 0; + + // Closes the web contents modal dialog. + // If this method causes a WillClose() call to the delegate, the manager + // will be deleted at the close of that invocation. + virtual void Close() = 0; + + // Sets focus on the web contents modal dialog. + virtual void Focus() = 0; + + // Runs a pulse animation for the web contents modal dialog. + virtual void Pulse() = 0; + + // Called when the host view for the dialog has changed. + virtual void HostChanged(WebContentsModalDialogHost* new_host) = 0; + + // Return the dialog under management by this object. + virtual gfx::NativeWindow dialog() = 0; + + protected: + SingleWebContentsDialogManager() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleWebContentsDialogManager); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_H_ diff --git a/chromium/components/web_modal/test_web_contents_modal_dialog_host.cc b/chromium/components/web_modal/test_web_contents_modal_dialog_host.cc new file mode 100644 index 00000000000..28a5d81f1e4 --- /dev/null +++ b/chromium/components/web_modal/test_web_contents_modal_dialog_host.cc @@ -0,0 +1,36 @@ +// Copyright 2013 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 "components/web_modal/test_web_contents_modal_dialog_host.h" + +#include "ui/gfx/geometry/point.h" + +namespace web_modal { + +TestWebContentsModalDialogHost::TestWebContentsModalDialogHost( + gfx::NativeView host_view) + : host_view_(host_view) {} + +TestWebContentsModalDialogHost::~TestWebContentsModalDialogHost() {} + +gfx::Size TestWebContentsModalDialogHost::GetMaximumDialogSize() { + return max_dialog_size_; +} + +gfx::NativeView TestWebContentsModalDialogHost::GetHostView() const { + return host_view_; +} + +gfx::Point TestWebContentsModalDialogHost::GetDialogPosition( + const gfx::Size& size) { + return gfx::Point(); +} + +void TestWebContentsModalDialogHost::AddObserver( + ModalDialogHostObserver* observer) {} + +void TestWebContentsModalDialogHost::RemoveObserver( + ModalDialogHostObserver* observer) {} + +} // namespace web_modal diff --git a/chromium/components/web_modal/test_web_contents_modal_dialog_host.h b/chromium/components/web_modal/test_web_contents_modal_dialog_host.h new file mode 100644 index 00000000000..8348f68dec1 --- /dev/null +++ b/chromium/components/web_modal/test_web_contents_modal_dialog_host.h @@ -0,0 +1,42 @@ +// Copyright 2013 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 COMPONENTS_WEB_MODAL_TEST_WEB_CONTENTS_MODAL_DIALOG_HOST_H_ +#define COMPONENTS_WEB_MODAL_TEST_WEB_CONTENTS_MODAL_DIALOG_HOST_H_ + +#include "components/web_modal/web_contents_modal_dialog_host.h" + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/native_widget_types.h" + +namespace web_modal { + +class TestWebContentsModalDialogHost : public WebContentsModalDialogHost { + public: + explicit TestWebContentsModalDialogHost(gfx::NativeView host_view); + ~TestWebContentsModalDialogHost() override; + + // WebContentsModalDialogHost: + gfx::Size GetMaximumDialogSize() override; + gfx::NativeView GetHostView() const override; + gfx::Point GetDialogPosition(const gfx::Size& size) override; + void AddObserver(ModalDialogHostObserver* observer) override; + void RemoveObserver(ModalDialogHostObserver* observer) override; + + void set_max_dialog_size(const gfx::Size& max_dialog_size) { + max_dialog_size_ = max_dialog_size; + } + + private: + gfx::NativeView host_view_; + gfx::Size max_dialog_size_; + + DISALLOW_COPY_AND_ASSIGN(TestWebContentsModalDialogHost); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_TEST_WEB_CONTENTS_MODAL_DIALOG_HOST_H_ diff --git a/chromium/components/web_modal/test_web_contents_modal_dialog_manager_delegate.cc b/chromium/components/web_modal/test_web_contents_modal_dialog_manager_delegate.cc new file mode 100644 index 00000000000..53c94d2caf9 --- /dev/null +++ b/chromium/components/web_modal/test_web_contents_modal_dialog_manager_delegate.cc @@ -0,0 +1,31 @@ +// Copyright 2013 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 "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h" + +namespace web_modal { + +TestWebContentsModalDialogManagerDelegate:: + TestWebContentsModalDialogManagerDelegate() + : web_contents_visible_(true), + web_contents_blocked_(false), + web_contents_modal_dialog_host_(NULL) {} + +void TestWebContentsModalDialogManagerDelegate::SetWebContentsBlocked( + content::WebContents* web_contents, + bool blocked) { + web_contents_blocked_ = blocked; +} + +WebContentsModalDialogHost* TestWebContentsModalDialogManagerDelegate:: + GetWebContentsModalDialogHost() { + return web_contents_modal_dialog_host_; +} + +bool TestWebContentsModalDialogManagerDelegate::IsWebContentsVisible( + content::WebContents* web_contents) { + return web_contents_visible_; +} + +} // namespace web_modal diff --git a/chromium/components/web_modal/test_web_contents_modal_dialog_manager_delegate.h b/chromium/components/web_modal/test_web_contents_modal_dialog_manager_delegate.h new file mode 100644 index 00000000000..8221424ae13 --- /dev/null +++ b/chromium/components/web_modal/test_web_contents_modal_dialog_manager_delegate.h @@ -0,0 +1,48 @@ +// Copyright 2013 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 COMPONENTS_WEB_MODAL_TEST_WEB_CONTENTS_MODAL_DIALOG_MANAGER_DELEGATE_H_ +#define COMPONENTS_WEB_MODAL_TEST_WEB_CONTENTS_MODAL_DIALOG_MANAGER_DELEGATE_H_ + +#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" + +#include "base/compiler_specific.h" +#include "base/macros.h" + +namespace web_modal { + +class TestWebContentsModalDialogManagerDelegate + : public WebContentsModalDialogManagerDelegate { + public: + TestWebContentsModalDialogManagerDelegate(); + + // WebContentsModalDialogManagerDelegate overrides: + void SetWebContentsBlocked(content::WebContents* web_contents, + bool blocked) override; + + WebContentsModalDialogHost* GetWebContentsModalDialogHost() override; + + bool IsWebContentsVisible(content::WebContents* web_contents) override; + + void set_web_contents_visible(bool visible) { + web_contents_visible_ = visible; + } + + void set_web_contents_modal_dialog_host(WebContentsModalDialogHost* host) { + web_contents_modal_dialog_host_ = host; + } + + bool web_contents_blocked() const { return web_contents_blocked_; } + + private: + bool web_contents_visible_; + bool web_contents_blocked_; + WebContentsModalDialogHost* web_contents_modal_dialog_host_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(TestWebContentsModalDialogManagerDelegate); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_TEST_WEB_CONTENTS_MODAL_DIALOG_MANAGER_DELEGATE_H_ diff --git a/chromium/components/web_modal/web_contents_modal_dialog_host.cc b/chromium/components/web_modal/web_contents_modal_dialog_host.cc new file mode 100644 index 00000000000..89913876eb6 --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_host.cc @@ -0,0 +1,12 @@ +// Copyright (c) 2013 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 "components/web_modal/web_contents_modal_dialog_host.h" + +namespace web_modal { + +WebContentsModalDialogHost::~WebContentsModalDialogHost() { +} + +} // namespace web_modal diff --git a/chromium/components/web_modal/web_contents_modal_dialog_host.h b/chromium/components/web_modal/web_contents_modal_dialog_host.h new file mode 100644 index 00000000000..3ae7c1f58df --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_host.h @@ -0,0 +1,30 @@ +// Copyright (c) 2013 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 COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_HOST_H_ +#define COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_HOST_H_ + +#include "components/web_modal/modal_dialog_host.h" + +namespace gfx { +class Size; +} + +namespace web_modal { + +// Unlike browser modal dialogs, web contents modal dialogs should not be able +// to draw outside the browser window. WebContentsModalDialogHost adds a +// GetMaximumDialogSize method in order for positioning code to be able to take +// this into account. +class WebContentsModalDialogHost : public ModalDialogHost { + public: + ~WebContentsModalDialogHost() override; + + // Returns the maximum dimensions a dialog can have. + virtual gfx::Size GetMaximumDialogSize() = 0; +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_HOST_H_ diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager.cc b/chromium/components/web_modal/web_contents_modal_dialog_manager.cc new file mode 100644 index 00000000000..e940b077a00 --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_manager.cc @@ -0,0 +1,186 @@ +// 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 "components/web_modal/web_contents_modal_dialog_manager.h" + +#include <utility> + +#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/browser/web_contents.h" +#include "net/base/registry_controlled_domains/registry_controlled_domain.h" + +using content::WebContents; + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager); + +namespace web_modal { + +WebContentsModalDialogManager::~WebContentsModalDialogManager() { + DCHECK(child_dialogs_.empty()); +} + +void WebContentsModalDialogManager::SetDelegate( + WebContentsModalDialogManagerDelegate* d) { + delegate_ = d; + + for (WebContentsModalDialogList::iterator it = child_dialogs_.begin(); + it != child_dialogs_.end(); it++) { + // Delegate can be NULL on Views/Win32 during tab drag. + (*it)->manager->HostChanged(d ? d->GetWebContentsModalDialogHost() : NULL); + } +} + +void WebContentsModalDialogManager::ShowModalDialog(gfx::NativeWindow dialog) { + scoped_ptr<SingleWebContentsDialogManager> mgr( + CreateNativeWebModalManager(dialog, this)); + ShowDialogWithManager(dialog, std::move(mgr)); +} + +// TODO(gbillock): Maybe "ShowBubbleWithManager"? +void WebContentsModalDialogManager::ShowDialogWithManager( + gfx::NativeWindow dialog, + scoped_ptr<SingleWebContentsDialogManager> manager) { + if (delegate_) + manager->HostChanged(delegate_->GetWebContentsModalDialogHost()); + child_dialogs_.push_back(new DialogState(dialog, std::move(manager))); + + if (child_dialogs_.size() == 1) { + BlockWebContentsInteraction(true); + if (delegate_ && delegate_->IsWebContentsVisible(web_contents())) + child_dialogs_.back()->manager->Show(); + } +} + +bool WebContentsModalDialogManager::IsDialogActive() const { + return !child_dialogs_.empty(); +} + +void WebContentsModalDialogManager::FocusTopmostDialog() const { + DCHECK(!child_dialogs_.empty()); + child_dialogs_.front()->manager->Focus(); +} + +content::WebContents* WebContentsModalDialogManager::GetWebContents() const { + return web_contents(); +} + +void WebContentsModalDialogManager::WillClose(gfx::NativeWindow dialog) { + WebContentsModalDialogList::iterator dlg = FindDialogState(dialog); + + // The Views tab contents modal dialog calls WillClose twice. Ignore the + // second invocation. + if (dlg == child_dialogs_.end()) + return; + + bool removed_topmost_dialog = dlg == child_dialogs_.begin(); + scoped_ptr<DialogState> deleter(*dlg); + child_dialogs_.erase(dlg); + if (!child_dialogs_.empty() && removed_topmost_dialog && + !closing_all_dialogs_) { + child_dialogs_.front()->manager->Show(); + } + + BlockWebContentsInteraction(!child_dialogs_.empty()); +} + +WebContentsModalDialogManager::WebContentsModalDialogManager( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + delegate_(NULL), + closing_all_dialogs_(false) { +} + +WebContentsModalDialogManager::DialogState::DialogState( + gfx::NativeWindow dialog, + scoped_ptr<SingleWebContentsDialogManager> mgr) + : dialog(dialog), + manager(mgr.release()) { +} + +WebContentsModalDialogManager::DialogState::~DialogState() {} + +WebContentsModalDialogManager::WebContentsModalDialogList::iterator +WebContentsModalDialogManager::FindDialogState(gfx::NativeWindow dialog) { + WebContentsModalDialogList::iterator i; + for (i = child_dialogs_.begin(); i != child_dialogs_.end(); ++i) { + if ((*i)->dialog == dialog) + break; + } + + return i; +} + +// TODO(gbillock): Move this to Views impl within Show()? It would +// call WebContents* contents = native_delegate_->GetWebContents(); and +// then set the block state. Advantage: could restrict some of the +// WCMDM delegate methods, then, and pass them behind the scenes. +void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) { + WebContents* contents = web_contents(); + if (!contents) { + // The WebContents has already disconnected. + return; + } + + // RenderViewHost may be NULL during shutdown. + content::RenderViewHost* host = contents->GetRenderViewHost(); + if (host) + host->GetWidget()->SetIgnoreInputEvents(blocked); + if (delegate_) + delegate_->SetWebContentsBlocked(contents, blocked); +} + +void WebContentsModalDialogManager::CloseAllDialogs() { + closing_all_dialogs_ = true; + + // Clear out any dialogs since we are leaving this page entirely. + while (!child_dialogs_.empty()) { + child_dialogs_.front()->manager->Close(); + } + + closing_all_dialogs_ = false; +} + +void WebContentsModalDialogManager::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + // Close constrained windows if necessary. + if (!net::registry_controlled_domains::SameDomainOrHost( + details.previous_url, details.entry->GetURL(), + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) + CloseAllDialogs(); +} + +void WebContentsModalDialogManager::DidGetIgnoredUIEvent() { + if (!child_dialogs_.empty()) { + child_dialogs_.front()->manager->Focus(); + } +} + +void WebContentsModalDialogManager::WasShown() { + if (!child_dialogs_.empty()) + child_dialogs_.front()->manager->Show(); +} + +void WebContentsModalDialogManager::WasHidden() { + if (!child_dialogs_.empty()) + child_dialogs_.front()->manager->Hide(); +} + +void WebContentsModalDialogManager::WebContentsDestroyed() { + // First cleanly close all child dialogs. + // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked + // some of these to close. CloseAllDialogs is async, so it might get called + // twice before it runs. + CloseAllDialogs(); +} + +void WebContentsModalDialogManager::DidAttachInterstitialPage() { + CloseAllDialogs(); +} + +} // namespace web_modal diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager.h b/chromium/components/web_modal/web_contents_modal_dialog_manager.h new file mode 100644 index 00000000000..f5d501116b2 --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_manager.h @@ -0,0 +1,125 @@ +// Copyright 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 COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_ +#define COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_ + +#include <deque> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "components/web_modal/single_web_contents_dialog_manager.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" +#include "ui/gfx/native_widget_types.h" + +namespace web_modal { + +class WebContentsModalDialogManagerDelegate; + +// Per-WebContents class to manage WebContents-modal dialogs. +class WebContentsModalDialogManager + : public SingleWebContentsDialogManagerDelegate, + public content::WebContentsObserver, + public content::WebContentsUserData<WebContentsModalDialogManager> { + public: + ~WebContentsModalDialogManager() override; + + WebContentsModalDialogManagerDelegate* delegate() const { return delegate_; } + void SetDelegate(WebContentsModalDialogManagerDelegate* d); + + static SingleWebContentsDialogManager* CreateNativeWebModalManager( + gfx::NativeWindow dialog, + SingleWebContentsDialogManagerDelegate* native_delegate); + + // Shows the dialog as a web contents modal dialog. The dialog will notify via + // WillClose() when it is being destroyed. + void ShowModalDialog(gfx::NativeWindow dialog); + + // Allow clients to supply their own native dialog manager. Suitable for + // bubble clients. + void ShowDialogWithManager( + gfx::NativeWindow dialog, + scoped_ptr<SingleWebContentsDialogManager> manager); + + // Returns true if any dialogs are active and not closed. + bool IsDialogActive() const; + + // Focus the topmost modal dialog. IsDialogActive() must be true when calling + // this function. + void FocusTopmostDialog() const; + + // SingleWebContentsDialogManagerDelegate: + content::WebContents* GetWebContents() const override; + void WillClose(gfx::NativeWindow dialog) override; + + // For testing. + class TestApi { + public: + explicit TestApi(WebContentsModalDialogManager* manager) + : manager_(manager) {} + + void CloseAllDialogs() { manager_->CloseAllDialogs(); } + void DidAttachInterstitialPage() { manager_->DidAttachInterstitialPage(); } + void WebContentsWasShown() { manager_->WasShown(); } + void WebContentsWasHidden() { manager_->WasHidden(); } + + private: + WebContentsModalDialogManager* manager_; + + DISALLOW_COPY_AND_ASSIGN(TestApi); + }; + + private: + explicit WebContentsModalDialogManager(content::WebContents* web_contents); + friend class content::WebContentsUserData<WebContentsModalDialogManager>; + + struct DialogState { + DialogState(gfx::NativeWindow dialog, + scoped_ptr<SingleWebContentsDialogManager> manager); + ~DialogState(); + + gfx::NativeWindow dialog; + scoped_ptr<SingleWebContentsDialogManager> manager; + }; + + typedef std::deque<DialogState*> WebContentsModalDialogList; + + // Utility function to get the dialog state for a dialog. + WebContentsModalDialogList::iterator FindDialogState( + gfx::NativeWindow dialog); + + // Blocks/unblocks interaction with renderer process. + void BlockWebContentsInteraction(bool blocked); + + bool IsWebContentsVisible() const; + + // Closes all WebContentsModalDialogs. + void CloseAllDialogs(); + + // Overridden from content::WebContentsObserver: + void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + void DidGetIgnoredUIEvent() override; + void WasShown() override; + void WasHidden() override; + void WebContentsDestroyed() override; + void DidAttachInterstitialPage() override; + + // Delegate for notifying our owner about stuff. Not owned by us. + WebContentsModalDialogManagerDelegate* delegate_; + + // All active dialogs. + WebContentsModalDialogList child_dialogs_; + + // True while closing the dialogs on WebContents close. + bool closing_all_dialogs_; + + DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManager); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_ diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager_delegate.cc b/chromium/components/web_modal/web_contents_modal_dialog_manager_delegate.cc new file mode 100644 index 00000000000..25a777cf4f5 --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_manager_delegate.cc @@ -0,0 +1,28 @@ +// 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 "components/web_modal/web_contents_modal_dialog_manager_delegate.h" + +#include <string.h> + +namespace web_modal { + +void WebContentsModalDialogManagerDelegate::SetWebContentsBlocked( + content::WebContents* web_contents, bool blocked) { +} + +WebContentsModalDialogHost* + WebContentsModalDialogManagerDelegate::GetWebContentsModalDialogHost() { + return NULL; +} + +bool WebContentsModalDialogManagerDelegate::IsWebContentsVisible( + content::WebContents* web_contents) { + return true; +} + +WebContentsModalDialogManagerDelegate::~WebContentsModalDialogManagerDelegate( +) {} + +} // namespace web_modal diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager_delegate.h b/chromium/components/web_modal/web_contents_modal_dialog_manager_delegate.h new file mode 100644 index 00000000000..76f74354de5 --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_manager_delegate.h @@ -0,0 +1,42 @@ +// 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 COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_DELEGATE_H_ +#define COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_DELEGATE_H_ + +namespace content { +class WebContents; +} + +namespace gfx { +class Point; +} + +namespace web_modal { + +class WebContentsModalDialogHost; + +class WebContentsModalDialogManagerDelegate { + public: + // Changes the blocked state of |web_contents|. WebContentses are considered + // blocked while displaying a web contents modal dialog. During that time + // renderer host will ignore any UI interaction within WebContents outside of + // the currently displaying dialog. + virtual void SetWebContentsBlocked(content::WebContents* web_contents, + bool blocked); + + // Returns the WebContentsModalDialogHost for use in positioning web contents + // modal dialogs within the browser window. + virtual WebContentsModalDialogHost* GetWebContentsModalDialogHost(); + + // Returns whether the WebContents is currently visible or not. + virtual bool IsWebContentsVisible(content::WebContents* web_contents); + + protected: + virtual ~WebContentsModalDialogManagerDelegate(); +}; + +} // namespace web_modal + +#endif // COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_DELEGATE_H_ diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc b/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc new file mode 100644 index 00000000000..0cb10999e11 --- /dev/null +++ b/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc @@ -0,0 +1,363 @@ +// 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 "components/web_modal/web_contents_modal_dialog_manager.h" + +#include <map> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "components/web_modal/single_web_contents_dialog_manager.h" +#include "components/web_modal/test_web_contents_modal_dialog_manager_delegate.h" +#include "content/public/test/test_renderer_host.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace web_modal { + +// Tracks persistent state changes of the native WC-modal dialog manager. +class NativeManagerTracker { + public: + enum DialogState { + UNKNOWN, + NOT_SHOWN, + SHOWN, + HIDDEN, + CLOSED + }; + + NativeManagerTracker() : state_(UNKNOWN), was_shown_(false) {} + + void SetState(DialogState state) { + state_ = state; + if (state_ == SHOWN) + was_shown_ = true; + } + + DialogState state_; + bool was_shown_; +}; + +NativeManagerTracker unused_tracker; + +class TestNativeWebContentsModalDialogManager + : public SingleWebContentsDialogManager { + public: + TestNativeWebContentsModalDialogManager( + gfx::NativeWindow dialog, + SingleWebContentsDialogManagerDelegate* delegate, + NativeManagerTracker* tracker) + : delegate_(delegate), + dialog_(dialog), + tracker_(tracker) { + if (tracker_) + tracker_->SetState(NativeManagerTracker::NOT_SHOWN); + } + + void Show() override { + if (tracker_) + tracker_->SetState(NativeManagerTracker::SHOWN); + } + void Hide() override { + if (tracker_) + tracker_->SetState(NativeManagerTracker::HIDDEN); + } + void Close() override { + if (tracker_) + tracker_->SetState(NativeManagerTracker::CLOSED); + delegate_->WillClose(dialog_); + } + void Focus() override {} + void Pulse() override {} + void HostChanged(WebContentsModalDialogHost* new_host) override {} + gfx::NativeWindow dialog() override { return dialog_; } + + void StopTracking() { + tracker_ = NULL; + } + + private: + SingleWebContentsDialogManagerDelegate* delegate_; + gfx::NativeWindow dialog_; + NativeManagerTracker* tracker_; + + DISALLOW_COPY_AND_ASSIGN(TestNativeWebContentsModalDialogManager); +}; + +class WebContentsModalDialogManagerTest + : public content::RenderViewHostTestHarness { + public: + WebContentsModalDialogManagerTest() + : next_dialog_id(1), + manager(NULL) { + } + + void SetUp() override { + content::RenderViewHostTestHarness::SetUp(); + + delegate.reset(new TestWebContentsModalDialogManagerDelegate); + WebContentsModalDialogManager::CreateForWebContents(web_contents()); + manager = WebContentsModalDialogManager::FromWebContents(web_contents()); + manager->SetDelegate(delegate.get()); + test_api.reset(new WebContentsModalDialogManager::TestApi(manager)); + } + + void TearDown() override { + test_api.reset(); + content::RenderViewHostTestHarness::TearDown(); + } + + protected: + gfx::NativeWindow MakeFakeDialog() { + // WebContentsModalDialogManager treats the dialog window as an opaque + // type, so creating fake dialog windows using reinterpret_cast is valid. + return reinterpret_cast<gfx::NativeWindow>(next_dialog_id++); + } + + int next_dialog_id; + scoped_ptr<TestWebContentsModalDialogManagerDelegate> delegate; + WebContentsModalDialogManager* manager; + scoped_ptr<WebContentsModalDialogManager::TestApi> test_api; + + DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerTest); +}; + +SingleWebContentsDialogManager* +WebContentsModalDialogManager::CreateNativeWebModalManager( + gfx::NativeWindow dialog, + SingleWebContentsDialogManagerDelegate* native_delegate) { + NOTREACHED(); + return new TestNativeWebContentsModalDialogManager( + dialog, + native_delegate, + &unused_tracker); +} + +// Test that the dialog is shown immediately when the delegate indicates the web +// contents is visible. +TEST_F(WebContentsModalDialogManagerTest, WebContentsVisible) { + // Dialog should be shown while WebContents is visible. + const gfx::NativeWindow dialog = MakeFakeDialog(); + + NativeManagerTracker tracker; + TestNativeWebContentsModalDialogManager* native_manager = + new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker); + manager->ShowDialogWithManager( + dialog, scoped_ptr<SingleWebContentsDialogManager>(native_manager)); + + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_); + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_TRUE(tracker.was_shown_); + + native_manager->StopTracking(); +} + +// Test that the dialog is not shown immediately when the delegate indicates the +// web contents is not visible. +TEST_F(WebContentsModalDialogManagerTest, WebContentsNotVisible) { + // Dialog should not be shown while WebContents is not visible. + delegate->set_web_contents_visible(false); + + const gfx::NativeWindow dialog = MakeFakeDialog(); + + NativeManagerTracker tracker; + TestNativeWebContentsModalDialogManager* native_manager = + new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker); + manager->ShowDialogWithManager( + dialog, scoped_ptr<SingleWebContentsDialogManager>(native_manager)); + + EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker.state_); + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_FALSE(tracker.was_shown_); + + native_manager->StopTracking(); +} + +// Test that only the first of multiple dialogs is shown. +TEST_F(WebContentsModalDialogManagerTest, ShowDialogs) { + const gfx::NativeWindow dialog1 = MakeFakeDialog(); + const gfx::NativeWindow dialog2 = MakeFakeDialog(); + const gfx::NativeWindow dialog3 = MakeFakeDialog(); + + NativeManagerTracker tracker1; + NativeManagerTracker tracker2; + NativeManagerTracker tracker3; + TestNativeWebContentsModalDialogManager* native_manager1 = + new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1); + TestNativeWebContentsModalDialogManager* native_manager2 = + new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2); + TestNativeWebContentsModalDialogManager* native_manager3 = + new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3); + manager->ShowDialogWithManager( + dialog1, scoped_ptr<SingleWebContentsDialogManager>(native_manager1)); + manager->ShowDialogWithManager( + dialog2, scoped_ptr<SingleWebContentsDialogManager>(native_manager2)); + manager->ShowDialogWithManager( + dialog3, scoped_ptr<SingleWebContentsDialogManager>(native_manager3)); + + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker1.state_); + EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker2.state_); + EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_); + + native_manager1->StopTracking(); + native_manager2->StopTracking(); + native_manager3->StopTracking(); +} + +// Test that the dialog is shown/hidden when the WebContents is shown/hidden. +TEST_F(WebContentsModalDialogManagerTest, VisibilityObservation) { + const gfx::NativeWindow dialog = MakeFakeDialog(); + + NativeManagerTracker tracker; + TestNativeWebContentsModalDialogManager* native_manager = + new TestNativeWebContentsModalDialogManager(dialog, manager, &tracker); + manager->ShowDialogWithManager( + dialog, scoped_ptr<SingleWebContentsDialogManager>(native_manager)); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_); + + test_api->WebContentsWasHidden(); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::HIDDEN, tracker.state_); + + test_api->WebContentsWasShown(); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker.state_); + + native_manager->StopTracking(); +} + +// Test that attaching an interstitial page closes all dialogs. +TEST_F(WebContentsModalDialogManagerTest, InterstitialPage) { + const gfx::NativeWindow dialog1 = MakeFakeDialog(); + const gfx::NativeWindow dialog2 = MakeFakeDialog(); + + NativeManagerTracker tracker1; + NativeManagerTracker tracker2; + TestNativeWebContentsModalDialogManager* native_manager1 = + new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1); + TestNativeWebContentsModalDialogManager* native_manager2 = + new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2); + manager->ShowDialogWithManager( + dialog1, scoped_ptr<SingleWebContentsDialogManager>(native_manager1)); + manager->ShowDialogWithManager( + dialog2, scoped_ptr<SingleWebContentsDialogManager>(native_manager2)); + + test_api->DidAttachInterstitialPage(); + + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_); + + EXPECT_TRUE(tracker1.was_shown_); + EXPECT_FALSE(tracker2.was_shown_); +} + + +// Test that the first dialog is always shown, regardless of the order in which +// dialogs are closed. +TEST_F(WebContentsModalDialogManagerTest, CloseDialogs) { + // The front dialog is always shown regardless of dialog close order. + const gfx::NativeWindow dialog1 = MakeFakeDialog(); + const gfx::NativeWindow dialog2 = MakeFakeDialog(); + const gfx::NativeWindow dialog3 = MakeFakeDialog(); + const gfx::NativeWindow dialog4 = MakeFakeDialog(); + + NativeManagerTracker tracker1; + NativeManagerTracker tracker2; + NativeManagerTracker tracker3; + NativeManagerTracker tracker4; + TestNativeWebContentsModalDialogManager* native_manager1 = + new TestNativeWebContentsModalDialogManager(dialog1, manager, &tracker1); + TestNativeWebContentsModalDialogManager* native_manager2 = + new TestNativeWebContentsModalDialogManager(dialog2, manager, &tracker2); + TestNativeWebContentsModalDialogManager* native_manager3 = + new TestNativeWebContentsModalDialogManager(dialog3, manager, &tracker3); + TestNativeWebContentsModalDialogManager* native_manager4 = + new TestNativeWebContentsModalDialogManager(dialog4, manager, &tracker4); + manager->ShowDialogWithManager( + dialog1, scoped_ptr<SingleWebContentsDialogManager>(native_manager1)); + manager->ShowDialogWithManager( + dialog2, scoped_ptr<SingleWebContentsDialogManager>(native_manager2)); + manager->ShowDialogWithManager( + dialog3, scoped_ptr<SingleWebContentsDialogManager>(native_manager3)); + manager->ShowDialogWithManager( + dialog4, scoped_ptr<SingleWebContentsDialogManager>(native_manager4)); + + native_manager1->Close(); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_); + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_); + EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker3.state_); + EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_); + + native_manager3->Close(); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_); + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker2.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_); + EXPECT_EQ(NativeManagerTracker::NOT_SHOWN, tracker4.state_); + EXPECT_FALSE(tracker3.was_shown_); + + native_manager2->Close(); + + EXPECT_TRUE(manager->IsDialogActive()); + EXPECT_TRUE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_); + EXPECT_EQ(NativeManagerTracker::SHOWN, tracker4.state_); + EXPECT_FALSE(tracker3.was_shown_); + + native_manager4->Close(); + + EXPECT_FALSE(manager->IsDialogActive()); + EXPECT_FALSE(delegate->web_contents_blocked()); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker1.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker2.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker3.state_); + EXPECT_EQ(NativeManagerTracker::CLOSED, tracker4.state_); + EXPECT_TRUE(tracker1.was_shown_); + EXPECT_TRUE(tracker2.was_shown_); + EXPECT_FALSE(tracker3.was_shown_); + EXPECT_TRUE(tracker4.was_shown_); +} + +// Test that CloseAllDialogs does what it says. +TEST_F(WebContentsModalDialogManagerTest, CloseAllDialogs) { + const int kWindowCount = 4; + NativeManagerTracker trackers[kWindowCount]; + TestNativeWebContentsModalDialogManager* native_managers[kWindowCount]; + for (int i = 0; i < kWindowCount; i++) { + const gfx::NativeWindow dialog = MakeFakeDialog(); + native_managers[i] = + new TestNativeWebContentsModalDialogManager( + dialog, manager, &(trackers[i])); + manager->ShowDialogWithManager( + dialog, scoped_ptr<SingleWebContentsDialogManager>(native_managers[i])); + } + + for (int i = 0; i < kWindowCount; i++) + EXPECT_NE(NativeManagerTracker::CLOSED, trackers[i].state_); + + test_api->CloseAllDialogs(); + + EXPECT_FALSE(delegate->web_contents_blocked()); + EXPECT_FALSE(manager->IsDialogActive()); + for (int i = 0; i < kWindowCount; i++) + EXPECT_EQ(NativeManagerTracker::CLOSED, trackers[i].state_); +} + +} // namespace web_modal |