Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_view_aura_unittest.cc
blob94198ae55724005f27551bb9e0cfcbfe1e8ad8fc
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.
5 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
7 #include "base/basictypes.h"
8 #include "base/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/renderer_host/render_widget_host_delegate.h"
11 #include "content/browser/renderer_host/render_widget_host_impl.h"
12 #include "content/common/input_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/browser/render_widget_host_view.h"
15 #include "content/public/test/mock_render_process_host.h"
16 #include "content/public/test/test_browser_context.h"
17 #include "ipc/ipc_test_sink.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "ui/aura/client/aura_constants.h"
20 #include "ui/aura/env.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/aura/test/aura_test_helper.h"
23 #include "ui/aura/test/test_cursor_client.h"
24 #include "ui/aura/test/test_screen.h"
25 #include "ui/aura/test/test_window_delegate.h"
26 #include "ui/aura/window.h"
27 #include "ui/aura/window_observer.h"
28 #include "ui/base/events/event.h"
29 #include "ui/base/events/event_utils.h"
30 #include "ui/base/ui_base_types.h"
32 namespace content {
33 namespace {
34 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
35 public:
36 MockRenderWidgetHostDelegate() {}
37 virtual ~MockRenderWidgetHostDelegate() {}
40 // Simple observer that keeps track of changes to a window for tests.
41 class TestWindowObserver : public aura::WindowObserver {
42 public:
43 explicit TestWindowObserver(aura::Window* window_to_observe)
44 : window_(window_to_observe) {
45 window_->AddObserver(this);
47 virtual ~TestWindowObserver() {
48 if (window_)
49 window_->RemoveObserver(this);
52 bool destroyed() const { return destroyed_; }
54 // aura::WindowObserver overrides:
55 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
56 CHECK_EQ(window, window_);
57 destroyed_ = true;
58 window_ = NULL;
61 private:
62 // Window that we're observing, or NULL if it's been destroyed.
63 aura::Window* window_;
65 // Was |window_| destroyed?
66 bool destroyed_;
68 DISALLOW_COPY_AND_ASSIGN(TestWindowObserver);
71 class RenderWidgetHostViewAuraTest : public testing::Test {
72 public:
73 RenderWidgetHostViewAuraTest() {}
75 virtual void SetUp() {
76 aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
77 aura_test_helper_->SetUp();
79 browser_context_.reset(new TestBrowserContext);
80 MockRenderProcessHost* process_host =
81 new MockRenderProcessHost(browser_context_.get());
83 sink_ = &process_host->sink();
85 parent_host_ = new RenderWidgetHostImpl(
86 &delegate_, process_host, MSG_ROUTING_NONE);
87 parent_view_ = static_cast<RenderWidgetHostViewAura*>(
88 RenderWidgetHostView::CreateViewForWidget(parent_host_));
89 parent_view_->InitAsChild(NULL);
90 parent_view_->GetNativeView()->SetDefaultParentByRootWindow(
91 aura_test_helper_->root_window(), gfx::Rect());
93 widget_host_ = new RenderWidgetHostImpl(
94 &delegate_, process_host, MSG_ROUTING_NONE);
95 widget_host_->Init();
96 view_ = static_cast<RenderWidgetHostViewAura*>(
97 RenderWidgetHostView::CreateViewForWidget(widget_host_));
100 virtual void TearDown() {
101 sink_ = NULL;
102 if (view_)
103 view_->Destroy();
104 delete widget_host_;
106 parent_view_->Destroy();
107 delete parent_host_;
109 browser_context_.reset();
110 aura_test_helper_->TearDown();
112 message_loop_.DeleteSoon(FROM_HERE, browser_context_.release());
113 message_loop_.RunUntilIdle();
116 protected:
117 base::MessageLoopForUI message_loop_;
118 scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
119 scoped_ptr<BrowserContext> browser_context_;
120 MockRenderWidgetHostDelegate delegate_;
122 // Tests should set these to NULL if they've already triggered their
123 // destruction.
124 RenderWidgetHostImpl* parent_host_;
125 RenderWidgetHostViewAura* parent_view_;
127 // Tests should set these to NULL if they've already triggered their
128 // destruction.
129 RenderWidgetHostImpl* widget_host_;
130 RenderWidgetHostViewAura* view_;
132 IPC::TestSink* sink_;
134 private:
135 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest);
138 } // namespace
140 // Checks that a fullscreen view has the correct show-state and receives the
141 // focus.
142 TEST_F(RenderWidgetHostViewAuraTest, FocusFullscreen) {
143 view_->InitAsFullscreen(parent_view_);
144 aura::Window* window = view_->GetNativeView();
145 ASSERT_TRUE(window != NULL);
146 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN,
147 window->GetProperty(aura::client::kShowStateKey));
149 // Check that we requested and received the focus.
150 EXPECT_TRUE(window->HasFocus());
152 // Check that we'll also say it's okay to activate the window when there's an
153 // ActivationClient defined.
154 EXPECT_TRUE(view_->ShouldActivate());
157 // Checks that a fullscreen view is destroyed when it loses the focus.
158 TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) {
159 view_->InitAsFullscreen(parent_view_);
160 aura::Window* window = view_->GetNativeView();
161 ASSERT_TRUE(window != NULL);
162 ASSERT_TRUE(window->HasFocus());
164 // After we create and focus another window, the RWHVA's window should be
165 // destroyed.
166 TestWindowObserver observer(window);
167 aura::test::TestWindowDelegate delegate;
168 scoped_ptr<aura::Window> sibling(new aura::Window(&delegate));
169 sibling->Init(ui::LAYER_TEXTURED);
170 sibling->Show();
171 window->parent()->AddChild(sibling.get());
172 sibling->Focus();
173 ASSERT_TRUE(sibling->HasFocus());
174 ASSERT_TRUE(observer.destroyed());
176 widget_host_ = NULL;
177 view_ = NULL;
180 // Checks that IME-composition-event state is maintained correctly.
181 TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
182 view_->InitAsChild(NULL);
183 view_->Show();
185 ui::CompositionText composition_text;
186 composition_text.text = ASCIIToUTF16("|a|b");
188 // Focused segment
189 composition_text.underlines.push_back(
190 ui::CompositionUnderline(0, 3, 0xff000000, true));
192 // Non-focused segment
193 composition_text.underlines.push_back(
194 ui::CompositionUnderline(3, 4, 0xff000000, false));
196 const ui::CompositionUnderlines& underlines = composition_text.underlines;
198 // Caret is at the end. (This emulates Japanese MSIME 2007 and later)
199 composition_text.selection = ui::Range(4);
201 sink_->ClearMessages();
202 view_->SetCompositionText(composition_text);
203 EXPECT_TRUE(view_->has_composition_text_);
205 const IPC::Message* msg =
206 sink_->GetFirstMessageMatching(ViewMsg_ImeSetComposition::ID);
207 ASSERT_TRUE(msg != NULL);
209 ViewMsg_ImeSetComposition::Param params;
210 ViewMsg_ImeSetComposition::Read(msg, &params);
211 // composition text
212 EXPECT_EQ(composition_text.text, params.a);
213 // underlines
214 ASSERT_EQ(underlines.size(), params.b.size());
215 for (size_t i = 0; i < underlines.size(); ++i) {
216 EXPECT_EQ(underlines[i].start_offset, params.b[i].startOffset);
217 EXPECT_EQ(underlines[i].end_offset, params.b[i].endOffset);
218 EXPECT_EQ(underlines[i].color, params.b[i].color);
219 EXPECT_EQ(underlines[i].thick, params.b[i].thick);
221 // highlighted range
222 EXPECT_EQ(4, params.c) << "Should be the same to the caret pos";
223 EXPECT_EQ(4, params.d) << "Should be the same to the caret pos";
226 view_->ImeCancelComposition();
227 EXPECT_FALSE(view_->has_composition_text_);
230 // Checks that touch-event state is maintained correctly.
231 TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
232 view_->InitAsChild(NULL);
233 view_->Show();
235 // Start with no touch-event handler in the renderer.
236 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
237 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
239 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
240 gfx::Point(30, 30),
242 ui::EventTimeForNow());
243 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
244 gfx::Point(20, 20),
246 ui::EventTimeForNow());
247 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
248 gfx::Point(20, 20),
250 ui::EventTimeForNow());
252 view_->OnTouchEvent(&press);
253 EXPECT_FALSE(press.handled());
254 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type);
255 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
256 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed,
257 view_->touch_event_.touches[0].state);
259 view_->OnTouchEvent(&move);
260 EXPECT_FALSE(move.handled());
261 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type);
262 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
263 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved,
264 view_->touch_event_.touches[0].state);
266 view_->OnTouchEvent(&release);
267 EXPECT_FALSE(release.handled());
268 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type);
269 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
271 // Now install some touch-event handlers and do the same steps. The touch
272 // events should now be consumed. However, the touch-event state should be
273 // updated as before.
274 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
275 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
277 view_->OnTouchEvent(&press);
278 EXPECT_TRUE(press.stopped_propagation());
279 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type);
280 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
281 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed,
282 view_->touch_event_.touches[0].state);
284 view_->OnTouchEvent(&move);
285 EXPECT_TRUE(move.stopped_propagation());
286 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type);
287 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
288 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved,
289 view_->touch_event_.touches[0].state);
291 view_->OnTouchEvent(&release);
292 EXPECT_TRUE(release.stopped_propagation());
293 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type);
294 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
296 // Now start a touch event, and remove the event-handlers before the release.
297 view_->OnTouchEvent(&press);
298 EXPECT_TRUE(press.stopped_propagation());
299 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type);
300 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
301 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed,
302 view_->touch_event_.touches[0].state);
304 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
305 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
307 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0,
308 base::Time::NowFromSystemTime() - base::Time());
309 view_->OnTouchEvent(&move2);
310 EXPECT_FALSE(move2.handled());
311 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type);
312 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
313 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved,
314 view_->touch_event_.touches[0].state);
316 ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0,
317 base::Time::NowFromSystemTime() - base::Time());
318 view_->OnTouchEvent(&release2);
319 EXPECT_FALSE(release2.handled());
320 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type);
321 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
324 // Checks that touch-events are queued properly when there is a touch-event
325 // handler on the page.
326 TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) {
327 view_->InitAsChild(NULL);
328 view_->Show();
330 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
331 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
333 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
334 gfx::Point(30, 30),
336 ui::EventTimeForNow());
337 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
338 gfx::Point(20, 20),
340 ui::EventTimeForNow());
341 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
342 gfx::Point(20, 20),
344 ui::EventTimeForNow());
346 view_->OnTouchEvent(&press);
347 EXPECT_TRUE(press.stopped_propagation());
348 EXPECT_EQ(WebKit::WebInputEvent::TouchStart, view_->touch_event_.type);
349 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
350 EXPECT_EQ(WebKit::WebTouchPoint::StatePressed,
351 view_->touch_event_.touches[0].state);
353 view_->OnTouchEvent(&move);
354 EXPECT_TRUE(move.stopped_propagation());
355 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type);
356 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
357 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved,
358 view_->touch_event_.touches[0].state);
360 // Send the same move event. Since the point hasn't moved, it won't affect the
361 // queue. However, the view should consume the event.
362 view_->OnTouchEvent(&move);
363 EXPECT_TRUE(move.stopped_propagation());
364 EXPECT_EQ(WebKit::WebInputEvent::TouchMove, view_->touch_event_.type);
365 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
366 EXPECT_EQ(WebKit::WebTouchPoint::StateMoved,
367 view_->touch_event_.touches[0].state);
369 view_->OnTouchEvent(&release);
370 EXPECT_TRUE(release.stopped_propagation());
371 EXPECT_EQ(WebKit::WebInputEvent::TouchEnd, view_->touch_event_.type);
372 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
375 TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
376 view_->InitAsChild(NULL);
377 view_->GetNativeView()->SetDefaultParentByRootWindow(
378 parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
379 sink_->ClearMessages();
380 view_->SetSize(gfx::Size(100, 100));
381 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
382 EXPECT_EQ(1u, sink_->message_count());
383 EXPECT_EQ(ViewMsg_Resize::ID, sink_->GetMessageAt(0)->type());
385 const IPC::Message* msg = sink_->GetMessageAt(0);
386 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
387 ViewMsg_Resize::Param params;
388 ViewMsg_Resize::Read(msg, &params);
389 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
390 EXPECT_EQ("100x100",
391 params.a.physical_backing_size.ToString()); // backing size
394 widget_host_->ResetSizeAndRepaintPendingFlags();
395 sink_->ClearMessages();
397 aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f);
398 EXPECT_EQ("200x200", view_->GetPhysicalBackingSize().ToString());
399 // Extra ScreenInfoChanged message for |parent_view_|.
400 EXPECT_EQ(1u, sink_->message_count());
402 const IPC::Message* msg = sink_->GetMessageAt(0);
403 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
404 ViewMsg_Resize::Param params;
405 ViewMsg_Resize::Read(msg, &params);
406 EXPECT_EQ(2.0f, params.a.screen_info.deviceScaleFactor);
407 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
408 EXPECT_EQ("200x200",
409 params.a.physical_backing_size.ToString()); // backing size
412 widget_host_->ResetSizeAndRepaintPendingFlags();
413 sink_->ClearMessages();
415 aura_test_helper_->test_screen()->SetDeviceScaleFactor(1.0f);
416 // Extra ScreenInfoChanged message for |parent_view_|.
417 EXPECT_EQ(1u, sink_->message_count());
418 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
420 const IPC::Message* msg = sink_->GetMessageAt(0);
421 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
422 ViewMsg_Resize::Param params;
423 ViewMsg_Resize::Read(msg, &params);
424 EXPECT_EQ(1.0f, params.a.screen_info.deviceScaleFactor);
425 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
426 EXPECT_EQ("100x100",
427 params.a.physical_backing_size.ToString()); // backing size
431 // Checks that InputMsg_CursorVisibilityChange IPC messages are dispatched
432 // to the renderer at the correct times.
433 TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
434 view_->InitAsChild(NULL);
435 view_->GetNativeView()->SetDefaultParentByRootWindow(
436 parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect());
437 view_->SetSize(gfx::Size(100, 100));
439 aura::test::TestCursorClient cursor_client(
440 parent_view_->GetNativeView()->GetRootWindow());
442 cursor_client.AddObserver(view_);
444 // Expect a message the first time the cursor is shown.
445 view_->WasShown();
446 sink_->ClearMessages();
447 cursor_client.ShowCursor();
448 EXPECT_EQ(1u, sink_->message_count());
449 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
450 InputMsg_CursorVisibilityChange::ID));
452 // No message expected if the renderer already knows the cursor is visible.
453 sink_->ClearMessages();
454 cursor_client.ShowCursor();
455 EXPECT_EQ(0u, sink_->message_count());
457 // Hiding the cursor should send a message.
458 sink_->ClearMessages();
459 cursor_client.HideCursor();
460 EXPECT_EQ(1u, sink_->message_count());
461 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
462 InputMsg_CursorVisibilityChange::ID));
464 // No message expected if the renderer already knows the cursor is invisible.
465 sink_->ClearMessages();
466 cursor_client.HideCursor();
467 EXPECT_EQ(0u, sink_->message_count());
469 // No messages should be sent while the view is invisible.
470 view_->WasHidden();
471 sink_->ClearMessages();
472 cursor_client.ShowCursor();
473 EXPECT_EQ(0u, sink_->message_count());
474 cursor_client.HideCursor();
475 EXPECT_EQ(0u, sink_->message_count());
477 // Show the view. Since the cursor was invisible when the view was hidden,
478 // no message should be sent.
479 sink_->ClearMessages();
480 view_->WasShown();
481 EXPECT_FALSE(sink_->GetUniqueMessageMatching(
482 InputMsg_CursorVisibilityChange::ID));
484 // No message expected if the renderer already knows the cursor is invisible.
485 sink_->ClearMessages();
486 cursor_client.HideCursor();
487 EXPECT_EQ(0u, sink_->message_count());
489 // Showing the cursor should send a message.
490 sink_->ClearMessages();
491 cursor_client.ShowCursor();
492 EXPECT_EQ(1u, sink_->message_count());
493 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
494 InputMsg_CursorVisibilityChange::ID));
496 // No messages should be sent while the view is invisible.
497 view_->WasHidden();
498 sink_->ClearMessages();
499 cursor_client.HideCursor();
500 EXPECT_EQ(0u, sink_->message_count());
502 // Show the view. Since the cursor was visible when the view was hidden,
503 // a message is expected to be sent.
504 sink_->ClearMessages();
505 view_->WasShown();
506 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
507 InputMsg_CursorVisibilityChange::ID));
509 cursor_client.RemoveObserver(view_);
512 } // namespace content