1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/bind.h" 6 #include "base/bind_helpers.h" 7 #include "base/files/file_path.h" 8 #include "base/memory/singleton.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/tabs/tab_strip_model.h" 14 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h" 15 #include "chrome/common/url_constants.h" 16 #include "chrome/test/base/in_process_browser_test.h" 17 #include "chrome/test/base/ui_test_utils.h" 18 #include "content/public/browser/browser_context.h" 19 #include "content/public/browser/render_widget_host_view.h" 20 #include "content/public/browser/web_contents.h" 21 #include "testing/gmock/include/gmock/gmock.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 #include "ui/views/controls/webview/web_dialog_view.h" 24 #include "ui/views/widget/widget.h" 25 #include "ui/web_dialogs/test/test_web_dialog_delegate.h" 26 27 using content::BrowserContext; 28 using content::WebContents; 29 using testing::Eq; 30 using ui::WebDialogDelegate; 31 32 namespace { 33 34 // Initial size of WebDialog for SizeWindow test case. 35 const int kInitialWidth = 40; 36 const int kInitialHeight = 40; 37 38 class TestWebDialogView : public views::WebDialogView { 39 public: 40 TestWebDialogView(content::BrowserContext* context, 41 WebDialogDelegate* delegate) 42 : views::WebDialogView(context, delegate, new ChromeWebContentsHandler), 43 should_quit_on_size_change_(false) { 44 delegate->GetDialogSize(&last_size_); 45 } 46 47 void set_should_quit_on_size_change(bool should_quit) { 48 should_quit_on_size_change_ = should_quit; 49 } 50 51 private: 52 // TODO(xiyuan): Update this when WidgetDelegate has bounds change hook. 53 virtual void SaveWindowPlacement(const gfx::Rect& bounds, 54 ui::WindowShowState show_state) OVERRIDE { 55 if (should_quit_on_size_change_ && last_size_ != bounds.size()) { 56 // Schedule message loop quit because we could be called while 57 // the bounds change call is on the stack and not in the nested message 58 // loop. 59 base::MessageLoop::current()->PostTask( 60 FROM_HERE, 61 base::Bind(&base::MessageLoop::Quit, 62 base::Unretained(base::MessageLoop::current()))); 63 } 64 65 last_size_ = bounds.size(); 66 } 67 68 virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE { 69 should_quit_on_size_change_ = false; // No quit when we are closing. 70 views::WebDialogView::OnDialogClosed(json_retval); 71 } 72 73 // Whether we should quit message loop when size change is detected. 74 bool should_quit_on_size_change_; 75 gfx::Size last_size_; 76 77 DISALLOW_COPY_AND_ASSIGN(TestWebDialogView); 78 }; 79 80 } // namespace 81 82 class WebDialogBrowserTest : public InProcessBrowserTest { 83 public: 84 WebDialogBrowserTest() {} 85 }; 86 87 // Windows has some issues resizing windows. An off by one problem, and a 88 // minimum size that seems too big. See http://crbug.com/52602. 89 #if defined(OS_WIN) 90 #define MAYBE_SizeWindow DISABLED_SizeWindow 91 #else 92 #define MAYBE_SizeWindow SizeWindow 93 #endif 94 IN_PROC_BROWSER_TEST_F(WebDialogBrowserTest, MAYBE_SizeWindow) { 95 ui::test::TestWebDialogDelegate delegate( 96 (GURL(chrome::kChromeUIChromeURLsURL))); 97 delegate.set_size(kInitialWidth, kInitialHeight); 98 99 TestWebDialogView* view = 100 new TestWebDialogView(browser()->profile(), &delegate); 101 WebContents* web_contents = 102 browser()->tab_strip_model()->GetActiveWebContents(); 103 ASSERT_TRUE(web_contents != NULL); 104 views::Widget::CreateWindowWithParent(view, web_contents->GetNativeView()); 105 view->GetWidget()->Show(); 106 107 // TestWebDialogView should quit current message loop on size change. 108 view->set_should_quit_on_size_change(true); 109 110 gfx::Rect bounds = view->GetWidget()->GetClientAreaBoundsInScreen(); 111 112 gfx::Rect set_bounds = bounds; 113 gfx::Rect actual_bounds, rwhv_bounds; 114 115 // Bigger than the default in both dimensions. 116 set_bounds.set_width(400); 117 set_bounds.set_height(300); 118 119 view->MoveContents(web_contents, set_bounds); 120 content::RunMessageLoop(); // TestWebDialogView will quit. 121 actual_bounds = view->GetWidget()->GetClientAreaBoundsInScreen(); 122 EXPECT_EQ(set_bounds, actual_bounds); 123 124 rwhv_bounds = 125 view->web_contents()->GetRenderWidgetHostView()->GetViewBounds(); 126 EXPECT_LT(0, rwhv_bounds.width()); 127 EXPECT_LT(0, rwhv_bounds.height()); 128 EXPECT_GE(set_bounds.width(), rwhv_bounds.width()); 129 EXPECT_GE(set_bounds.height(), rwhv_bounds.height()); 130 131 // Larger in one dimension and smaller in the other. 132 set_bounds.set_width(550); 133 set_bounds.set_height(250); 134 135 view->MoveContents(web_contents, set_bounds); 136 content::RunMessageLoop(); // TestWebDialogView will quit. 137 actual_bounds = view->GetWidget()->GetClientAreaBoundsInScreen(); 138 EXPECT_EQ(set_bounds, actual_bounds); 139 140 rwhv_bounds = 141 view->web_contents()->GetRenderWidgetHostView()->GetViewBounds(); 142 EXPECT_LT(0, rwhv_bounds.width()); 143 EXPECT_LT(0, rwhv_bounds.height()); 144 EXPECT_GE(set_bounds.width(), rwhv_bounds.width()); 145 EXPECT_GE(set_bounds.height(), rwhv_bounds.height()); 146 147 // Get very small. 148 const gfx::Size min_size = view->GetWidget()->GetMinimumSize(); 149 EXPECT_LT(0, min_size.width()); 150 EXPECT_LT(0, min_size.height()); 151 152 set_bounds.set_size(min_size); 153 154 view->MoveContents(web_contents, set_bounds); 155 content::RunMessageLoop(); // TestWebDialogView will quit. 156 actual_bounds = view->GetWidget()->GetClientAreaBoundsInScreen(); 157 EXPECT_EQ(set_bounds, actual_bounds); 158 159 rwhv_bounds = 160 view->web_contents()->GetRenderWidgetHostView()->GetViewBounds(); 161 EXPECT_LT(0, rwhv_bounds.width()); 162 EXPECT_LT(0, rwhv_bounds.height()); 163 EXPECT_GE(set_bounds.width(), rwhv_bounds.width()); 164 EXPECT_GE(set_bounds.height(), rwhv_bounds.height()); 165 166 // Check to make sure we can't get to 0x0. First expand beyond the minimum 167 // size that was set above so that TestWebDialogView has a change to pick up. 168 set_bounds.set_height(250); 169 view->MoveContents(web_contents, set_bounds); 170 content::RunMessageLoop(); // TestWebDialogView will quit. 171 actual_bounds = view->GetWidget()->GetClientAreaBoundsInScreen(); 172 EXPECT_EQ(set_bounds, actual_bounds); 173 174 // Now verify that attempts to re-size to 0x0 enforces the minimum size. 175 set_bounds.set_width(0); 176 set_bounds.set_height(0); 177 178 view->MoveContents(web_contents, set_bounds); 179 content::RunMessageLoop(); // TestWebDialogView will quit. 180 actual_bounds = view->GetWidget()->GetClientAreaBoundsInScreen(); 181 EXPECT_EQ(min_size, actual_bounds.size()); 182 183 // And that the render view is also non-zero. 184 rwhv_bounds = 185 view->web_contents()->GetRenderWidgetHostView()->GetViewBounds(); 186 EXPECT_LT(0, rwhv_bounds.width()); 187 EXPECT_LT(0, rwhv_bounds.height()); 188 189 view->GetWidget()->CloseNow(); 190 } 191