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/memory/shared_memory.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "cc/output/compositor_frame.h"
13 #include "cc/output/compositor_frame_metadata.h"
14 #include "cc/output/copy_output_request.h"
15 #include "cc/output/gl_frame_data.h"
16 #include "content/browser/browser_thread_impl.h"
17 #include "content/browser/compositor/owned_mailbox.h"
18 #include "content/browser/compositor/resize_lock.h"
19 #include "content/browser/renderer_host/render_widget_host_delegate.h"
20 #include "content/browser/renderer_host/render_widget_host_impl.h"
21 #include "content/common/gpu/gpu_messages.h"
22 #include "content/common/host_shared_bitmap_manager.h"
23 #include "content/common/input_messages.h"
24 #include "content/common/view_messages.h"
25 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/test/mock_render_process_host.h"
28 #include "content/public/test/test_browser_context.h"
29 #include "ipc/ipc_test_sink.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "ui/aura/client/aura_constants.h"
33 #include "ui/aura/client/screen_position_client.h"
34 #include "ui/aura/client/window_tree_client.h"
35 #include "ui/aura/env.h"
36 #include "ui/aura/layout_manager.h"
37 #include "ui/aura/test/aura_test_helper.h"
38 #include "ui/aura/test/event_generator.h"
39 #include "ui/aura/test/test_cursor_client.h"
40 #include "ui/aura/test/test_screen.h"
41 #include "ui/aura/test/test_window_delegate.h"
42 #include "ui/aura/window.h"
43 #include "ui/aura/window_event_dispatcher.h"
44 #include "ui/aura/window_observer.h"
45 #include "ui/base/ui_base_types.h"
46 #include "ui/compositor/compositor.h"
47 #include "ui/compositor/test/draw_waiter_for_test.h"
48 #include "ui/compositor/test/in_process_context_factory.h"
49 #include "ui/events/event.h"
50 #include "ui/events/event_utils.h"
57 // Simple screen position client to test coordinate system conversion.
58 class TestScreenPositionClient
59 : public aura::client::ScreenPositionClient {
61 TestScreenPositionClient() {}
62 virtual ~TestScreenPositionClient() {}
64 // aura::client::ScreenPositionClient overrides:
65 virtual void ConvertPointToScreen(const aura::Window* window,
66 gfx::Point* point) OVERRIDE {
67 point->Offset(-1, -1);
70 virtual void ConvertPointFromScreen(const aura::Window* window,
71 gfx::Point* point) OVERRIDE {
75 virtual void ConvertHostPointToScreen(aura::Window* window,
76 gfx::Point* point) OVERRIDE {
77 ConvertPointToScreen(window, point);
80 virtual void SetBounds(aura::Window* window,
81 const gfx::Rect& bounds,
82 const gfx::Display& display) OVERRIDE {
86 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
88 MockRenderWidgetHostDelegate() {}
89 virtual ~MockRenderWidgetHostDelegate() {}
92 // Simple observer that keeps track of changes to a window for tests.
93 class TestWindowObserver : public aura::WindowObserver {
95 explicit TestWindowObserver(aura::Window* window_to_observe)
96 : window_(window_to_observe) {
97 window_->AddObserver(this);
99 virtual ~TestWindowObserver() {
101 window_->RemoveObserver(this);
104 bool destroyed() const { return destroyed_; }
106 // aura::WindowObserver overrides:
107 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
108 CHECK_EQ(window, window_);
114 // Window that we're observing, or NULL if it's been destroyed.
115 aura::Window* window_;
117 // Was |window_| destroyed?
120 DISALLOW_COPY_AND_ASSIGN(TestWindowObserver);
123 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
125 FakeFrameSubscriber(gfx::Size size, base::Callback<void(bool)> callback)
126 : size_(size), callback_(callback) {}
128 virtual bool ShouldCaptureFrame(base::TimeTicks present_time,
129 scoped_refptr<media::VideoFrame>* storage,
130 DeliverFrameCallback* callback) OVERRIDE {
131 *storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
136 *callback = base::Bind(&FakeFrameSubscriber::CallbackMethod, callback_);
140 static void CallbackMethod(base::Callback<void(bool)> callback,
141 base::TimeTicks timestamp,
143 callback.Run(success);
148 base::Callback<void(bool)> callback_;
151 class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
153 FakeRenderWidgetHostViewAura(RenderWidgetHost* widget)
154 : RenderWidgetHostViewAura(widget), has_resize_lock_(false) {}
156 virtual ~FakeRenderWidgetHostViewAura() {}
158 virtual bool ShouldCreateResizeLock() OVERRIDE {
159 gfx::Size desired_size = window()->bounds().size();
160 return desired_size != current_frame_size();
163 virtual scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock)
165 gfx::Size desired_size = window()->bounds().size();
166 return scoped_ptr<ResizeLock>(
167 new FakeResizeLock(desired_size, defer_compositor_lock));
170 virtual void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request)
172 last_copy_request_ = request.Pass();
173 if (last_copy_request_->has_texture_mailbox()) {
174 // Give the resulting texture a size.
175 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
176 GLuint texture = gl_helper->ConsumeMailboxToTexture(
177 last_copy_request_->texture_mailbox().mailbox(),
178 last_copy_request_->texture_mailbox().sync_point());
179 gl_helper->ResizeTexture(texture, window()->bounds().size());
180 gl_helper->DeleteTexture(texture);
184 void RunOnCompositingDidCommit() {
185 OnCompositingDidCommit(window()->GetHost()->compositor());
188 // A lock that doesn't actually do anything to the compositor, and does not
190 class FakeResizeLock : public ResizeLock {
192 FakeResizeLock(const gfx::Size new_size, bool defer_compositor_lock)
193 : ResizeLock(new_size, defer_compositor_lock) {}
196 bool has_resize_lock_;
197 gfx::Size last_frame_size_;
198 scoped_ptr<cc::CopyOutputRequest> last_copy_request_;
201 class RenderWidgetHostViewAuraTest : public testing::Test {
203 RenderWidgetHostViewAuraTest()
204 : browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {}
206 void SetUpEnvironment() {
207 ImageTransportFactory::InitializeForUnitTests(
208 scoped_ptr<ui::ContextFactory>(new ui::InProcessContextFactory));
209 aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
210 aura_test_helper_->SetUp();
212 browser_context_.reset(new TestBrowserContext);
213 process_host_ = new MockRenderProcessHost(browser_context_.get());
215 sink_ = &process_host_->sink();
217 parent_host_ = new RenderWidgetHostImpl(
218 &delegate_, process_host_, MSG_ROUTING_NONE, false);
219 parent_view_ = static_cast<RenderWidgetHostViewAura*>(
220 RenderWidgetHostView::CreateViewForWidget(parent_host_));
221 parent_view_->InitAsChild(NULL);
222 aura::client::ParentWindowWithContext(parent_view_->GetNativeView(),
223 aura_test_helper_->root_window(),
226 widget_host_ = new RenderWidgetHostImpl(
227 &delegate_, process_host_, MSG_ROUTING_NONE, false);
228 widget_host_->Init();
229 widget_host_->OnMessageReceived(
230 ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
231 view_ = new FakeRenderWidgetHostViewAura(widget_host_);
234 void TearDownEnvironment() {
236 process_host_ = NULL;
241 parent_view_->Destroy();
244 browser_context_.reset();
245 aura_test_helper_->TearDown();
247 message_loop_.DeleteSoon(FROM_HERE, browser_context_.release());
248 message_loop_.RunUntilIdle();
249 ImageTransportFactory::Terminate();
252 virtual void SetUp() { SetUpEnvironment(); }
254 virtual void TearDown() { TearDownEnvironment(); }
257 base::MessageLoopForUI message_loop_;
258 BrowserThreadImpl browser_thread_for_ui_;
259 scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
260 scoped_ptr<BrowserContext> browser_context_;
261 MockRenderWidgetHostDelegate delegate_;
262 MockRenderProcessHost* process_host_;
264 // Tests should set these to NULL if they've already triggered their
266 RenderWidgetHostImpl* parent_host_;
267 RenderWidgetHostViewAura* parent_view_;
269 // Tests should set these to NULL if they've already triggered their
271 RenderWidgetHostImpl* widget_host_;
272 FakeRenderWidgetHostViewAura* view_;
274 IPC::TestSink* sink_;
277 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest);
280 class RenderWidgetHostViewAuraShutdownTest
281 : public RenderWidgetHostViewAuraTest {
283 RenderWidgetHostViewAuraShutdownTest() {}
285 virtual void TearDown() OVERRIDE {
286 // No TearDownEnvironment here, we do this explicitly during the test.
290 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest);
293 // A layout manager that always resizes a child to the root window size.
294 class FullscreenLayoutManager : public aura::LayoutManager {
296 explicit FullscreenLayoutManager(aura::Window* owner)
298 virtual ~FullscreenLayoutManager() {}
300 // Overridden from aura::LayoutManager:
301 virtual void OnWindowResized() OVERRIDE {
302 aura::Window::Windows::const_iterator i;
303 for (i = owner_->children().begin(); i != owner_->children().end(); ++i) {
304 (*i)->SetBounds(gfx::Rect());
307 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
308 child->SetBounds(gfx::Rect());
310 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
312 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
314 virtual void OnChildWindowVisibilityChanged(aura::Window* child,
315 bool visible) OVERRIDE {
317 virtual void SetChildBounds(aura::Window* child,
318 const gfx::Rect& requested_bounds) OVERRIDE {
319 SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size()));
323 aura::Window* owner_;
324 DISALLOW_COPY_AND_ASSIGN(FullscreenLayoutManager);
327 class MockWindowObserver : public aura::WindowObserver {
329 MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&));
334 // Checks that a fullscreen view has the correct show-state and receives the
336 TEST_F(RenderWidgetHostViewAuraTest, FocusFullscreen) {
337 view_->InitAsFullscreen(parent_view_);
338 aura::Window* window = view_->GetNativeView();
339 ASSERT_TRUE(window != NULL);
340 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN,
341 window->GetProperty(aura::client::kShowStateKey));
343 // Check that we requested and received the focus.
344 EXPECT_TRUE(window->HasFocus());
346 // Check that we'll also say it's okay to activate the window when there's an
347 // ActivationClient defined.
348 EXPECT_TRUE(view_->ShouldActivate());
351 // Checks that a popup is positioned correctly relative to its parent using
352 // screen coordinates.
353 TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) {
354 TestScreenPositionClient screen_position_client;
356 aura::Window* window = parent_view_->GetNativeView();
357 aura::Window* root = window->GetRootWindow();
358 aura::client::SetScreenPositionClient(root, &screen_position_client);
360 parent_view_->SetBounds(gfx::Rect(10, 10, 800, 600));
361 gfx::Rect bounds_in_screen = parent_view_->GetViewBounds();
362 int horiz = bounds_in_screen.width() / 4;
363 int vert = bounds_in_screen.height() / 4;
364 bounds_in_screen.Inset(horiz, vert);
366 // Verify that when the popup is initialized for the first time, it correctly
367 // treats the input bounds as screen coordinates.
368 view_->InitAsPopup(parent_view_, bounds_in_screen);
370 gfx::Rect final_bounds_in_screen = view_->GetViewBounds();
371 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString());
373 // Verify that directly setting the bounds via SetBounds() treats the input
374 // as screen coordinates.
375 bounds_in_screen = gfx::Rect(60, 60, 100, 100);
376 view_->SetBounds(bounds_in_screen);
377 final_bounds_in_screen = view_->GetViewBounds();
378 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString());
380 // Verify that setting the size does not alter the origin.
381 gfx::Point original_origin = window->bounds().origin();
382 view_->SetSize(gfx::Size(120, 120));
383 gfx::Point new_origin = window->bounds().origin();
384 EXPECT_EQ(original_origin.ToString(), new_origin.ToString());
386 aura::client::SetScreenPositionClient(root, NULL);
389 // Checks that a fullscreen view is destroyed when it loses the focus.
390 TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) {
391 view_->InitAsFullscreen(parent_view_);
392 aura::Window* window = view_->GetNativeView();
393 ASSERT_TRUE(window != NULL);
394 ASSERT_TRUE(window->HasFocus());
396 // After we create and focus another window, the RWHVA's window should be
398 TestWindowObserver observer(window);
399 aura::test::TestWindowDelegate delegate;
400 scoped_ptr<aura::Window> sibling(new aura::Window(&delegate));
401 sibling->Init(aura::WINDOW_LAYER_TEXTURED);
403 window->parent()->AddChild(sibling.get());
405 ASSERT_TRUE(sibling->HasFocus());
406 ASSERT_TRUE(observer.destroyed());
412 // Checks that a popup view is destroyed when a user clicks outside of the popup
413 // view and focus does not change. This is the case when the user clicks on the
414 // desktop background on Chrome OS.
415 TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupClickOutsidePopup) {
416 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400));
417 parent_view_->Focus();
418 EXPECT_TRUE(parent_view_->HasFocus());
420 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
421 aura::Window* window = view_->GetNativeView();
422 ASSERT_TRUE(window != NULL);
424 gfx::Point click_point;
425 EXPECT_FALSE(window->GetBoundsInRootWindow().Contains(click_point));
426 aura::Window* parent_window = parent_view_->GetNativeView();
427 EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(click_point));
429 TestWindowObserver observer(window);
430 aura::test::EventGenerator generator(window->GetRootWindow(), click_point);
431 generator.ClickLeftButton();
432 ASSERT_TRUE(parent_view_->HasFocus());
433 ASSERT_TRUE(observer.destroyed());
439 // Checks that a popup view is destroyed when a user taps outside of the popup
440 // view and focus does not change. This is the case when the user taps the
441 // desktop background on Chrome OS.
442 TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupTapOutsidePopup) {
443 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400));
444 parent_view_->Focus();
445 EXPECT_TRUE(parent_view_->HasFocus());
447 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
448 aura::Window* window = view_->GetNativeView();
449 ASSERT_TRUE(window != NULL);
451 gfx::Point tap_point;
452 EXPECT_FALSE(window->GetBoundsInRootWindow().Contains(tap_point));
453 aura::Window* parent_window = parent_view_->GetNativeView();
454 EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(tap_point));
456 TestWindowObserver observer(window);
457 aura::test::EventGenerator generator(window->GetRootWindow(), tap_point);
458 generator.GestureTapAt(tap_point);
459 ASSERT_TRUE(parent_view_->HasFocus());
460 ASSERT_TRUE(observer.destroyed());
466 // Checks that IME-composition-event state is maintained correctly.
467 TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
468 view_->InitAsChild(NULL);
471 ui::CompositionText composition_text;
472 composition_text.text = base::ASCIIToUTF16("|a|b");
475 composition_text.underlines.push_back(
476 ui::CompositionUnderline(0, 3, 0xff000000, true));
478 // Non-focused segment
479 composition_text.underlines.push_back(
480 ui::CompositionUnderline(3, 4, 0xff000000, false));
482 const ui::CompositionUnderlines& underlines = composition_text.underlines;
484 // Caret is at the end. (This emulates Japanese MSIME 2007 and later)
485 composition_text.selection = gfx::Range(4);
487 sink_->ClearMessages();
488 view_->SetCompositionText(composition_text);
489 EXPECT_TRUE(view_->has_composition_text_);
491 const IPC::Message* msg =
492 sink_->GetFirstMessageMatching(ViewMsg_ImeSetComposition::ID);
493 ASSERT_TRUE(msg != NULL);
495 ViewMsg_ImeSetComposition::Param params;
496 ViewMsg_ImeSetComposition::Read(msg, ¶ms);
498 EXPECT_EQ(composition_text.text, params.a);
500 ASSERT_EQ(underlines.size(), params.b.size());
501 for (size_t i = 0; i < underlines.size(); ++i) {
502 EXPECT_EQ(underlines[i].start_offset, params.b[i].startOffset);
503 EXPECT_EQ(underlines[i].end_offset, params.b[i].endOffset);
504 EXPECT_EQ(underlines[i].color, params.b[i].color);
505 EXPECT_EQ(underlines[i].thick, params.b[i].thick);
508 EXPECT_EQ(4, params.c) << "Should be the same to the caret pos";
509 EXPECT_EQ(4, params.d) << "Should be the same to the caret pos";
512 view_->ImeCancelComposition();
513 EXPECT_FALSE(view_->has_composition_text_);
516 // Checks that touch-event state is maintained correctly.
517 TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
518 view_->InitAsChild(NULL);
521 // Start with no touch-event handler in the renderer.
522 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
523 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
525 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
528 ui::EventTimeForNow());
529 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
532 ui::EventTimeForNow());
533 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
536 ui::EventTimeForNow());
538 view_->OnTouchEvent(&press);
539 EXPECT_FALSE(press.handled());
540 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
541 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
542 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
543 view_->touch_event_.touches[0].state);
545 view_->OnTouchEvent(&move);
546 EXPECT_FALSE(move.handled());
547 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
548 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
549 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
550 view_->touch_event_.touches[0].state);
552 view_->OnTouchEvent(&release);
553 EXPECT_FALSE(release.handled());
554 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
555 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
557 // Now install some touch-event handlers and do the same steps. The touch
558 // events should now be consumed. However, the touch-event state should be
559 // updated as before.
560 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
561 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
563 view_->OnTouchEvent(&press);
564 EXPECT_TRUE(press.stopped_propagation());
565 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
566 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
567 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
568 view_->touch_event_.touches[0].state);
570 view_->OnTouchEvent(&move);
571 EXPECT_TRUE(move.stopped_propagation());
572 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
573 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
574 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
575 view_->touch_event_.touches[0].state);
577 view_->OnTouchEvent(&release);
578 EXPECT_TRUE(release.stopped_propagation());
579 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
580 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
582 // Now start a touch event, and remove the event-handlers before the release.
583 view_->OnTouchEvent(&press);
584 EXPECT_TRUE(press.stopped_propagation());
585 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
586 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
587 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
588 view_->touch_event_.touches[0].state);
590 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
591 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
593 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0,
594 base::Time::NowFromSystemTime() - base::Time());
595 view_->OnTouchEvent(&move2);
596 EXPECT_FALSE(move2.handled());
597 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
598 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
599 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
600 view_->touch_event_.touches[0].state);
602 ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0,
603 base::Time::NowFromSystemTime() - base::Time());
604 view_->OnTouchEvent(&release2);
605 EXPECT_FALSE(release2.handled());
606 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
607 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
610 // Checks that touch-events are queued properly when there is a touch-event
611 // handler on the page.
612 TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) {
613 view_->InitAsChild(NULL);
616 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
617 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
619 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
622 ui::EventTimeForNow());
623 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
626 ui::EventTimeForNow());
627 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
630 ui::EventTimeForNow());
632 view_->OnTouchEvent(&press);
633 EXPECT_TRUE(press.stopped_propagation());
634 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
635 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
636 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
637 view_->touch_event_.touches[0].state);
639 view_->OnTouchEvent(&move);
640 EXPECT_TRUE(move.stopped_propagation());
641 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
642 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
643 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
644 view_->touch_event_.touches[0].state);
646 // Send the same move event. Since the point hasn't moved, it won't affect the
647 // queue. However, the view should consume the event.
648 view_->OnTouchEvent(&move);
649 EXPECT_TRUE(move.stopped_propagation());
650 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
651 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
652 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
653 view_->touch_event_.touches[0].state);
655 view_->OnTouchEvent(&release);
656 EXPECT_TRUE(release.stopped_propagation());
657 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
658 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
661 TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
662 view_->InitAsChild(NULL);
663 aura::client::ParentWindowWithContext(
664 view_->GetNativeView(),
665 parent_view_->GetNativeView()->GetRootWindow(),
667 sink_->ClearMessages();
668 view_->SetSize(gfx::Size(100, 100));
669 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
670 EXPECT_EQ(1u, sink_->message_count());
671 EXPECT_EQ(ViewMsg_Resize::ID, sink_->GetMessageAt(0)->type());
673 const IPC::Message* msg = sink_->GetMessageAt(0);
674 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
675 ViewMsg_Resize::Param params;
676 ViewMsg_Resize::Read(msg, ¶ms);
677 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
679 params.a.physical_backing_size.ToString()); // backing size
682 widget_host_->ResetSizeAndRepaintPendingFlags();
683 sink_->ClearMessages();
685 aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f);
686 EXPECT_EQ("200x200", view_->GetPhysicalBackingSize().ToString());
687 // Extra ScreenInfoChanged message for |parent_view_|.
688 EXPECT_EQ(1u, sink_->message_count());
690 const IPC::Message* msg = sink_->GetMessageAt(0);
691 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
692 ViewMsg_Resize::Param params;
693 ViewMsg_Resize::Read(msg, ¶ms);
694 EXPECT_EQ(2.0f, params.a.screen_info.deviceScaleFactor);
695 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
697 params.a.physical_backing_size.ToString()); // backing size
700 widget_host_->ResetSizeAndRepaintPendingFlags();
701 sink_->ClearMessages();
703 aura_test_helper_->test_screen()->SetDeviceScaleFactor(1.0f);
704 // Extra ScreenInfoChanged message for |parent_view_|.
705 EXPECT_EQ(1u, sink_->message_count());
706 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
708 const IPC::Message* msg = sink_->GetMessageAt(0);
709 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
710 ViewMsg_Resize::Param params;
711 ViewMsg_Resize::Read(msg, ¶ms);
712 EXPECT_EQ(1.0f, params.a.screen_info.deviceScaleFactor);
713 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
715 params.a.physical_backing_size.ToString()); // backing size
719 // Checks that InputMsg_CursorVisibilityChange IPC messages are dispatched
720 // to the renderer at the correct times.
721 TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
722 view_->InitAsChild(NULL);
723 aura::client::ParentWindowWithContext(
724 view_->GetNativeView(),
725 parent_view_->GetNativeView()->GetRootWindow(),
727 view_->SetSize(gfx::Size(100, 100));
729 aura::test::TestCursorClient cursor_client(
730 parent_view_->GetNativeView()->GetRootWindow());
732 cursor_client.AddObserver(view_);
734 // Expect a message the first time the cursor is shown.
736 sink_->ClearMessages();
737 cursor_client.ShowCursor();
738 EXPECT_EQ(1u, sink_->message_count());
739 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
740 InputMsg_CursorVisibilityChange::ID));
742 // No message expected if the renderer already knows the cursor is visible.
743 sink_->ClearMessages();
744 cursor_client.ShowCursor();
745 EXPECT_EQ(0u, sink_->message_count());
747 // Hiding the cursor should send a message.
748 sink_->ClearMessages();
749 cursor_client.HideCursor();
750 EXPECT_EQ(1u, sink_->message_count());
751 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
752 InputMsg_CursorVisibilityChange::ID));
754 // No message expected if the renderer already knows the cursor is invisible.
755 sink_->ClearMessages();
756 cursor_client.HideCursor();
757 EXPECT_EQ(0u, sink_->message_count());
759 // No messages should be sent while the view is invisible.
761 sink_->ClearMessages();
762 cursor_client.ShowCursor();
763 EXPECT_EQ(0u, sink_->message_count());
764 cursor_client.HideCursor();
765 EXPECT_EQ(0u, sink_->message_count());
767 // Show the view. Since the cursor was invisible when the view was hidden,
768 // no message should be sent.
769 sink_->ClearMessages();
771 EXPECT_FALSE(sink_->GetUniqueMessageMatching(
772 InputMsg_CursorVisibilityChange::ID));
774 // No message expected if the renderer already knows the cursor is invisible.
775 sink_->ClearMessages();
776 cursor_client.HideCursor();
777 EXPECT_EQ(0u, sink_->message_count());
779 // Showing the cursor should send a message.
780 sink_->ClearMessages();
781 cursor_client.ShowCursor();
782 EXPECT_EQ(1u, sink_->message_count());
783 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
784 InputMsg_CursorVisibilityChange::ID));
786 // No messages should be sent while the view is invisible.
788 sink_->ClearMessages();
789 cursor_client.HideCursor();
790 EXPECT_EQ(0u, sink_->message_count());
792 // Show the view. Since the cursor was visible when the view was hidden,
793 // a message is expected to be sent.
794 sink_->ClearMessages();
796 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
797 InputMsg_CursorVisibilityChange::ID));
799 cursor_client.RemoveObserver(view_);
802 TEST_F(RenderWidgetHostViewAuraTest, UpdateCursorIfOverSelf) {
803 view_->InitAsChild(NULL);
804 aura::client::ParentWindowWithContext(
805 view_->GetNativeView(),
806 parent_view_->GetNativeView()->GetRootWindow(),
809 // Note that all coordinates in this test are screen coordinates.
810 view_->SetBounds(gfx::Rect(60, 60, 100, 100));
813 aura::test::TestCursorClient cursor_client(
814 parent_view_->GetNativeView()->GetRootWindow());
816 // Cursor is in the middle of the window.
817 cursor_client.reset_calls_to_set_cursor();
818 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(110, 110));
819 view_->UpdateCursorIfOverSelf();
820 EXPECT_EQ(1, cursor_client.calls_to_set_cursor());
822 // Cursor is near the top of the window.
823 cursor_client.reset_calls_to_set_cursor();
824 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(80, 65));
825 view_->UpdateCursorIfOverSelf();
826 EXPECT_EQ(1, cursor_client.calls_to_set_cursor());
828 // Cursor is near the bottom of the window.
829 cursor_client.reset_calls_to_set_cursor();
830 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(159, 159));
831 view_->UpdateCursorIfOverSelf();
832 EXPECT_EQ(1, cursor_client.calls_to_set_cursor());
834 // Cursor is above the window.
835 cursor_client.reset_calls_to_set_cursor();
836 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(67, 59));
837 view_->UpdateCursorIfOverSelf();
838 EXPECT_EQ(0, cursor_client.calls_to_set_cursor());
840 // Cursor is below the window.
841 cursor_client.reset_calls_to_set_cursor();
842 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(161, 161));
843 view_->UpdateCursorIfOverSelf();
844 EXPECT_EQ(0, cursor_client.calls_to_set_cursor());
847 scoped_ptr<cc::CompositorFrame> MakeGLFrame(float scale_factor,
850 OwnedMailbox* owned_mailbox) {
851 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
852 frame->metadata.device_scale_factor = scale_factor;
853 frame->gl_frame_data.reset(new cc::GLFrameData);
854 DCHECK(owned_mailbox->sync_point());
855 frame->gl_frame_data->sync_point = owned_mailbox->sync_point();
856 memcpy(frame->gl_frame_data->mailbox.name,
857 owned_mailbox->mailbox().name,
858 sizeof(frame->gl_frame_data->mailbox.name));
859 frame->gl_frame_data->size = size;
860 frame->gl_frame_data->sub_buffer_rect = damage;
864 scoped_ptr<cc::CompositorFrame> MakeSoftwareFrame(float scale_factor,
867 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
868 frame->metadata.device_scale_factor = scale_factor;
869 frame->software_frame_data.reset(new cc::SoftwareFrameData);
870 frame->software_frame_data->id = 1;
871 frame->software_frame_data->size = size;
872 frame->software_frame_data->damage_rect = damage;
873 base::SharedMemory shm;
874 shm.CreateAndMapAnonymous(size.GetArea() * 4);
875 shm.GiveToProcess(base::GetCurrentProcessHandle(),
876 &frame->software_frame_data->handle);
880 scoped_ptr<cc::CompositorFrame> MakeDelegatedFrame(float scale_factor,
883 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
884 frame->metadata.device_scale_factor = scale_factor;
885 frame->delegated_frame_data.reset(new cc::DelegatedFrameData);
887 scoped_ptr<cc::RenderPass> pass = cc::RenderPass::Create();
888 pass->SetNew(cc::RenderPass::Id(1, 1),
892 frame->delegated_frame_data->render_pass_list.push_back(pass.Pass());
896 // Resizing in fullscreen mode should send the up-to-date screen info.
897 TEST_F(RenderWidgetHostViewAuraTest, FullscreenResize) {
898 aura::Window* root_window = aura_test_helper_->root_window();
899 root_window->SetLayoutManager(new FullscreenLayoutManager(root_window));
900 view_->InitAsFullscreen(parent_view_);
902 widget_host_->ResetSizeAndRepaintPendingFlags();
903 sink_->ClearMessages();
905 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
906 scoped_refptr<OwnedMailbox> owned_mailbox = new OwnedMailbox(gl_helper);
907 gl_helper->ResizeTexture(owned_mailbox->texture_id(), gfx::Size(1, 1));
908 owned_mailbox->UpdateSyncPoint(gl_helper->InsertSyncPoint());
910 // Call WasResized to flush the old screen info.
911 view_->GetRenderWidgetHost()->WasResized();
913 // 0 is CreatingNew message.
914 const IPC::Message* msg = sink_->GetMessageAt(0);
915 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
916 ViewMsg_Resize::Param params;
917 ViewMsg_Resize::Read(msg, ¶ms);
918 EXPECT_EQ("0,0 800x600",
919 gfx::Rect(params.a.screen_info.availableRect).ToString());
920 EXPECT_EQ("800x600", params.a.new_size.ToString());
921 // Resizes are blocked until we swapped a frame of the correct size, and
922 // we've committed it.
923 view_->OnSwapCompositorFrame(0,
926 gfx::Rect(params.a.new_size),
927 owned_mailbox.get()));
928 ui::DrawWaiterForTest::WaitForCommit(
929 root_window->GetHost()->compositor());
932 widget_host_->ResetSizeAndRepaintPendingFlags();
933 sink_->ClearMessages();
935 // Make sure the corrent screen size is set along in the resize
936 // request when the screen size has changed.
937 aura_test_helper_->test_screen()->SetUIScale(0.5);
938 EXPECT_EQ(1u, sink_->message_count());
940 const IPC::Message* msg = sink_->GetMessageAt(0);
941 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
942 ViewMsg_Resize::Param params;
943 ViewMsg_Resize::Read(msg, ¶ms);
944 EXPECT_EQ("0,0 1600x1200",
945 gfx::Rect(params.a.screen_info.availableRect).ToString());
946 EXPECT_EQ("1600x1200", params.a.new_size.ToString());
947 view_->OnSwapCompositorFrame(0,
950 gfx::Rect(params.a.new_size),
951 owned_mailbox.get()));
952 ui::DrawWaiterForTest::WaitForCommit(
953 root_window->GetHost()->compositor());
957 // Swapping a frame should notify the window.
958 TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) {
959 gfx::Size view_size(100, 100);
960 gfx::Rect view_rect(view_size);
962 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
963 scoped_refptr<OwnedMailbox> owned_mailbox = new OwnedMailbox(gl_helper);
964 gl_helper->ResizeTexture(owned_mailbox->texture_id(), gfx::Size(400, 400));
965 owned_mailbox->UpdateSyncPoint(gl_helper->InsertSyncPoint());
967 view_->InitAsChild(NULL);
968 aura::client::ParentWindowWithContext(
969 view_->GetNativeView(),
970 parent_view_->GetNativeView()->GetRootWindow(),
972 view_->SetSize(view_size);
975 MockWindowObserver observer;
976 view_->window_->AddObserver(&observer);
978 // Swap a frame through the GPU path.
979 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
980 params.surface_id = widget_host_->surface_id();
981 params.route_id = widget_host_->GetRoutingID();
982 memcpy(params.mailbox.name,
983 owned_mailbox->mailbox().name,
984 sizeof(params.mailbox.name));
985 params.size = view_size;
986 params.scale_factor = 1.f;
988 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
989 view_->AcceleratedSurfaceBuffersSwapped(params, 0);
990 testing::Mock::VerifyAndClearExpectations(&observer);
993 params.size = gfx::Size(200, 200);
994 params.scale_factor = 2.f;
995 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
996 view_->AcceleratedSurfaceBuffersSwapped(params, 0);
997 testing::Mock::VerifyAndClearExpectations(&observer);
999 // Partial frames though GPU path
1000 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params post_params;
1001 post_params.surface_id = widget_host_->surface_id();
1002 post_params.route_id = widget_host_->GetRoutingID();
1003 memcpy(post_params.mailbox.name,
1004 owned_mailbox->mailbox().name,
1005 sizeof(params.mailbox.name));
1006 post_params.surface_size = gfx::Size(200, 200);
1007 post_params.surface_scale_factor = 2.f;
1010 post_params.width = 80;
1011 post_params.height = 80;
1012 // rect from params is upside down, and is inflated in RWHVA, just because.
1013 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
1014 gfx::Rect(19, 39, 42, 42)));
1015 view_->AcceleratedSurfacePostSubBuffer(post_params, 0);
1016 testing::Mock::VerifyAndClearExpectations(&observer);
1018 // Composite-to-mailbox path
1019 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1020 view_->OnSwapCompositorFrame(
1021 0, MakeGLFrame(1.f, view_size, view_rect, owned_mailbox.get()));
1022 testing::Mock::VerifyAndClearExpectations(&observer);
1024 // rect from GL frame is upside down, and is inflated in RWHVA, just because.
1025 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
1026 gfx::Rect(4, 89, 7, 7)));
1027 view_->OnSwapCompositorFrame(
1029 MakeGLFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5), owned_mailbox.get()));
1030 testing::Mock::VerifyAndClearExpectations(&observer);
1033 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1034 view_->OnSwapCompositorFrame(0, MakeSoftwareFrame(1.f, view_size, view_rect));
1035 testing::Mock::VerifyAndClearExpectations(&observer);
1037 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
1038 gfx::Rect(5, 5, 5, 5)));
1039 view_->OnSwapCompositorFrame(
1040 0, MakeSoftwareFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5)));
1041 testing::Mock::VerifyAndClearExpectations(&observer);
1043 // Delegated renderer path
1044 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1045 view_->OnSwapCompositorFrame(
1046 0, MakeDelegatedFrame(1.f, view_size, view_rect));
1047 testing::Mock::VerifyAndClearExpectations(&observer);
1049 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
1050 gfx::Rect(5, 5, 5, 5)));
1051 view_->OnSwapCompositorFrame(
1052 0, MakeDelegatedFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5)));
1053 testing::Mock::VerifyAndClearExpectations(&observer);
1055 view_->window_->RemoveObserver(&observer);
1058 // Skipped frames should not drop their damage.
1059 TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
1060 gfx::Rect view_rect(100, 100);
1061 gfx::Size frame_size = view_rect.size();
1063 view_->InitAsChild(NULL);
1064 aura::client::ParentWindowWithContext(
1065 view_->GetNativeView(),
1066 parent_view_->GetNativeView()->GetRootWindow(),
1068 view_->SetSize(view_rect.size());
1070 MockWindowObserver observer;
1071 view_->window_->AddObserver(&observer);
1073 // A full frame of damage.
1074 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1075 view_->OnSwapCompositorFrame(
1076 0, MakeDelegatedFrame(1.f, frame_size, view_rect));
1077 testing::Mock::VerifyAndClearExpectations(&observer);
1078 view_->RunOnCompositingDidCommit();
1080 // A partial damage frame.
1081 gfx::Rect partial_view_rect(30, 30, 20, 20);
1082 EXPECT_CALL(observer,
1083 OnWindowPaintScheduled(view_->window_, partial_view_rect));
1084 view_->OnSwapCompositorFrame(
1085 0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect));
1086 testing::Mock::VerifyAndClearExpectations(&observer);
1087 view_->RunOnCompositingDidCommit();
1089 // Lock the compositor. Now we should drop frames.
1090 view_rect = gfx::Rect(150, 150);
1091 view_->SetSize(view_rect.size());
1092 view_->MaybeCreateResizeLock();
1094 // This frame is dropped.
1095 gfx::Rect dropped_damage_rect_1(10, 20, 30, 40);
1096 EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0);
1097 view_->OnSwapCompositorFrame(
1098 0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_1));
1099 testing::Mock::VerifyAndClearExpectations(&observer);
1100 view_->RunOnCompositingDidCommit();
1102 gfx::Rect dropped_damage_rect_2(40, 50, 10, 20);
1103 EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0);
1104 view_->OnSwapCompositorFrame(
1105 0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_2));
1106 testing::Mock::VerifyAndClearExpectations(&observer);
1107 view_->RunOnCompositingDidCommit();
1109 // Unlock the compositor. This frame should damage everything.
1110 frame_size = view_rect.size();
1112 gfx::Rect new_damage_rect(5, 6, 10, 10);
1113 EXPECT_CALL(observer,
1114 OnWindowPaintScheduled(view_->window_, view_rect));
1115 view_->OnSwapCompositorFrame(
1116 0, MakeDelegatedFrame(1.f, frame_size, new_damage_rect));
1117 testing::Mock::VerifyAndClearExpectations(&observer);
1118 view_->RunOnCompositingDidCommit();
1120 // A partial damage frame, this should not be dropped.
1121 EXPECT_CALL(observer,
1122 OnWindowPaintScheduled(view_->window_, partial_view_rect));
1123 view_->OnSwapCompositorFrame(
1124 0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect));
1125 testing::Mock::VerifyAndClearExpectations(&observer);
1126 view_->RunOnCompositingDidCommit();
1129 view_->window_->RemoveObserver(&observer);
1132 TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
1133 gfx::Rect view_rect(100, 100);
1134 gfx::Size frame_size = view_rect.size();
1136 view_->InitAsChild(NULL);
1137 aura::client::ParentWindowWithContext(
1138 view_->GetNativeView(),
1139 parent_view_->GetNativeView()->GetRootWindow(),
1141 view_->SetSize(view_rect.size());
1143 MockWindowObserver observer;
1144 view_->window_->AddObserver(&observer);
1147 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1148 view_->OnSwapCompositorFrame(
1149 0, MakeDelegatedFrame(1.f, frame_size, view_rect));
1150 testing::Mock::VerifyAndClearExpectations(&observer);
1151 view_->RunOnCompositingDidCommit();
1153 // Swap a frame with a different surface id.
1154 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1155 view_->OnSwapCompositorFrame(
1156 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1157 testing::Mock::VerifyAndClearExpectations(&observer);
1158 view_->RunOnCompositingDidCommit();
1160 // Swap an empty frame, with a different surface id.
1161 view_->OnSwapCompositorFrame(
1162 2, MakeDelegatedFrame(1.f, gfx::Size(), gfx::Rect()));
1163 testing::Mock::VerifyAndClearExpectations(&observer);
1164 view_->RunOnCompositingDidCommit();
1166 // Swap another frame, with a different surface id.
1167 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1168 view_->OnSwapCompositorFrame(3,
1169 MakeDelegatedFrame(1.f, frame_size, view_rect));
1170 testing::Mock::VerifyAndClearExpectations(&observer);
1171 view_->RunOnCompositingDidCommit();
1173 view_->window_->RemoveObserver(&observer);
1176 TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
1177 size_t max_renderer_frames =
1178 RendererFrameManager::GetInstance()->max_number_of_saved_frames();
1179 ASSERT_LE(2u, max_renderer_frames);
1180 size_t renderer_count = max_renderer_frames + 1;
1181 gfx::Rect view_rect(100, 100);
1182 gfx::Size frame_size = view_rect.size();
1183 DCHECK_EQ(0u, HostSharedBitmapManager::current()->AllocatedBitmapCount());
1185 scoped_ptr<RenderWidgetHostImpl * []> hosts(
1186 new RenderWidgetHostImpl* [renderer_count]);
1187 scoped_ptr<FakeRenderWidgetHostViewAura * []> views(
1188 new FakeRenderWidgetHostViewAura* [renderer_count]);
1190 // Create a bunch of renderers.
1191 for (size_t i = 0; i < renderer_count; ++i) {
1192 hosts[i] = new RenderWidgetHostImpl(
1193 &delegate_, process_host_, MSG_ROUTING_NONE, false);
1195 hosts[i]->OnMessageReceived(
1196 ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
1197 views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
1198 views[i]->InitAsChild(NULL);
1199 aura::client::ParentWindowWithContext(
1200 views[i]->GetNativeView(),
1201 parent_view_->GetNativeView()->GetRootWindow(),
1203 views[i]->SetSize(view_rect.size());
1206 // Make each renderer visible, and swap a frame on it, then make it invisible.
1207 for (size_t i = 0; i < renderer_count; ++i) {
1208 views[i]->WasShown();
1209 views[i]->OnSwapCompositorFrame(
1210 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1211 EXPECT_TRUE(views[i]->frame_provider_);
1212 views[i]->WasHidden();
1215 // There should be max_renderer_frames with a frame in it, and one without it.
1216 // Since the logic is LRU eviction, the first one should be without.
1217 EXPECT_FALSE(views[0]->frame_provider_);
1218 for (size_t i = 1; i < renderer_count; ++i)
1219 EXPECT_TRUE(views[i]->frame_provider_);
1221 // LRU renderer is [0], make it visible, it shouldn't evict anything yet.
1222 views[0]->WasShown();
1223 EXPECT_FALSE(views[0]->frame_provider_);
1224 EXPECT_TRUE(views[1]->frame_provider_);
1226 // Swap a frame on it, it should evict the next LRU [1].
1227 views[0]->OnSwapCompositorFrame(
1228 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1229 EXPECT_TRUE(views[0]->frame_provider_);
1230 EXPECT_FALSE(views[1]->frame_provider_);
1231 views[0]->WasHidden();
1233 // LRU renderer is [1], still hidden. Swap a frame on it, it should evict
1234 // the next LRU [2].
1235 views[1]->OnSwapCompositorFrame(
1236 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1237 EXPECT_TRUE(views[0]->frame_provider_);
1238 EXPECT_TRUE(views[1]->frame_provider_);
1239 EXPECT_FALSE(views[2]->frame_provider_);
1240 for (size_t i = 3; i < renderer_count; ++i)
1241 EXPECT_TRUE(views[i]->frame_provider_);
1243 // Make all renderers but [0] visible and swap a frame on them, keep [0]
1244 // hidden, it becomes the LRU.
1245 for (size_t i = 1; i < renderer_count; ++i) {
1246 views[i]->WasShown();
1247 views[i]->OnSwapCompositorFrame(
1248 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1249 EXPECT_TRUE(views[i]->frame_provider_);
1251 EXPECT_FALSE(views[0]->frame_provider_);
1253 // Swap a frame on [0], it should be evicted immediately.
1254 views[0]->OnSwapCompositorFrame(
1255 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1256 EXPECT_FALSE(views[0]->frame_provider_);
1258 // Make [0] visible, and swap a frame on it. Nothing should be evicted
1259 // although we're above the limit.
1260 views[0]->WasShown();
1261 views[0]->OnSwapCompositorFrame(
1262 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1263 for (size_t i = 0; i < renderer_count; ++i)
1264 EXPECT_TRUE(views[i]->frame_provider_);
1266 // Make [0] hidden, it should evict its frame.
1267 views[0]->WasHidden();
1268 EXPECT_FALSE(views[0]->frame_provider_);
1270 for (size_t i = 0; i < renderer_count - 1; ++i)
1271 views[i]->WasHidden();
1273 // Allocate enough bitmaps so that two frames (proportionally) would be
1274 // enough hit the handle limit.
1275 int handles_per_frame = 5;
1276 RendererFrameManager::GetInstance()->set_max_handles(handles_per_frame * 2);
1278 for (size_t i = 0; i < (renderer_count - 1) * handles_per_frame; i++) {
1279 HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap(
1281 base::SharedMemory::NULLHandle(),
1282 base::GetCurrentProcessHandle(),
1283 cc::SharedBitmap::GenerateId());
1286 // Hiding this last bitmap should evict all but two frames.
1287 views[renderer_count - 1]->WasHidden();
1288 for (size_t i = 0; i < renderer_count; ++i) {
1289 if (i + 2 < renderer_count)
1290 EXPECT_FALSE(views[i]->frame_provider_);
1292 EXPECT_TRUE(views[i]->frame_provider_);
1294 HostSharedBitmapManager::current()->ProcessRemoved(
1295 base::GetCurrentProcessHandle());
1296 RendererFrameManager::GetInstance()->set_max_handles(
1297 base::SharedMemory::GetHandleLimit());
1299 for (size_t i = 0; i < renderer_count; ++i) {
1300 views[i]->Destroy();
1305 TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
1306 size_t max_renderer_frames =
1307 RendererFrameManager::GetInstance()->max_number_of_saved_frames();
1308 ASSERT_LE(2u, max_renderer_frames);
1309 size_t renderer_count = max_renderer_frames + 1;
1310 gfx::Rect view_rect(100, 100);
1311 gfx::Size frame_size = view_rect.size();
1312 DCHECK_EQ(0u, HostSharedBitmapManager::current()->AllocatedBitmapCount());
1314 scoped_ptr<RenderWidgetHostImpl * []> hosts(
1315 new RenderWidgetHostImpl* [renderer_count]);
1316 scoped_ptr<FakeRenderWidgetHostViewAura * []> views(
1317 new FakeRenderWidgetHostViewAura* [renderer_count]);
1319 // Create a bunch of renderers.
1320 for (size_t i = 0; i < renderer_count; ++i) {
1321 hosts[i] = new RenderWidgetHostImpl(
1322 &delegate_, process_host_, MSG_ROUTING_NONE, false);
1324 hosts[i]->OnMessageReceived(
1325 ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
1326 views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
1327 views[i]->InitAsChild(NULL);
1328 aura::client::ParentWindowWithContext(
1329 views[i]->GetNativeView(),
1330 parent_view_->GetNativeView()->GetRootWindow(),
1332 views[i]->SetSize(view_rect.size());
1335 // Make each renderer visible and swap a frame on it. No eviction should
1336 // occur because all frames are visible.
1337 for (size_t i = 0; i < renderer_count; ++i) {
1338 views[i]->WasShown();
1339 views[i]->OnSwapCompositorFrame(
1340 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1341 EXPECT_TRUE(views[i]->frame_provider_);
1344 // If we hide [0], then [0] should be evicted.
1345 views[0]->WasHidden();
1346 EXPECT_FALSE(views[0]->frame_provider_);
1348 // If we lock [0] before hiding it, then [0] should not be evicted.
1349 views[0]->WasShown();
1350 views[0]->OnSwapCompositorFrame(
1351 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1352 EXPECT_TRUE(views[0]->frame_provider_);
1353 views[0]->LockResources();
1354 views[0]->WasHidden();
1355 EXPECT_TRUE(views[0]->frame_provider_);
1357 // If we unlock [0] now, then [0] should be evicted.
1358 views[0]->UnlockResources();
1359 EXPECT_FALSE(views[0]->frame_provider_);
1361 for (size_t i = 0; i < renderer_count; ++i) {
1362 views[i]->Destroy();
1367 TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
1368 gfx::Rect view_rect(100, 100);
1369 gfx::Size frame_size(100, 100);
1371 view_->InitAsChild(NULL);
1372 aura::client::ParentWindowWithContext(
1373 view_->GetNativeView(),
1374 parent_view_->GetNativeView()->GetRootWindow(),
1376 view_->SetSize(view_rect.size());
1379 // With a 1x DPI UI and 1x DPI Renderer.
1380 view_->OnSwapCompositorFrame(
1381 1, MakeDelegatedFrame(1.f, frame_size, gfx::Rect(frame_size)));
1383 // Save the frame provider.
1384 scoped_refptr<cc::DelegatedFrameProvider> frame_provider =
1385 view_->frame_provider_;
1387 // This frame will have the same number of physical pixels, but has a new
1389 view_->OnSwapCompositorFrame(
1390 1, MakeDelegatedFrame(2.f, frame_size, gfx::Rect(frame_size)));
1392 // When we get a new frame with the same frame size in physical pixels, but a
1393 // different scale, we should generate a new frame provider, as the final
1394 // result will need to be scaled differently to the screen.
1395 EXPECT_NE(frame_provider.get(), view_->frame_provider_.get());
1398 class RenderWidgetHostViewAuraCopyRequestTest
1399 : public RenderWidgetHostViewAuraShutdownTest {
1401 RenderWidgetHostViewAuraCopyRequestTest()
1402 : callback_count_(0), result_(false) {}
1404 void CallbackMethod(const base::Closure& quit_closure, bool result) {
1410 int callback_count_;
1414 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraCopyRequestTest);
1417 TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
1418 base::RunLoop run_loop;
1420 gfx::Rect view_rect(100, 100);
1421 scoped_ptr<cc::CopyOutputRequest> request;
1423 view_->InitAsChild(NULL);
1424 aura::client::ParentWindowWithContext(
1425 view_->GetNativeView(),
1426 parent_view_->GetNativeView()->GetRootWindow(),
1428 view_->SetSize(view_rect.size());
1431 scoped_ptr<FakeFrameSubscriber> frame_subscriber(new FakeFrameSubscriber(
1433 base::Bind(&RenderWidgetHostViewAuraCopyRequestTest::CallbackMethod,
1434 base::Unretained(this),
1435 run_loop.QuitClosure())));
1437 EXPECT_EQ(0, callback_count_);
1438 EXPECT_FALSE(view_->last_copy_request_);
1440 view_->BeginFrameSubscription(
1441 frame_subscriber.PassAs<RenderWidgetHostViewFrameSubscriber>());
1442 view_->OnSwapCompositorFrame(
1443 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
1445 EXPECT_EQ(0, callback_count_);
1446 EXPECT_TRUE(view_->last_copy_request_);
1447 EXPECT_TRUE(view_->last_copy_request_->has_texture_mailbox());
1448 request = view_->last_copy_request_.Pass();
1450 // There should be one subscriber texture in flight.
1451 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size());
1453 // Send back the mailbox included in the request. There's no release callback
1454 // since the mailbox came from the RWHVA originally.
1455 request->SendTextureResult(view_rect.size(),
1456 request->texture_mailbox(),
1457 scoped_ptr<cc::SingleReleaseCallback>());
1459 // This runs until the callback happens.
1462 // The callback should succeed.
1463 EXPECT_EQ(0u, view_->active_frame_subscriber_textures_.size());
1464 EXPECT_EQ(1, callback_count_);
1465 EXPECT_TRUE(result_);
1467 view_->OnSwapCompositorFrame(
1468 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
1470 EXPECT_EQ(1, callback_count_);
1471 request = view_->last_copy_request_.Pass();
1473 // There should be one subscriber texture in flight again.
1474 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size());
1476 // Destroy the RenderWidgetHostViewAura and ImageTransportFactory.
1477 TearDownEnvironment();
1479 // Send back the mailbox included in the request. There's no release callback
1480 // since the mailbox came from the RWHVA originally.
1481 request->SendTextureResult(view_rect.size(),
1482 request->texture_mailbox(),
1483 scoped_ptr<cc::SingleReleaseCallback>());
1485 // Because the copy request callback may be holding state within it, that
1486 // state must handle the RWHVA and ImageTransportFactory going away before the
1487 // callback is called. This test passes if it does not crash as a result of
1488 // these things being destroyed.
1489 EXPECT_EQ(2, callback_count_);
1490 EXPECT_FALSE(result_);
1493 } // namespace content