render_widget_host_view_aura_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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 "content/browser/renderer_host/render_widget_host_view_aura.h" 6 7#include "base/basictypes.h" 8#include "base/message_loop.h" 9#include "content/browser/renderer_host/render_widget_host_delegate.h" 10#include "content/browser/renderer_host/render_widget_host_impl.h" 11#include "content/common/view_messages.h" 12#include "content/public/browser/render_widget_host_view.h" 13#include "content/public/test/mock_render_process_host.h" 14#include "content/public/test/test_browser_context.h" 15#include "ipc/ipc_test_sink.h" 16#include "testing/gtest/include/gtest/gtest.h" 17#include "ui/aura/client/aura_constants.h" 18#include "ui/aura/env.h" 19#include "ui/aura/test/aura_test_helper.h" 20#include "ui/aura/test/test_screen.h" 21#include "ui/aura/test/test_window_delegate.h" 22#include "ui/aura/window.h" 23#include "ui/aura/window_observer.h" 24#include "ui/base/events/event.h" 25#include "ui/base/events/event_utils.h" 26#include "ui/base/ui_base_types.h" 27 28namespace content { 29namespace { 30class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { 31 public: 32 MockRenderWidgetHostDelegate() {} 33 virtual ~MockRenderWidgetHostDelegate() {} 34}; 35 36// Simple observer that keeps track of changes to a window for tests. 37class TestWindowObserver : public aura::WindowObserver { 38 public: 39 explicit TestWindowObserver(aura::Window* window_to_observe) 40 : window_(window_to_observe) { 41 window_->AddObserver(this); 42 } 43 virtual ~TestWindowObserver() { 44 if (window_) 45 window_->RemoveObserver(this); 46 } 47 48 bool destroyed() const { return destroyed_; } 49 50 // aura::WindowObserver overrides: 51 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 52 CHECK_EQ(window, window_); 53 destroyed_ = true; 54 window_ = NULL; 55 } 56 57 private: 58 // Window that we're observing, or NULL if it's been destroyed. 59 aura::Window* window_; 60 61 // Was |window_| destroyed? 62 bool destroyed_; 63 64 DISALLOW_COPY_AND_ASSIGN(TestWindowObserver); 65}; 66 67class RenderWidgetHostViewAuraTest : public testing::Test { 68 public: 69 RenderWidgetHostViewAuraTest() {} 70 71 virtual void SetUp() { 72 aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_)); 73 aura_test_helper_->SetUp(); 74 75 browser_context_.reset(new TestBrowserContext); 76 MockRenderProcessHost* process_host = 77 new MockRenderProcessHost(browser_context_.get()); 78 79 sink_ = &process_host->sink(); 80 81 parent_host_ = new RenderWidgetHostImpl( 82 &delegate_, process_host, MSG_ROUTING_NONE); 83 parent_view_ = static_cast<RenderWidgetHostViewAura*>( 84 RenderWidgetHostView::CreateViewForWidget(parent_host_)); 85 parent_view_->InitAsChild(NULL); 86 parent_view_->GetNativeView()->SetDefaultParentByRootWindow( 87 aura_test_helper_->root_window(), gfx::Rect()); 88 89 widget_host_ = new RenderWidgetHostImpl( 90 &delegate_, process_host, MSG_ROUTING_NONE); 91 widget_host_->Init(); 92 view_ = static_cast<RenderWidgetHostViewAura*>( 93 RenderWidgetHostView::CreateViewForWidget(widget_host_)); 94 } 95 96 virtual void TearDown() { 97 sink_ = NULL; 98 if (view_) 99 view_->Destroy(); 100 delete widget_host_; 101 102 parent_view_->Destroy(); 103 delete parent_host_; 104 105 browser_context_.reset(); 106 aura_test_helper_->TearDown(); 107 108 message_loop_.DeleteSoon(FROM_HERE, browser_context_.release()); 109 message_loop_.RunUntilIdle(); 110 } 111 112 protected: 113 base::MessageLoopForUI message_loop_; 114 scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_; 115 scoped_ptr<BrowserContext> browser_context_; 116 MockRenderWidgetHostDelegate delegate_; 117 118 // Tests should set these to NULL if they've already triggered their 119 // destruction. 120 RenderWidgetHostImpl* parent_host_; 121 RenderWidgetHostViewAura* parent_view_; 122 123 // Tests should set these to NULL if they've already triggered their 124 // destruction. 125 RenderWidgetHostImpl* widget_host_; 126 RenderWidgetHostViewAura* view_; 127 128 IPC::TestSink* sink_; 129 130 private: 131 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest); 132}; 133 134} // namespace 135 136// Checks that a fullscreen view has the correct show-state and receives the 137// focus. 138TEST_F(RenderWidgetHostViewAuraTest, FocusFullscreen) { 139 view_->InitAsFullscreen(parent_view_); 140 aura::Window* window = view_->GetNativeView(); 141 ASSERT_TRUE(window != NULL); 142 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, 143 window->GetProperty(aura::client::kShowStateKey)); 144 145 // Check that we requested and received the focus. 146 EXPECT_TRUE(window->HasFocus()); 147 148 // Check that we'll also say it's okay to activate the window when there's an 149 // ActivationClient defined. 150 EXPECT_TRUE(view_->ShouldActivate()); 151} 152 153// Checks that a fullscreen view is destroyed when it loses the focus. 154TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) { 155 view_->InitAsFullscreen(parent_view_); 156 aura::Window* window = view_->GetNativeView(); 157 ASSERT_TRUE(window != NULL); 158 ASSERT_TRUE(window->HasFocus()); 159 160 // After we create and focus another window, the RWHVA's window should be 161 // destroyed. 162 TestWindowObserver observer(window); 163 aura::test::TestWindowDelegate delegate; 164 scoped_ptr<aura::Window> sibling(new aura::Window(&delegate)); 165 sibling->Init(ui::LAYER_TEXTURED); 166 sibling->Show(); 167 window->parent()->AddChild(sibling.get()); 168 sibling->Focus(); 169 ASSERT_TRUE(sibling->HasFocus()); 170 ASSERT_TRUE(observer.destroyed()); 171 172 widget_host_ = NULL; 173 view_ = NULL; 174} 175 176// Checks that touch-event state is maintained correctly. 177TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) { 178 view_->InitAsChild(NULL); 179 view_->Show(); 180 181 // Start with no touch-event handler in the renderer. 182 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); 183 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent()); 184 185 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 186 gfx::Point(30, 30), 187 0, 188 ui::EventTimeForNow()); 189 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 190 gfx::Point(20, 20), 191 0, 192 ui::EventTimeForNow()); 193 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, 194 gfx::Point(20, 20), 195 0, 196 ui::EventTimeForNow()); 197 198 view_->OnTouchEvent(&press); 199 EXPECT_FALSE(press.handled()); 200 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type); 201 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 202 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed, 203 view_->touch_event_.touches[0].state); 204 205 view_->OnTouchEvent(&move); 206 EXPECT_FALSE(move.handled()); 207 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type); 208 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 209 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved, 210 view_->touch_event_.touches[0].state); 211 212 view_->OnTouchEvent(&release); 213 EXPECT_FALSE(release.handled()); 214 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type); 215 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 216 217 // Now install some touch-event handlers and do the same steps. The touch 218 // events should now be consumed. However, the touch-event state should be 219 // updated as before. 220 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); 221 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent()); 222 223 view_->OnTouchEvent(&press); 224 EXPECT_TRUE(press.stopped_propagation()); 225 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type); 226 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 227 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed, 228 view_->touch_event_.touches[0].state); 229 230 view_->OnTouchEvent(&move); 231 EXPECT_TRUE(move.stopped_propagation()); 232 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type); 233 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 234 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved, 235 view_->touch_event_.touches[0].state); 236 237 view_->OnTouchEvent(&release); 238 EXPECT_TRUE(release.stopped_propagation()); 239 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type); 240 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 241 242 // Now start a touch event, and remove the event-handlers before the release. 243 view_->OnTouchEvent(&press); 244 EXPECT_TRUE(press.stopped_propagation()); 245 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type); 246 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 247 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed, 248 view_->touch_event_.touches[0].state); 249 250 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); 251 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent()); 252 253 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0, 254 base::Time::NowFromSystemTime() - base::Time()); 255 view_->OnTouchEvent(&move2); 256 EXPECT_FALSE(move2.handled()); 257 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type); 258 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 259 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved, 260 view_->touch_event_.touches[0].state); 261 262 ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0, 263 base::Time::NowFromSystemTime() - base::Time()); 264 view_->OnTouchEvent(&release2); 265 EXPECT_FALSE(release2.handled()); 266 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type); 267 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 268} 269 270// Checks that touch-events are queued properly when there is a touch-event 271// handler on the page. 272TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) { 273 view_->InitAsChild(NULL); 274 view_->Show(); 275 276 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); 277 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent()); 278 279 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 280 gfx::Point(30, 30), 281 0, 282 ui::EventTimeForNow()); 283 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 284 gfx::Point(20, 20), 285 0, 286 ui::EventTimeForNow()); 287 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, 288 gfx::Point(20, 20), 289 0, 290 ui::EventTimeForNow()); 291 292 view_->OnTouchEvent(&press); 293 EXPECT_TRUE(press.stopped_propagation()); 294 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type); 295 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 296 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed, 297 view_->touch_event_.touches[0].state); 298 299 view_->OnTouchEvent(&move); 300 EXPECT_TRUE(move.stopped_propagation()); 301 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type); 302 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 303 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved, 304 view_->touch_event_.touches[0].state); 305 306 // Send the same move event. Since the point hasn't moved, it won't affect the 307 // queue. However, the view should consume the event. 308 view_->OnTouchEvent(&move); 309 EXPECT_TRUE(move.stopped_propagation()); 310 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type); 311 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 312 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved, 313 view_->touch_event_.touches[0].state); 314 315 view_->OnTouchEvent(&release); 316 EXPECT_TRUE(release.stopped_propagation()); 317 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type); 318 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 319} 320 321TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) { 322 view_->InitAsChild(NULL); 323 view_->GetNativeView()->SetDefaultParentByRootWindow( 324 parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); 325 sink_->ClearMessages(); 326 view_->SetSize(gfx::Size(100, 100)); 327 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString()); 328 EXPECT_EQ(1u, sink_->message_count()); 329 EXPECT_EQ(ViewMsg_Resize::ID, sink_->GetMessageAt(0)->type()); 330 { 331 const IPC::Message* msg = sink_->GetMessageAt(0); 332 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 333 ViewMsg_Resize::Param params; 334 ViewMsg_Resize::Read(msg, ¶ms); 335 EXPECT_EQ("100x100", params.a.ToString()); // dip size 336 EXPECT_EQ("100x100", params.b.ToString()); // backing size 337 } 338 339 widget_host_->ResetSizeAndRepaintPendingFlags(); 340 sink_->ClearMessages(); 341 342 aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f); 343 EXPECT_EQ("200x200", view_->GetPhysicalBackingSize().ToString()); 344 // Extra ScreenInfoChanged message for |parent_view_|. 345 EXPECT_EQ(3u, sink_->message_count()); 346 EXPECT_EQ(ViewMsg_ScreenInfoChanged::ID, sink_->GetMessageAt(0)->type()); 347 { 348 const IPC::Message* msg = sink_->GetMessageAt(1); 349 EXPECT_EQ(ViewMsg_ScreenInfoChanged::ID, msg->type()); 350 ViewMsg_ScreenInfoChanged::Param params; 351 ViewMsg_ScreenInfoChanged::Read(msg, ¶ms); 352 EXPECT_EQ(2.0f, params.a.deviceScaleFactor); 353 } 354 { 355 const IPC::Message* msg = sink_->GetMessageAt(2); 356 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 357 ViewMsg_Resize::Param params; 358 ViewMsg_Resize::Read(msg, ¶ms); 359 EXPECT_EQ("100x100", params.a.ToString()); // dip size 360 EXPECT_EQ("200x200", params.b.ToString()); // backing size 361 } 362 363 widget_host_->ResetSizeAndRepaintPendingFlags(); 364 sink_->ClearMessages(); 365 366 aura_test_helper_->test_screen()->SetDeviceScaleFactor(1.0f); 367 // Extra ScreenInfoChanged message for |parent_view_|. 368 EXPECT_EQ(3u, sink_->message_count()); 369 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString()); 370 EXPECT_EQ(ViewMsg_ScreenInfoChanged::ID, sink_->GetMessageAt(0)->type()); 371 { 372 const IPC::Message* msg = sink_->GetMessageAt(1); 373 EXPECT_EQ(ViewMsg_ScreenInfoChanged::ID, msg->type()); 374 ViewMsg_ScreenInfoChanged::Param params; 375 ViewMsg_ScreenInfoChanged::Read(msg, ¶ms); 376 EXPECT_EQ(1.0f, params.a.deviceScaleFactor); 377 } 378 { 379 const IPC::Message* msg = sink_->GetMessageAt(2); 380 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 381 ViewMsg_Resize::Param params; 382 ViewMsg_Resize::Read(msg, ¶ms); 383 EXPECT_EQ("100x100", params.a.ToString()); // dip size 384 EXPECT_EQ("100x100", params.b.ToString()); // backing size 385 } 386} 387 388} // namespace content 389