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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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