Commit bdcf05d8 authored by apacible's avatar apacible Committed by Commit bot

Currently, constrained web dialogs cannot autoresize. This change gives an...

Currently, constrained web dialogs cannot autoresize. This change gives an option to pass in a minimum and maximum size, which enables the autoresizing functionality.

OSX has not yet been implemented.

BUG=217034

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

Cr-Commit-Position: refs/heads/master@{#308300}
parent 7521caae
......@@ -370,9 +370,9 @@ WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog(
// The dialog delegates are deleted when the dialog is closed.
ConstrainedWebDialogDelegate* web_dialog_delegate =
CreateConstrainedWebDialog(initiator->GetBrowserContext(),
new PrintPreviewDialogDelegate(initiator),
initiator);
ShowConstrainedWebDialog(initiator->GetBrowserContext(),
new PrintPreviewDialogDelegate(initiator),
initiator);
WebContents* preview_dialog = web_dialog_delegate->GetWebContents();
EnableInternalPDFPluginForContents(preview_dialog);
......
......@@ -76,6 +76,18 @@ class ConstrainedWebDialogDelegateViewMac :
return constrained_window_->GetNativeDialog();
}
WebContents* GetWebContents() override { return impl_->GetWebContents(); }
gfx::Size GetMinimumSize() const override {
NOTIMPLEMENTED();
return gfx::Size();
}
gfx::Size GetMaximumSize() const override {
NOTIMPLEMENTED();
return gfx::Size();
}
gfx::Size GetPreferredSize() const override {
NOTIMPLEMENTED();
return gfx::Size();
}
// ConstrainedWindowMacDelegate interface
void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override {
......@@ -115,7 +127,7 @@ ConstrainedWebDialogDelegateViewMac::ConstrainedWebDialogDelegateViewMac(
impl_->set_window(constrained_window_.get());
}
ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
ConstrainedWebDialogDelegate* ShowConstrainedWebDialog(
content::BrowserContext* browser_context,
WebDialogDelegate* delegate,
content::WebContents* web_contents) {
......
......@@ -9,10 +9,14 @@
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/web_modal/popup_manager.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
......@@ -20,15 +24,28 @@
namespace {
// WebContentsObserver that tracks the lifetime of the WebContents to avoid
// potential use after destruction.
class InitiatorWebContentsObserver
: public content::WebContentsObserver {
public:
explicit InitiatorWebContentsObserver(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
}
private:
DISALLOW_COPY_AND_ASSIGN(InitiatorWebContentsObserver);
};
class WebDialogWebContentsDelegateViews
: public ui::WebDialogWebContentsDelegate {
public:
WebDialogWebContentsDelegateViews(content::BrowserContext* browser_context,
content::WebContents* initiator,
InitiatorWebContentsObserver* observer,
views::WebView* web_view)
: ui::WebDialogWebContentsDelegate(browser_context,
new ChromeWebContentsHandler()),
initiator_(initiator),
initiator_observer_(observer),
web_view_(web_view) {
}
~WebDialogWebContentsDelegateViews() override {}
......@@ -45,15 +62,36 @@ class WebDialogWebContentsDelegateViews
// http://crbug.com/104586
// Disabled on Mac due to http://crbug.com/112173
#if !defined(OS_MACOSX)
auto delegate = initiator_->GetDelegate();
if (!initiator_observer_->web_contents())
return;
auto delegate = initiator_observer_->web_contents()->GetDelegate();
if (!delegate)
return;
delegate->HandleKeyboardEvent(initiator_, event);
delegate->HandleKeyboardEvent(initiator_observer_->web_contents(), event);
#endif
}
void ResizeDueToAutoResize(content::WebContents* source,
const gfx::Size& preferred_size) override {
if (source != web_view_->GetWebContents())
return;
if (!initiator_observer_->web_contents())
return;
// Sets WebView's preferred size based on auto-resized contents.
web_view_->SetPreferredSize(preferred_size);
constrained_window::UpdateWebContentsModalDialogPosition(
web_view_->GetWidget(),
web_modal::WebContentsModalDialogManager::FromWebContents(
initiator_observer_->web_contents())->delegate()->
GetWebContentsModalDialogHost());
}
private:
content::WebContents* initiator_;
InitiatorWebContentsObserver* const initiator_observer_;
views::WebView* web_view_;
DISALLOW_COPY_AND_ASSIGN(WebDialogWebContentsDelegateViews);
......@@ -64,10 +102,10 @@ class ConstrainedWebDialogDelegateViews
public:
ConstrainedWebDialogDelegateViews(content::BrowserContext* context,
ui::WebDialogDelegate* delegate,
content::WebContents* web_contents,
InitiatorWebContentsObserver* observer,
views::WebView* view)
: ConstrainedWebDialogDelegateBase(context, delegate,
new WebDialogWebContentsDelegateViews(context, web_contents, view)),
new WebDialogWebContentsDelegateViews(context, observer, view)),
view_(view) {}
~ConstrainedWebDialogDelegateViews() override {}
......@@ -107,10 +145,16 @@ class ConstrainedWebDialogDelegateViewViews
ConstrainedWebDialogDelegateViewViews(
content::BrowserContext* browser_context,
ui::WebDialogDelegate* delegate,
content::WebContents* web_contents)
content::WebContents* web_contents,
const gfx::Size& min_size,
const gfx::Size& max_size)
: views::WebView(browser_context),
initiator_observer_(web_contents),
impl_(new ConstrainedWebDialogDelegateViews(browser_context, delegate,
web_contents, this)) {
&initiator_observer_,
this)),
min_size_(min_size),
max_size_(max_size) {
SetWebContents(GetWebContents());
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
}
......@@ -168,30 +212,90 @@ class ConstrainedWebDialogDelegateViewViews
}
gfx::Size GetPreferredSize() const override {
gfx::Size size;
if (!impl_->closed_via_webui())
GetWebDialogDelegate()->GetDialogSize(&size);
if (!impl_->closed_via_webui()) {
// The size is set here if the dialog has been auto-resized in
// WebDialogWebContentsDelegateViews's ResizeDueToAutoResize.
size = WebView::GetPreferredSize();
if (size.IsEmpty()) {
// The size set here if the dialog has not been auto-resized or
// auto-resizable is not enabled.
GetWebDialogDelegate()->GetDialogSize(&size);
}
}
return size;
}
gfx::Size GetMinimumSize() const override {
// Return an empty size so that we can be made smaller.
return gfx::Size();
return min_size_;
}
gfx::Size GetMaximumSize() const override {
return !max_size_.IsEmpty() ? max_size_ : WebView::GetMaximumSize();
}
void RenderViewCreated(content::RenderViewHost* render_view_host) override {
if (!max_size_.IsEmpty())
EnableAutoResize();
}
void RenderViewHostChanged(content::RenderViewHost* old_host,
content::RenderViewHost* new_host) override {
if (!max_size_.IsEmpty())
EnableAutoResize();
}
void DocumentOnLoadCompletedInMainFrame() override {
if (!max_size_.IsEmpty()) {
EnableAutoResize();
if (initiator_observer_.web_contents()) {
web_modal::PopupManager* popup_manager =
web_modal::PopupManager::FromWebContents(
initiator_observer_.web_contents());
popup_manager->ShowModalDialog(GetWidget()->GetNativeView(),
initiator_observer_.web_contents());
}
}
}
private:
void EnableAutoResize() {
content::RenderViewHost* render_view_host =
GetWebContents()->GetRenderViewHost();
render_view_host->EnableAutoResize(min_size_, max_size_);
}
InitiatorWebContentsObserver initiator_observer_;
scoped_ptr<ConstrainedWebDialogDelegateViews> impl_;
// Minimum and maximum sizes to determine dialog bounds for auto-resizing.
const gfx::Size min_size_;
const gfx::Size max_size_;
DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewViews);
};
} // namespace
ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
ConstrainedWebDialogDelegate* ShowConstrainedWebDialog(
content::BrowserContext* browser_context,
ui::WebDialogDelegate* delegate,
content::WebContents* web_contents) {
ConstrainedWebDialogDelegateViewViews* dialog =
new ConstrainedWebDialogDelegateViewViews(
browser_context, delegate, web_contents);
browser_context, delegate, web_contents,
gfx::Size(), gfx::Size());
constrained_window::ShowWebModalDialogViews(dialog, web_contents);
return dialog;
}
ConstrainedWebDialogDelegate* ShowConstrainedWebDialogWithAutoResize(
content::BrowserContext* browser_context,
ui::WebDialogDelegate* delegate,
content::WebContents* web_contents,
const gfx::Size& min_size,
const gfx::Size& max_size) {
DCHECK(!min_size.IsEmpty());
DCHECK(!max_size.IsEmpty());
ConstrainedWebDialogDelegateViewViews* dialog =
new ConstrainedWebDialogDelegateViewViews(
browser_context, delegate, web_contents,
min_size, max_size);
constrained_window::CreateWebModalDialogViews(dialog, web_contents);
return dialog;
}
......@@ -228,8 +228,8 @@ void CertificateViewerDialog::Show(WebContents* web_contents,
gfx::NativeWindow parent) {
// TODO(bshe): UI tweaks needed for Aura HTML Dialog, such as adding padding
// on the title for Aura ConstrainedWebDialogUI.
dialog_ = CreateConstrainedWebDialog(web_contents->GetBrowserContext(), this,
web_contents);
dialog_ = ShowConstrainedWebDialog(web_contents->GetBrowserContext(), this,
web_contents);
}
NativeWebContentsModalDialog
......
......@@ -99,3 +99,18 @@ void ConstrainedWebDialogDelegateBase::HandleKeyboardEvent(
content::WebContents* source,
const NativeWebKeyboardEvent& event) {
}
gfx::Size ConstrainedWebDialogDelegateBase::GetMinimumSize() const {
NOTREACHED();
return gfx::Size();
}
gfx::Size ConstrainedWebDialogDelegateBase::GetMaximumSize() const {
NOTREACHED();
return gfx::Size();
}
gfx::Size ConstrainedWebDialogDelegateBase::GetPreferredSize() const {
NOTREACHED();
return gfx::Size();
}
......@@ -35,8 +35,11 @@ class ConstrainedWebDialogDelegateBase
ui::WebDialogDelegate* GetWebDialogDelegate() override;
void OnDialogCloseFromWebUI() override;
void ReleaseWebContentsOnDialogClose() override;
web_modal::NativeWebContentsModalDialog GetNativeDialog() override;
content::WebContents* GetWebContents() override;
web_modal::NativeWebContentsModalDialog GetNativeDialog() override;
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
gfx::Size GetPreferredSize() const override;
// WebDialogWebContentsDelegate interface.
void HandleKeyboardEvent(
......
......@@ -10,6 +10,10 @@
#include "content/public/browser/web_ui_controller.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
class Size;
}
namespace content {
class BrowserContext;
class RenderViewHost;
......@@ -41,6 +45,14 @@ class ConstrainedWebDialogDelegate {
// Returns the native type used to display the dialog.
virtual web_modal::NativeWebContentsModalDialog GetNativeDialog() = 0;
// Returns the minimum size for the dialog.
virtual gfx::Size GetMinimumSize() const = 0;
// Returns the maximum size for the dialog.
virtual gfx::Size GetMaximumSize() const = 0;
virtual gfx::Size GetPreferredSize() const = 0;
protected:
virtual ~ConstrainedWebDialogDelegate() {}
};
......@@ -75,16 +87,31 @@ class ConstrainedWebDialogUI : public content::WebUIController {
DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogUI);
};
// Create a constrained HTML dialog. The actual object that gets created
// is a ConstrainedWebDialogDelegate, which later triggers construction of a
// ConstrainedWebDialogUI object.
// Create and show a constrained HTML dialog. The actual object that gets
// created is a ConstrainedWebDialogDelegate, which later triggers construction
// of a ConstrainedWebDialogUI object.
// |browser_context| is used to construct the constrained HTML dialog's
// WebContents.
// |delegate| controls the behavior of the dialog.
// |overshadowed| is the tab being overshadowed by the dialog.
ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
ConstrainedWebDialogDelegate* ShowConstrainedWebDialog(
content::BrowserContext* browser_context,
ui::WebDialogDelegate* delegate,
content::WebContents* overshadowed);
// Create and show a constrained HTML dialog with auto-resize enabled. The
// dialog is shown automatically with a call to PopupManager->ShowModalDialog()
// after document load has completed to avoid UI jankiness.
// |browser_context| is used to construct the dialog's WebContents.
// |delegate| controls the behavior of the dialog.
// |overshadowed| is the tab being overshadowed by the dialog.
// |min_size| is the minimum size of the dialog.
// |max_size| is the maximum size of the dialog.
ConstrainedWebDialogDelegate* ShowConstrainedWebDialogWithAutoResize(
content::BrowserContext* browser_context,
ui::WebDialogDelegate* delegate,
content::WebContents* overshadowed,
const gfx::Size& min_size,
const gfx::Size& max_size);
#endif // CHROME_BROWSER_UI_WEBUI_CONSTRAINED_WEB_DIALOG_UI_H_
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/callback.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
......@@ -12,6 +14,8 @@
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "ui/web_dialogs/test/test_web_dialog_delegate.h"
using content::WebContents;
......@@ -20,6 +24,24 @@ using web_modal::WebContentsModalDialogManager;
namespace {
#if !defined(OS_MACOSX)
static const char kTestDataURL[] = "data:text/html,<!doctype html>"
"<body></body>"
"<style>"
"body { height: 150px; width: 150px; }"
"</style>";
bool IsEqualSizes(gfx::Size expected,
ConstrainedWebDialogDelegate* dialog_delegate) {
return expected == dialog_delegate->GetPreferredSize();
}
std::string GetChangeDimensionsScript(int dimension) {
return base::StringPrintf("window.document.body.style.width = %d + 'px';"
"window.document.body.style.height = %d + 'px';", dimension, dimension);
}
#endif
class ConstrainedWebDialogBrowserTestObserver
: public content::WebContentsObserver {
public:
......@@ -43,6 +65,25 @@ class ConstrainedWebDialogBrowserTest : public InProcessBrowserTest {
public:
ConstrainedWebDialogBrowserTest() {}
// Runs the current MessageLoop until |condition| is true or timeout.
bool RunLoopUntil(const base::Callback<bool()>& condition) {
const base::TimeTicks start_time = base::TimeTicks::Now();
while (!condition.Run()) {
const base::TimeTicks current_time = base::TimeTicks::Now();
if (current_time - start_time > base::TimeDelta::FromSeconds(5)) {
ADD_FAILURE() << "Condition not met within five seconds.";
return false;
}
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::MessageLoop::QuitClosure(),
base::TimeDelta::FromMilliseconds(20));
content::RunMessageLoop();
}
return true;
}
protected:
bool IsShowingWebContentsModalDialog(WebContents* web_contents) const {
WebContentsModalDialogManager* web_contents_modal_dialog_manager =
......@@ -61,7 +102,7 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest, BasicTest) {
ASSERT_TRUE(web_contents);
ConstrainedWebDialogDelegate* dialog_delegate =
CreateConstrainedWebDialog(browser()->profile(), delegate, web_contents);
ShowConstrainedWebDialog(browser()->profile(), delegate, web_contents);
ASSERT_TRUE(dialog_delegate);
EXPECT_TRUE(dialog_delegate->GetNativeDialog());
EXPECT_TRUE(IsShowingWebContentsModalDialog(web_contents));
......@@ -78,7 +119,7 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest,
ASSERT_TRUE(web_contents);
ConstrainedWebDialogDelegate* dialog_delegate =
CreateConstrainedWebDialog(browser()->profile(), delegate, web_contents);
ShowConstrainedWebDialog(browser()->profile(), delegate, web_contents);
ASSERT_TRUE(dialog_delegate);
scoped_ptr<WebContents> new_tab(dialog_delegate->GetWebContents());
ASSERT_TRUE(new_tab.get());
......@@ -93,3 +134,127 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest,
new_tab.reset();
EXPECT_TRUE(observer.contents_destroyed());
}
#if !defined(OS_MACOSX)
// Tests that dialog autoresizes based on web contents when autoresizing
// is enabled.
IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest,
ContentResizeInAutoResizingDialog) {
// During auto-resizing, dialogs size to (WebContents size) + 16.
const int dialog_border_space = 16;
// Expected dialog sizes after auto-resizing.
const int initial_size = 150 + dialog_border_space;
const int new_size = 175 + dialog_border_space;
// The delegate deletes itself.
WebDialogDelegate* delegate =
new ui::test::TestWebDialogDelegate(GURL(kTestDataURL));
WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
// Observes the next created WebContents.
content::TestNavigationObserver observer(NULL);
observer.StartWatchingNewWebContents();
gfx::Size min_size = gfx::Size(100, 100);
gfx::Size max_size = gfx::Size(200, 200);
gfx::Size initial_dialog_size;
delegate->GetDialogSize(&initial_dialog_size);
ConstrainedWebDialogDelegate* dialog_delegate =
ShowConstrainedWebDialogWithAutoResize(browser()->profile(), delegate,
web_contents, min_size,
max_size);
ASSERT_TRUE(dialog_delegate);
EXPECT_TRUE(dialog_delegate->GetNativeDialog());
ASSERT_FALSE(IsShowingWebContentsModalDialog(web_contents));
EXPECT_EQ(min_size, dialog_delegate->GetMinimumSize());
EXPECT_EQ(max_size, dialog_delegate->GetMaximumSize());
// Check for initial sizing. Dialog was created as a 400x400 dialog.
EXPECT_EQ(gfx::Size(), web_contents->GetPreferredSize());
ASSERT_EQ(initial_dialog_size, dialog_delegate->GetPreferredSize());
observer.Wait();
// Wait until the entire WebContents has loaded.
WaitForLoadStop(dialog_delegate->GetWebContents());
ASSERT_TRUE(IsShowingWebContentsModalDialog(web_contents));
// Resize to content's originally set dimensions.
ASSERT_TRUE(RunLoopUntil(base::Bind(
&IsEqualSizes,
gfx::Size(initial_size, initial_size),
dialog_delegate)));
// Resize to dimensions within expected bounds.
EXPECT_TRUE(ExecuteScript(dialog_delegate->GetWebContents(),
GetChangeDimensionsScript(175)));
ASSERT_TRUE(RunLoopUntil(base::Bind(
&IsEqualSizes,
gfx::Size(new_size, new_size),
dialog_delegate)));
// Resize to dimensions smaller than the minimum bounds.
EXPECT_TRUE(ExecuteScript(dialog_delegate->GetWebContents(),
GetChangeDimensionsScript(50)));
ASSERT_TRUE(RunLoopUntil(base::Bind(
&IsEqualSizes,
min_size,
dialog_delegate)));
// Resize to dimensions greater than the maximum bounds.
EXPECT_TRUE(ExecuteScript(dialog_delegate->GetWebContents(),
GetChangeDimensionsScript(250)));
ASSERT_TRUE(RunLoopUntil(base::Bind(
&IsEqualSizes,
max_size,
dialog_delegate)));
}
// Tests that dialog does not autoresize when autoresizing is not enabled.
IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest,
ContentResizeInNonAutoResizingDialog) {
// The delegate deletes itself.
WebDialogDelegate* delegate =
new ui::test::TestWebDialogDelegate(GURL(kTestDataURL));
WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
ConstrainedWebDialogDelegate* dialog_delegate =
ShowConstrainedWebDialog(browser()->profile(), delegate, web_contents);
ASSERT_TRUE(dialog_delegate);
EXPECT_TRUE(dialog_delegate->GetNativeDialog());
EXPECT_TRUE(IsShowingWebContentsModalDialog(web_contents));
// Wait until the entire WebContents has loaded.
WaitForLoadStop(dialog_delegate->GetWebContents());
gfx::Size initial_dialog_size;
delegate->GetDialogSize(&initial_dialog_size);
// Check for initial sizing. Dialog was created as a 400x400 dialog.
EXPECT_EQ(gfx::Size(), web_contents->GetPreferredSize());
ASSERT_EQ(initial_dialog_size, dialog_delegate->GetPreferredSize());
// Resize <body> to dimension smaller than dialog.
EXPECT_TRUE(ExecuteScript(dialog_delegate->GetWebContents(),
GetChangeDimensionsScript(100)));
ASSERT_TRUE(RunLoopUntil(base::Bind(
&IsEqualSizes,
initial_dialog_size,
dialog_delegate)));
// Resize <body> to dimension larger than dialog.
EXPECT_TRUE(ExecuteScript(dialog_delegate->GetWebContents(),
GetChangeDimensionsScript(500)));
ASSERT_TRUE(RunLoopUntil(base::Bind(
&IsEqualSizes,
initial_dialog_size,
dialog_delegate)));
}
#endif // !OS_MACOSX
......@@ -151,7 +151,7 @@ void ProfileSigninConfirmationDialog::Close() const {
void ProfileSigninConfirmationDialog::Show(bool prompt) {
prompt_for_new_profile_ = prompt;
dialog_delegate_ = CreateConstrainedWebDialog(profile_, this, web_contents_);
dialog_delegate_ = ShowConstrainedWebDialog(profile_, this, web_contents_);
}
ui::ModalType ProfileSigninConfirmationDialog::GetDialogModalType() const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment