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/resize_lock.h"
18 #include "content/browser/renderer_host/render_widget_host_delegate.h"
19 #include "content/browser/renderer_host/render_widget_host_impl.h"
20 #include "content/common/gpu/gpu_messages.h"
21 #include "content/common/input_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
24 #include "content/public/browser/render_widget_host_view.h"
25 #include "content/public/test/mock_render_process_host.h"
26 #include "content/public/test/test_browser_context.h"
27 #include "ipc/ipc_test_sink.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "ui/aura/client/aura_constants.h"
31 #include "ui/aura/client/screen_position_client.h"
32 #include "ui/aura/client/window_tree_client.h"
33 #include "ui/aura/env.h"
34 #include "ui/aura/layout_manager.h"
35 #include "ui/aura/root_window.h"
36 #include "ui/aura/test/aura_test_helper.h"
37 #include "ui/aura/test/event_generator.h"
38 #include "ui/aura/test/test_cursor_client.h"
39 #include "ui/aura/test/test_screen.h"
40 #include "ui/aura/test/test_window_delegate.h"
41 #include "ui/aura/window.h"
42 #include "ui/aura/window_observer.h"
43 #include "ui/base/ui_base_types.h"
44 #include "ui/compositor/compositor.h"
45 #include "ui/compositor/test/draw_waiter_for_test.h"
46 #include "ui/compositor/test/test_context_factory.h"
47 #include "ui/events/event.h"
48 #include "ui/events/event_utils.h"
55 // Simple screen position client to test coordinate system conversion.
56 class TestScreenPositionClient
57 : public aura::client::ScreenPositionClient {
59 TestScreenPositionClient() {}
60 virtual ~TestScreenPositionClient() {}
62 // aura::client::ScreenPositionClient overrides:
63 virtual void ConvertPointToScreen(const aura::Window* window,
64 gfx::Point* point) OVERRIDE {
65 point->Offset(-1, -1);
68 virtual void ConvertPointFromScreen(const aura::Window* window,
69 gfx::Point* point) OVERRIDE {
73 virtual void ConvertHostPointToScreen(aura::Window* window,
74 gfx::Point* point) OVERRIDE {
75 ConvertPointToScreen(window, point);
78 virtual void SetBounds(aura::Window* window,
79 const gfx::Rect& bounds,
80 const gfx::Display& display) OVERRIDE {
84 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
86 MockRenderWidgetHostDelegate() {}
87 virtual ~MockRenderWidgetHostDelegate() {}
90 // Simple observer that keeps track of changes to a window for tests.
91 class TestWindowObserver : public aura::WindowObserver {
93 explicit TestWindowObserver(aura::Window* window_to_observe)
94 : window_(window_to_observe) {
95 window_->AddObserver(this);
97 virtual ~TestWindowObserver() {
99 window_->RemoveObserver(this);
102 bool destroyed() const { return destroyed_; }
104 // aura::WindowObserver overrides:
105 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
106 CHECK_EQ(window, window_);
112 // Window that we're observing, or NULL if it's been destroyed.
113 aura::Window* window_;
115 // Was |window_| destroyed?
118 DISALLOW_COPY_AND_ASSIGN(TestWindowObserver);
121 class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
123 FakeFrameSubscriber(gfx::Size size, base::Callback<void(bool)> callback)
124 : size_(size), callback_(callback) {}
126 virtual bool ShouldCaptureFrame(base::TimeTicks present_time,
127 scoped_refptr<media::VideoFrame>* storage,
128 DeliverFrameCallback* callback) OVERRIDE {
129 *storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
134 *callback = base::Bind(&FakeFrameSubscriber::CallbackMethod, callback_);
138 static void CallbackMethod(base::Callback<void(bool)> callback,
139 base::TimeTicks timestamp,
141 callback.Run(success);
146 base::Callback<void(bool)> callback_;
149 class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
151 FakeRenderWidgetHostViewAura(RenderWidgetHost* widget)
152 : RenderWidgetHostViewAura(widget), has_resize_lock_(false) {}
154 virtual ~FakeRenderWidgetHostViewAura() {}
156 virtual bool ShouldCreateResizeLock() OVERRIDE {
157 gfx::Size desired_size = window()->bounds().size();
158 return desired_size != current_frame_size();
161 virtual scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock)
163 gfx::Size desired_size = window()->bounds().size();
164 return scoped_ptr<ResizeLock>(
165 new FakeResizeLock(desired_size, defer_compositor_lock));
168 virtual void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request)
170 last_copy_request_ = request.Pass();
173 void RunOnCompositingDidCommit() {
174 OnCompositingDidCommit(window()->GetDispatcher()->host()->compositor());
177 // A lock that doesn't actually do anything to the compositor, and does not
179 class FakeResizeLock : public ResizeLock {
181 FakeResizeLock(const gfx::Size new_size, bool defer_compositor_lock)
182 : ResizeLock(new_size, defer_compositor_lock) {}
185 bool has_resize_lock_;
186 gfx::Size last_frame_size_;
187 scoped_ptr<cc::CopyOutputRequest> last_copy_request_;
190 class RenderWidgetHostViewAuraTest : public testing::Test {
192 RenderWidgetHostViewAuraTest()
193 : browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {}
195 void SetUpEnvironment() {
196 ImageTransportFactory::InitializeForUnitTests(
197 scoped_ptr<ui::ContextFactory>(new ui::TestContextFactory));
198 aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
199 bool allow_test_contexts = true;
200 aura_test_helper_->SetUp(allow_test_contexts);
202 browser_context_.reset(new TestBrowserContext);
203 process_host_ = new MockRenderProcessHost(browser_context_.get());
205 sink_ = &process_host_->sink();
207 parent_host_ = new RenderWidgetHostImpl(
208 &delegate_, process_host_, MSG_ROUTING_NONE, false);
209 parent_view_ = static_cast<RenderWidgetHostViewAura*>(
210 RenderWidgetHostView::CreateViewForWidget(parent_host_));
211 parent_view_->InitAsChild(NULL);
212 aura::client::ParentWindowWithContext(parent_view_->GetNativeView(),
213 aura_test_helper_->root_window(),
216 widget_host_ = new RenderWidgetHostImpl(
217 &delegate_, process_host_, MSG_ROUTING_NONE, false);
218 widget_host_->Init();
219 widget_host_->OnMessageReceived(
220 ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
221 view_ = new FakeRenderWidgetHostViewAura(widget_host_);
224 void TearDownEnvironment() {
226 process_host_ = NULL;
231 parent_view_->Destroy();
234 browser_context_.reset();
235 aura_test_helper_->TearDown();
237 message_loop_.DeleteSoon(FROM_HERE, browser_context_.release());
238 message_loop_.RunUntilIdle();
239 ImageTransportFactory::Terminate();
242 virtual void SetUp() { SetUpEnvironment(); }
244 virtual void TearDown() { TearDownEnvironment(); }
247 base::MessageLoopForUI message_loop_;
248 BrowserThreadImpl browser_thread_for_ui_;
249 scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
250 scoped_ptr<BrowserContext> browser_context_;
251 MockRenderWidgetHostDelegate delegate_;
252 MockRenderProcessHost* process_host_;
254 // Tests should set these to NULL if they've already triggered their
256 RenderWidgetHostImpl* parent_host_;
257 RenderWidgetHostViewAura* parent_view_;
259 // Tests should set these to NULL if they've already triggered their
261 RenderWidgetHostImpl* widget_host_;
262 FakeRenderWidgetHostViewAura* view_;
264 IPC::TestSink* sink_;
267 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest);
270 class RenderWidgetHostViewAuraShutdownTest
271 : public RenderWidgetHostViewAuraTest {
273 RenderWidgetHostViewAuraShutdownTest() {}
275 virtual void TearDown() OVERRIDE {
276 // No TearDownEnvironment here, we do this explicitly during the test.
280 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest);
283 // A layout manager that always resizes a child to the root window size.
284 class FullscreenLayoutManager : public aura::LayoutManager {
286 explicit FullscreenLayoutManager(aura::Window* owner)
288 virtual ~FullscreenLayoutManager() {}
290 // Overridden from aura::LayoutManager:
291 virtual void OnWindowResized() OVERRIDE {
292 aura::Window::Windows::const_iterator i;
293 for (i = owner_->children().begin(); i != owner_->children().end(); ++i) {
294 (*i)->SetBounds(gfx::Rect());
297 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
298 child->SetBounds(gfx::Rect());
300 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {
302 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {
304 virtual void OnChildWindowVisibilityChanged(aura::Window* child,
305 bool visible) OVERRIDE {
307 virtual void SetChildBounds(aura::Window* child,
308 const gfx::Rect& requested_bounds) OVERRIDE {
309 SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size()));
313 aura::Window* owner_;
314 DISALLOW_COPY_AND_ASSIGN(FullscreenLayoutManager);
317 class MockWindowObserver : public aura::WindowObserver {
319 MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&));
324 // Checks that a fullscreen view has the correct show-state and receives the
326 TEST_F(RenderWidgetHostViewAuraTest, FocusFullscreen) {
327 view_->InitAsFullscreen(parent_view_);
328 aura::Window* window = view_->GetNativeView();
329 ASSERT_TRUE(window != NULL);
330 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN,
331 window->GetProperty(aura::client::kShowStateKey));
333 // Check that we requested and received the focus.
334 EXPECT_TRUE(window->HasFocus());
336 // Check that we'll also say it's okay to activate the window when there's an
337 // ActivationClient defined.
338 EXPECT_TRUE(view_->ShouldActivate());
341 // Checks that a popup is positioned correctly relative to its parent using
342 // screen coordinates.
343 TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) {
344 TestScreenPositionClient screen_position_client;
346 aura::Window* window = parent_view_->GetNativeView();
347 aura::Window* root = window->GetRootWindow();
348 aura::client::SetScreenPositionClient(root, &screen_position_client);
350 parent_view_->SetBounds(gfx::Rect(10, 10, 800, 600));
351 gfx::Rect bounds_in_screen = parent_view_->GetViewBounds();
352 int horiz = bounds_in_screen.width() / 4;
353 int vert = bounds_in_screen.height() / 4;
354 bounds_in_screen.Inset(horiz, vert);
356 // Verify that when the popup is initialized for the first time, it correctly
357 // treats the input bounds as screen coordinates.
358 view_->InitAsPopup(parent_view_, bounds_in_screen);
360 gfx::Rect final_bounds_in_screen = view_->GetViewBounds();
361 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString());
363 // Verify that directly setting the bounds via SetBounds() treats the input
364 // as screen coordinates.
365 bounds_in_screen = gfx::Rect(60, 60, 100, 100);
366 view_->SetBounds(bounds_in_screen);
367 final_bounds_in_screen = view_->GetViewBounds();
368 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString());
370 // Verify that setting the size does not alter the origin.
371 gfx::Point original_origin = window->bounds().origin();
372 view_->SetSize(gfx::Size(120, 120));
373 gfx::Point new_origin = window->bounds().origin();
374 EXPECT_EQ(original_origin.ToString(), new_origin.ToString());
376 aura::client::SetScreenPositionClient(root, NULL);
379 // Checks that a fullscreen view is destroyed when it loses the focus.
380 TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) {
381 view_->InitAsFullscreen(parent_view_);
382 aura::Window* window = view_->GetNativeView();
383 ASSERT_TRUE(window != NULL);
384 ASSERT_TRUE(window->HasFocus());
386 // After we create and focus another window, the RWHVA's window should be
388 TestWindowObserver observer(window);
389 aura::test::TestWindowDelegate delegate;
390 scoped_ptr<aura::Window> sibling(new aura::Window(&delegate));
391 sibling->Init(aura::WINDOW_LAYER_TEXTURED);
393 window->parent()->AddChild(sibling.get());
395 ASSERT_TRUE(sibling->HasFocus());
396 ASSERT_TRUE(observer.destroyed());
402 // Checks that a popup view is destroyed when a user clicks outside of the popup
403 // view and focus does not change. This is the case when the user clicks on the
404 // desktop background on Chrome OS.
405 TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupClickOutsidePopup) {
406 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400));
407 parent_view_->Focus();
408 EXPECT_TRUE(parent_view_->HasFocus());
410 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
411 aura::Window* window = view_->GetNativeView();
412 ASSERT_TRUE(window != NULL);
414 gfx::Point click_point;
415 EXPECT_FALSE(window->GetBoundsInRootWindow().Contains(click_point));
416 aura::Window* parent_window = parent_view_->GetNativeView();
417 EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(click_point));
419 TestWindowObserver observer(window);
420 aura::test::EventGenerator generator(window->GetRootWindow(), click_point);
421 generator.ClickLeftButton();
422 ASSERT_TRUE(parent_view_->HasFocus());
423 ASSERT_TRUE(observer.destroyed());
429 // Checks that a popup view is destroyed when a user taps outside of the popup
430 // view and focus does not change. This is the case when the user taps the
431 // desktop background on Chrome OS.
432 TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupTapOutsidePopup) {
433 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400));
434 parent_view_->Focus();
435 EXPECT_TRUE(parent_view_->HasFocus());
437 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
438 aura::Window* window = view_->GetNativeView();
439 ASSERT_TRUE(window != NULL);
441 gfx::Point tap_point;
442 EXPECT_FALSE(window->GetBoundsInRootWindow().Contains(tap_point));
443 aura::Window* parent_window = parent_view_->GetNativeView();
444 EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(tap_point));
446 TestWindowObserver observer(window);
447 aura::test::EventGenerator generator(window->GetRootWindow(), tap_point);
448 generator.GestureTapAt(tap_point);
449 ASSERT_TRUE(parent_view_->HasFocus());
450 ASSERT_TRUE(observer.destroyed());
456 // Checks that IME-composition-event state is maintained correctly.
457 TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
458 view_->InitAsChild(NULL);
461 ui::CompositionText composition_text;
462 composition_text.text = base::ASCIIToUTF16("|a|b");
465 composition_text.underlines.push_back(
466 ui::CompositionUnderline(0, 3, 0xff000000, true));
468 // Non-focused segment
469 composition_text.underlines.push_back(
470 ui::CompositionUnderline(3, 4, 0xff000000, false));
472 const ui::CompositionUnderlines& underlines = composition_text.underlines;
474 // Caret is at the end. (This emulates Japanese MSIME 2007 and later)
475 composition_text.selection = gfx::Range(4);
477 sink_->ClearMessages();
478 view_->SetCompositionText(composition_text);
479 EXPECT_TRUE(view_->has_composition_text_);
481 const IPC::Message* msg =
482 sink_->GetFirstMessageMatching(ViewMsg_ImeSetComposition::ID);
483 ASSERT_TRUE(msg != NULL);
485 ViewMsg_ImeSetComposition::Param params;
486 ViewMsg_ImeSetComposition::Read(msg, ¶ms);
488 EXPECT_EQ(composition_text.text, params.a);
490 ASSERT_EQ(underlines.size(), params.b.size());
491 for (size_t i = 0; i < underlines.size(); ++i) {
492 EXPECT_EQ(underlines[i].start_offset, params.b[i].startOffset);
493 EXPECT_EQ(underlines[i].end_offset, params.b[i].endOffset);
494 EXPECT_EQ(underlines[i].color, params.b[i].color);
495 EXPECT_EQ(underlines[i].thick, params.b[i].thick);
498 EXPECT_EQ(4, params.c) << "Should be the same to the caret pos";
499 EXPECT_EQ(4, params.d) << "Should be the same to the caret pos";
502 view_->ImeCancelComposition();
503 EXPECT_FALSE(view_->has_composition_text_);
506 // Checks that touch-event state is maintained correctly.
507 TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
508 view_->InitAsChild(NULL);
511 // Start with no touch-event handler in the renderer.
512 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
513 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
515 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
518 ui::EventTimeForNow());
519 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
522 ui::EventTimeForNow());
523 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
526 ui::EventTimeForNow());
528 view_->OnTouchEvent(&press);
529 EXPECT_FALSE(press.handled());
530 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
531 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
532 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
533 view_->touch_event_.touches[0].state);
535 view_->OnTouchEvent(&move);
536 EXPECT_FALSE(move.handled());
537 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
538 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
539 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
540 view_->touch_event_.touches[0].state);
542 view_->OnTouchEvent(&release);
543 EXPECT_FALSE(release.handled());
544 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
545 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
547 // Now install some touch-event handlers and do the same steps. The touch
548 // events should now be consumed. However, the touch-event state should be
549 // updated as before.
550 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
551 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
553 view_->OnTouchEvent(&press);
554 EXPECT_TRUE(press.stopped_propagation());
555 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
556 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
557 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
558 view_->touch_event_.touches[0].state);
560 view_->OnTouchEvent(&move);
561 EXPECT_TRUE(move.stopped_propagation());
562 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
563 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
564 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
565 view_->touch_event_.touches[0].state);
567 view_->OnTouchEvent(&release);
568 EXPECT_TRUE(release.stopped_propagation());
569 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
570 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
572 // Now start a touch event, and remove the event-handlers before the release.
573 view_->OnTouchEvent(&press);
574 EXPECT_TRUE(press.stopped_propagation());
575 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
576 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
577 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
578 view_->touch_event_.touches[0].state);
580 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
581 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
583 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0,
584 base::Time::NowFromSystemTime() - base::Time());
585 view_->OnTouchEvent(&move2);
586 EXPECT_FALSE(move2.handled());
587 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
588 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
589 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
590 view_->touch_event_.touches[0].state);
592 ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0,
593 base::Time::NowFromSystemTime() - base::Time());
594 view_->OnTouchEvent(&release2);
595 EXPECT_FALSE(release2.handled());
596 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
597 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
600 // Checks that touch-events are queued properly when there is a touch-event
601 // handler on the page.
602 TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) {
603 view_->InitAsChild(NULL);
606 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
607 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
609 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
612 ui::EventTimeForNow());
613 ui::TouchEvent move(ui::ET_TOUCH_MOVED,
616 ui::EventTimeForNow());
617 ui::TouchEvent release(ui::ET_TOUCH_RELEASED,
620 ui::EventTimeForNow());
622 view_->OnTouchEvent(&press);
623 EXPECT_TRUE(press.stopped_propagation());
624 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type);
625 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
626 EXPECT_EQ(blink::WebTouchPoint::StatePressed,
627 view_->touch_event_.touches[0].state);
629 view_->OnTouchEvent(&move);
630 EXPECT_TRUE(move.stopped_propagation());
631 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
632 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
633 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
634 view_->touch_event_.touches[0].state);
636 // Send the same move event. Since the point hasn't moved, it won't affect the
637 // queue. However, the view should consume the event.
638 view_->OnTouchEvent(&move);
639 EXPECT_TRUE(move.stopped_propagation());
640 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type);
641 EXPECT_EQ(1U, view_->touch_event_.touchesLength);
642 EXPECT_EQ(blink::WebTouchPoint::StateMoved,
643 view_->touch_event_.touches[0].state);
645 view_->OnTouchEvent(&release);
646 EXPECT_TRUE(release.stopped_propagation());
647 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type);
648 EXPECT_EQ(0U, view_->touch_event_.touchesLength);
651 TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) {
652 view_->InitAsChild(NULL);
653 aura::client::ParentWindowWithContext(
654 view_->GetNativeView(),
655 parent_view_->GetNativeView()->GetRootWindow(),
657 sink_->ClearMessages();
658 view_->SetSize(gfx::Size(100, 100));
659 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
660 EXPECT_EQ(1u, sink_->message_count());
661 EXPECT_EQ(ViewMsg_Resize::ID, sink_->GetMessageAt(0)->type());
663 const IPC::Message* msg = sink_->GetMessageAt(0);
664 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
665 ViewMsg_Resize::Param params;
666 ViewMsg_Resize::Read(msg, ¶ms);
667 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
669 params.a.physical_backing_size.ToString()); // backing size
672 widget_host_->ResetSizeAndRepaintPendingFlags();
673 sink_->ClearMessages();
675 aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f);
676 EXPECT_EQ("200x200", view_->GetPhysicalBackingSize().ToString());
677 // Extra ScreenInfoChanged message for |parent_view_|.
678 EXPECT_EQ(1u, sink_->message_count());
680 const IPC::Message* msg = sink_->GetMessageAt(0);
681 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
682 ViewMsg_Resize::Param params;
683 ViewMsg_Resize::Read(msg, ¶ms);
684 EXPECT_EQ(2.0f, params.a.screen_info.deviceScaleFactor);
685 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
687 params.a.physical_backing_size.ToString()); // backing size
690 widget_host_->ResetSizeAndRepaintPendingFlags();
691 sink_->ClearMessages();
693 aura_test_helper_->test_screen()->SetDeviceScaleFactor(1.0f);
694 // Extra ScreenInfoChanged message for |parent_view_|.
695 EXPECT_EQ(1u, sink_->message_count());
696 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString());
698 const IPC::Message* msg = sink_->GetMessageAt(0);
699 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
700 ViewMsg_Resize::Param params;
701 ViewMsg_Resize::Read(msg, ¶ms);
702 EXPECT_EQ(1.0f, params.a.screen_info.deviceScaleFactor);
703 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size
705 params.a.physical_backing_size.ToString()); // backing size
709 // Checks that InputMsg_CursorVisibilityChange IPC messages are dispatched
710 // to the renderer at the correct times.
711 TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) {
712 view_->InitAsChild(NULL);
713 aura::client::ParentWindowWithContext(
714 view_->GetNativeView(),
715 parent_view_->GetNativeView()->GetRootWindow(),
717 view_->SetSize(gfx::Size(100, 100));
719 aura::test::TestCursorClient cursor_client(
720 parent_view_->GetNativeView()->GetRootWindow());
722 cursor_client.AddObserver(view_);
724 // Expect a message the first time the cursor is shown.
726 sink_->ClearMessages();
727 cursor_client.ShowCursor();
728 EXPECT_EQ(1u, sink_->message_count());
729 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
730 InputMsg_CursorVisibilityChange::ID));
732 // No message expected if the renderer already knows the cursor is visible.
733 sink_->ClearMessages();
734 cursor_client.ShowCursor();
735 EXPECT_EQ(0u, sink_->message_count());
737 // Hiding the cursor should send a message.
738 sink_->ClearMessages();
739 cursor_client.HideCursor();
740 EXPECT_EQ(1u, sink_->message_count());
741 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
742 InputMsg_CursorVisibilityChange::ID));
744 // No message expected if the renderer already knows the cursor is invisible.
745 sink_->ClearMessages();
746 cursor_client.HideCursor();
747 EXPECT_EQ(0u, sink_->message_count());
749 // No messages should be sent while the view is invisible.
751 sink_->ClearMessages();
752 cursor_client.ShowCursor();
753 EXPECT_EQ(0u, sink_->message_count());
754 cursor_client.HideCursor();
755 EXPECT_EQ(0u, sink_->message_count());
757 // Show the view. Since the cursor was invisible when the view was hidden,
758 // no message should be sent.
759 sink_->ClearMessages();
761 EXPECT_FALSE(sink_->GetUniqueMessageMatching(
762 InputMsg_CursorVisibilityChange::ID));
764 // No message expected if the renderer already knows the cursor is invisible.
765 sink_->ClearMessages();
766 cursor_client.HideCursor();
767 EXPECT_EQ(0u, sink_->message_count());
769 // Showing the cursor should send a message.
770 sink_->ClearMessages();
771 cursor_client.ShowCursor();
772 EXPECT_EQ(1u, sink_->message_count());
773 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
774 InputMsg_CursorVisibilityChange::ID));
776 // No messages should be sent while the view is invisible.
778 sink_->ClearMessages();
779 cursor_client.HideCursor();
780 EXPECT_EQ(0u, sink_->message_count());
782 // Show the view. Since the cursor was visible when the view was hidden,
783 // a message is expected to be sent.
784 sink_->ClearMessages();
786 EXPECT_TRUE(sink_->GetUniqueMessageMatching(
787 InputMsg_CursorVisibilityChange::ID));
789 cursor_client.RemoveObserver(view_);
792 TEST_F(RenderWidgetHostViewAuraTest, UpdateCursorIfOverSelf) {
793 view_->InitAsChild(NULL);
794 aura::client::ParentWindowWithContext(
795 view_->GetNativeView(),
796 parent_view_->GetNativeView()->GetRootWindow(),
799 // Note that all coordinates in this test are screen coordinates.
800 view_->SetBounds(gfx::Rect(60, 60, 100, 100));
803 aura::test::TestCursorClient cursor_client(
804 parent_view_->GetNativeView()->GetRootWindow());
806 // Cursor is in the middle of the window.
807 cursor_client.reset_calls_to_set_cursor();
808 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(110, 110));
809 view_->UpdateCursorIfOverSelf();
810 EXPECT_EQ(1, cursor_client.calls_to_set_cursor());
812 // Cursor is near the top of the window.
813 cursor_client.reset_calls_to_set_cursor();
814 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(80, 65));
815 view_->UpdateCursorIfOverSelf();
816 EXPECT_EQ(1, cursor_client.calls_to_set_cursor());
818 // Cursor is near the bottom of the window.
819 cursor_client.reset_calls_to_set_cursor();
820 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(159, 159));
821 view_->UpdateCursorIfOverSelf();
822 EXPECT_EQ(1, cursor_client.calls_to_set_cursor());
824 // Cursor is above the window.
825 cursor_client.reset_calls_to_set_cursor();
826 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(67, 59));
827 view_->UpdateCursorIfOverSelf();
828 EXPECT_EQ(0, cursor_client.calls_to_set_cursor());
830 // Cursor is below the window.
831 cursor_client.reset_calls_to_set_cursor();
832 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(161, 161));
833 view_->UpdateCursorIfOverSelf();
834 EXPECT_EQ(0, cursor_client.calls_to_set_cursor());
837 scoped_ptr<cc::CompositorFrame> MakeGLFrame(float scale_factor,
840 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
841 frame->metadata.device_scale_factor = scale_factor;
842 frame->gl_frame_data.reset(new cc::GLFrameData);
843 frame->gl_frame_data->sync_point = 1;
844 memset(frame->gl_frame_data->mailbox.name,
846 sizeof(frame->gl_frame_data->mailbox.name));
847 frame->gl_frame_data->size = size;
848 frame->gl_frame_data->sub_buffer_rect = damage;
852 scoped_ptr<cc::CompositorFrame> MakeSoftwareFrame(float scale_factor,
855 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
856 frame->metadata.device_scale_factor = scale_factor;
857 frame->software_frame_data.reset(new cc::SoftwareFrameData);
858 frame->software_frame_data->id = 1;
859 frame->software_frame_data->size = size;
860 frame->software_frame_data->damage_rect = damage;
861 base::SharedMemory shm;
862 shm.CreateAndMapAnonymous(size.GetArea() * 4);
863 shm.GiveToProcess(base::GetCurrentProcessHandle(),
864 &frame->software_frame_data->handle);
868 scoped_ptr<cc::CompositorFrame> MakeDelegatedFrame(float scale_factor,
871 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
872 frame->metadata.device_scale_factor = scale_factor;
873 frame->delegated_frame_data.reset(new cc::DelegatedFrameData);
875 scoped_ptr<cc::RenderPass> pass = cc::RenderPass::Create();
876 pass->SetNew(cc::RenderPass::Id(1, 1),
880 frame->delegated_frame_data->render_pass_list.push_back(pass.Pass());
884 // Resizing in fullscreen mode should send the up-to-date screen info.
885 TEST_F(RenderWidgetHostViewAuraTest, FullscreenResize) {
886 aura::Window* root_window = aura_test_helper_->root_window();
887 root_window->SetLayoutManager(new FullscreenLayoutManager(root_window));
888 view_->InitAsFullscreen(parent_view_);
890 widget_host_->ResetSizeAndRepaintPendingFlags();
891 sink_->ClearMessages();
893 // Call WasResized to flush the old screen info.
894 view_->GetRenderWidgetHost()->WasResized();
896 // 0 is CreatingNew message.
897 const IPC::Message* msg = sink_->GetMessageAt(0);
898 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
899 ViewMsg_Resize::Param params;
900 ViewMsg_Resize::Read(msg, ¶ms);
901 EXPECT_EQ("0,0 800x600",
902 gfx::Rect(params.a.screen_info.availableRect).ToString());
903 EXPECT_EQ("800x600", params.a.new_size.ToString());
904 // Resizes are blocked until we swapped a frame of the correct size, and
905 // we've committed it.
906 view_->OnSwapCompositorFrame(
907 0, MakeGLFrame(1.f, params.a.new_size, gfx::Rect(params.a.new_size)));
908 ui::DrawWaiterForTest::WaitForCommit(
909 root_window->GetDispatcher()->host()->compositor());
912 widget_host_->ResetSizeAndRepaintPendingFlags();
913 sink_->ClearMessages();
915 // Make sure the corrent screen size is set along in the resize
916 // request when the screen size has changed.
917 aura_test_helper_->test_screen()->SetUIScale(0.5);
918 EXPECT_EQ(1u, sink_->message_count());
920 const IPC::Message* msg = sink_->GetMessageAt(0);
921 EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
922 ViewMsg_Resize::Param params;
923 ViewMsg_Resize::Read(msg, ¶ms);
924 EXPECT_EQ("0,0 1600x1200",
925 gfx::Rect(params.a.screen_info.availableRect).ToString());
926 EXPECT_EQ("1600x1200", params.a.new_size.ToString());
927 view_->OnSwapCompositorFrame(
928 0, MakeGLFrame(1.f, params.a.new_size, gfx::Rect(params.a.new_size)));
929 ui::DrawWaiterForTest::WaitForCommit(
930 root_window->GetDispatcher()->host()->compositor());
934 // Swapping a frame should notify the window.
935 TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) {
936 gfx::Size view_size(100, 100);
937 gfx::Rect view_rect(view_size);
939 view_->InitAsChild(NULL);
940 aura::client::ParentWindowWithContext(
941 view_->GetNativeView(),
942 parent_view_->GetNativeView()->GetRootWindow(),
944 view_->SetSize(view_size);
947 MockWindowObserver observer;
948 view_->window_->AddObserver(&observer);
950 // Swap a frame through the GPU path.
951 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
952 params.surface_id = widget_host_->surface_id();
953 params.route_id = widget_host_->GetRoutingID();
954 memset(params.mailbox.name, '1', sizeof(params.mailbox.name));
955 params.size = view_size;
956 params.scale_factor = 1.f;
958 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
959 view_->AcceleratedSurfaceBuffersSwapped(params, 0);
960 testing::Mock::VerifyAndClearExpectations(&observer);
963 params.size = gfx::Size(200, 200);
964 params.scale_factor = 2.f;
965 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
966 view_->AcceleratedSurfaceBuffersSwapped(params, 0);
967 testing::Mock::VerifyAndClearExpectations(&observer);
969 // Partial frames though GPU path
970 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params post_params;
971 post_params.surface_id = widget_host_->surface_id();
972 post_params.route_id = widget_host_->GetRoutingID();
973 memset(post_params.mailbox.name, '1', sizeof(post_params.mailbox.name));
974 post_params.surface_size = gfx::Size(200, 200);
975 post_params.surface_scale_factor = 2.f;
978 post_params.width = 80;
979 post_params.height = 80;
980 // rect from params is upside down, and is inflated in RWHVA, just because.
981 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
982 gfx::Rect(19, 39, 42, 42)));
983 view_->AcceleratedSurfacePostSubBuffer(post_params, 0);
984 testing::Mock::VerifyAndClearExpectations(&observer);
986 // Composite-to-mailbox path
987 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
988 view_->OnSwapCompositorFrame(0, MakeGLFrame(1.f, view_size, view_rect));
989 testing::Mock::VerifyAndClearExpectations(&observer);
991 // rect from GL frame is upside down, and is inflated in RWHVA, just because.
992 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
993 gfx::Rect(4, 89, 7, 7)));
994 view_->OnSwapCompositorFrame(
995 0, MakeGLFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5)));
996 testing::Mock::VerifyAndClearExpectations(&observer);
999 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1000 view_->OnSwapCompositorFrame(0, MakeSoftwareFrame(1.f, view_size, view_rect));
1001 testing::Mock::VerifyAndClearExpectations(&observer);
1003 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
1004 gfx::Rect(5, 5, 5, 5)));
1005 view_->OnSwapCompositorFrame(
1006 0, MakeSoftwareFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5)));
1007 testing::Mock::VerifyAndClearExpectations(&observer);
1009 // Delegated renderer path
1010 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1011 view_->OnSwapCompositorFrame(
1012 0, MakeDelegatedFrame(1.f, view_size, view_rect));
1013 testing::Mock::VerifyAndClearExpectations(&observer);
1015 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
1016 gfx::Rect(5, 5, 5, 5)));
1017 view_->OnSwapCompositorFrame(
1018 0, MakeDelegatedFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5)));
1019 testing::Mock::VerifyAndClearExpectations(&observer);
1021 view_->window_->RemoveObserver(&observer);
1024 // Skipped frames should not drop their damage.
1025 TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
1026 gfx::Rect view_rect(100, 100);
1027 gfx::Size frame_size = view_rect.size();
1029 view_->InitAsChild(NULL);
1030 aura::client::ParentWindowWithContext(
1031 view_->GetNativeView(),
1032 parent_view_->GetNativeView()->GetRootWindow(),
1034 view_->SetSize(view_rect.size());
1036 MockWindowObserver observer;
1037 view_->window_->AddObserver(&observer);
1039 // A full frame of damage.
1040 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1041 view_->OnSwapCompositorFrame(
1042 0, MakeDelegatedFrame(1.f, frame_size, view_rect));
1043 testing::Mock::VerifyAndClearExpectations(&observer);
1044 view_->RunOnCompositingDidCommit();
1046 // A partial damage frame.
1047 gfx::Rect partial_view_rect(30, 30, 20, 20);
1048 EXPECT_CALL(observer,
1049 OnWindowPaintScheduled(view_->window_, partial_view_rect));
1050 view_->OnSwapCompositorFrame(
1051 0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect));
1052 testing::Mock::VerifyAndClearExpectations(&observer);
1053 view_->RunOnCompositingDidCommit();
1055 // Lock the compositor. Now we should drop frames.
1056 view_rect = gfx::Rect(150, 150);
1057 view_->SetSize(view_rect.size());
1058 view_->MaybeCreateResizeLock();
1060 // This frame is dropped.
1061 gfx::Rect dropped_damage_rect_1(10, 20, 30, 40);
1062 EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0);
1063 view_->OnSwapCompositorFrame(
1064 0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_1));
1065 testing::Mock::VerifyAndClearExpectations(&observer);
1066 view_->RunOnCompositingDidCommit();
1068 gfx::Rect dropped_damage_rect_2(40, 50, 10, 20);
1069 EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0);
1070 view_->OnSwapCompositorFrame(
1071 0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_2));
1072 testing::Mock::VerifyAndClearExpectations(&observer);
1073 view_->RunOnCompositingDidCommit();
1075 // Unlock the compositor. This frame should damage everything.
1076 frame_size = view_rect.size();
1078 gfx::Rect new_damage_rect(5, 6, 10, 10);
1079 EXPECT_CALL(observer,
1080 OnWindowPaintScheduled(view_->window_, view_rect));
1081 view_->OnSwapCompositorFrame(
1082 0, MakeDelegatedFrame(1.f, frame_size, new_damage_rect));
1083 testing::Mock::VerifyAndClearExpectations(&observer);
1084 view_->RunOnCompositingDidCommit();
1086 // A partial damage frame, this should not be dropped.
1087 EXPECT_CALL(observer,
1088 OnWindowPaintScheduled(view_->window_, partial_view_rect));
1089 view_->OnSwapCompositorFrame(
1090 0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect));
1091 testing::Mock::VerifyAndClearExpectations(&observer);
1092 view_->RunOnCompositingDidCommit();
1095 view_->window_->RemoveObserver(&observer);
1098 TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
1099 gfx::Rect view_rect(100, 100);
1100 gfx::Size frame_size = view_rect.size();
1102 view_->InitAsChild(NULL);
1103 aura::client::ParentWindowWithContext(
1104 view_->GetNativeView(),
1105 parent_view_->GetNativeView()->GetRootWindow(),
1107 view_->SetSize(view_rect.size());
1109 MockWindowObserver observer;
1110 view_->window_->AddObserver(&observer);
1113 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1114 view_->OnSwapCompositorFrame(
1115 0, MakeDelegatedFrame(1.f, frame_size, view_rect));
1116 testing::Mock::VerifyAndClearExpectations(&observer);
1117 view_->RunOnCompositingDidCommit();
1119 // Swap a frame with a different surface id.
1120 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1121 view_->OnSwapCompositorFrame(
1122 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1123 testing::Mock::VerifyAndClearExpectations(&observer);
1124 view_->RunOnCompositingDidCommit();
1126 // Swap an empty frame, with a different surface id.
1127 view_->OnSwapCompositorFrame(
1128 2, MakeDelegatedFrame(1.f, gfx::Size(), gfx::Rect()));
1129 testing::Mock::VerifyAndClearExpectations(&observer);
1130 view_->RunOnCompositingDidCommit();
1132 // Swap another frame, with a different surface id.
1133 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
1134 view_->OnSwapCompositorFrame(3,
1135 MakeDelegatedFrame(1.f, frame_size, view_rect));
1136 testing::Mock::VerifyAndClearExpectations(&observer);
1137 view_->RunOnCompositingDidCommit();
1139 view_->window_->RemoveObserver(&observer);
1142 TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
1143 size_t max_renderer_frames =
1144 RendererFrameManager::GetInstance()->max_number_of_saved_frames();
1145 ASSERT_LE(2u, max_renderer_frames);
1146 size_t renderer_count = max_renderer_frames + 1;
1147 gfx::Rect view_rect(100, 100);
1148 gfx::Size frame_size = view_rect.size();
1150 scoped_ptr<RenderWidgetHostImpl * []> hosts(
1151 new RenderWidgetHostImpl* [renderer_count]);
1152 scoped_ptr<FakeRenderWidgetHostViewAura * []> views(
1153 new FakeRenderWidgetHostViewAura* [renderer_count]);
1155 // Create a bunch of renderers.
1156 for (size_t i = 0; i < renderer_count; ++i) {
1157 hosts[i] = new RenderWidgetHostImpl(
1158 &delegate_, process_host_, MSG_ROUTING_NONE, false);
1160 hosts[i]->OnMessageReceived(
1161 ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
1162 views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
1163 views[i]->InitAsChild(NULL);
1164 aura::client::ParentWindowWithContext(
1165 views[i]->GetNativeView(),
1166 parent_view_->GetNativeView()->GetRootWindow(),
1168 views[i]->SetSize(view_rect.size());
1171 // Make each renderer visible, and swap a frame on it, then make it invisible.
1172 for (size_t i = 0; i < renderer_count; ++i) {
1173 views[i]->WasShown();
1174 views[i]->OnSwapCompositorFrame(
1175 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1176 EXPECT_TRUE(views[i]->frame_provider_);
1177 views[i]->WasHidden();
1180 // There should be max_renderer_frames with a frame in it, and one without it.
1181 // Since the logic is LRU eviction, the first one should be without.
1182 EXPECT_FALSE(views[0]->frame_provider_);
1183 for (size_t i = 1; i < renderer_count; ++i)
1184 EXPECT_TRUE(views[i]->frame_provider_);
1186 // LRU renderer is [0], make it visible, it shouldn't evict anything yet.
1187 views[0]->WasShown();
1188 EXPECT_FALSE(views[0]->frame_provider_);
1189 EXPECT_TRUE(views[1]->frame_provider_);
1191 // Swap a frame on it, it should evict the next LRU [1].
1192 views[0]->OnSwapCompositorFrame(
1193 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1194 EXPECT_TRUE(views[0]->frame_provider_);
1195 EXPECT_FALSE(views[1]->frame_provider_);
1196 views[0]->WasHidden();
1198 // LRU renderer is [1], still hidden. Swap a frame on it, it should evict
1199 // the next LRU [2].
1200 views[1]->OnSwapCompositorFrame(
1201 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1202 EXPECT_TRUE(views[0]->frame_provider_);
1203 EXPECT_TRUE(views[1]->frame_provider_);
1204 EXPECT_FALSE(views[2]->frame_provider_);
1205 for (size_t i = 3; i < renderer_count; ++i)
1206 EXPECT_TRUE(views[i]->frame_provider_);
1208 // Make all renderers but [0] visible and swap a frame on them, keep [0]
1209 // hidden, it becomes the LRU.
1210 for (size_t i = 1; i < renderer_count; ++i) {
1211 views[i]->WasShown();
1212 views[i]->OnSwapCompositorFrame(
1213 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1214 EXPECT_TRUE(views[i]->frame_provider_);
1216 EXPECT_FALSE(views[0]->frame_provider_);
1218 // Swap a frame on [0], it should be evicted immediately.
1219 views[0]->OnSwapCompositorFrame(
1220 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1221 EXPECT_FALSE(views[0]->frame_provider_);
1223 // Make [0] visible, and swap a frame on it. Nothing should be evicted
1224 // although we're above the limit.
1225 views[0]->WasShown();
1226 views[0]->OnSwapCompositorFrame(
1227 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1228 for (size_t i = 0; i < renderer_count; ++i)
1229 EXPECT_TRUE(views[i]->frame_provider_);
1231 // Make [0] hidden, it should evict its frame.
1232 views[0]->WasHidden();
1233 EXPECT_FALSE(views[0]->frame_provider_);
1235 for (size_t i = 0; i < renderer_count; ++i) {
1236 views[i]->Destroy();
1241 TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
1242 size_t max_renderer_frames =
1243 RendererFrameManager::GetInstance()->max_number_of_saved_frames();
1244 ASSERT_LE(2u, max_renderer_frames);
1245 size_t renderer_count = max_renderer_frames + 1;
1246 gfx::Rect view_rect(100, 100);
1247 gfx::Size frame_size = view_rect.size();
1249 scoped_ptr<RenderWidgetHostImpl * []> hosts(
1250 new RenderWidgetHostImpl* [renderer_count]);
1251 scoped_ptr<FakeRenderWidgetHostViewAura * []> views(
1252 new FakeRenderWidgetHostViewAura* [renderer_count]);
1254 // Create a bunch of renderers.
1255 for (size_t i = 0; i < renderer_count; ++i) {
1256 hosts[i] = new RenderWidgetHostImpl(
1257 &delegate_, process_host_, MSG_ROUTING_NONE, false);
1259 hosts[i]->OnMessageReceived(
1260 ViewHostMsg_DidActivateAcceleratedCompositing(0, true));
1261 views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
1262 views[i]->InitAsChild(NULL);
1263 aura::client::ParentWindowWithContext(
1264 views[i]->GetNativeView(),
1265 parent_view_->GetNativeView()->GetRootWindow(),
1267 views[i]->SetSize(view_rect.size());
1270 // Make each renderer visible and swap a frame on it. No eviction should
1271 // occur because all frames are visible.
1272 for (size_t i = 0; i < renderer_count; ++i) {
1273 views[i]->WasShown();
1274 views[i]->OnSwapCompositorFrame(
1275 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1276 EXPECT_TRUE(views[i]->frame_provider_);
1279 // If we hide [0], then [0] should be evicted.
1280 views[0]->WasHidden();
1281 EXPECT_FALSE(views[0]->frame_provider_);
1283 // If we lock [0] before hiding it, then [0] should not be evicted.
1284 views[0]->WasShown();
1285 views[0]->OnSwapCompositorFrame(
1286 1, MakeDelegatedFrame(1.f, frame_size, view_rect));
1287 EXPECT_TRUE(views[0]->frame_provider_);
1288 views[0]->LockResources();
1289 views[0]->WasHidden();
1290 EXPECT_TRUE(views[0]->frame_provider_);
1292 // If we unlock [0] now, then [0] should be evicted.
1293 views[0]->UnlockResources();
1294 EXPECT_FALSE(views[0]->frame_provider_);
1296 for (size_t i = 0; i < renderer_count; ++i) {
1297 views[i]->Destroy();
1302 TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
1303 gfx::Rect view_rect(100, 100);
1304 gfx::Size frame_size(100, 100);
1306 view_->InitAsChild(NULL);
1307 aura::client::ParentWindowWithContext(
1308 view_->GetNativeView(),
1309 parent_view_->GetNativeView()->GetRootWindow(),
1311 view_->SetSize(view_rect.size());
1314 // With a 1x DPI UI and 1x DPI Renderer.
1315 view_->OnSwapCompositorFrame(
1316 1, MakeDelegatedFrame(1.f, frame_size, gfx::Rect(frame_size)));
1318 // Save the frame provider.
1319 scoped_refptr<cc::DelegatedFrameProvider> frame_provider =
1320 view_->frame_provider_;
1322 // This frame will have the same number of physical pixels, but has a new
1324 view_->OnSwapCompositorFrame(
1325 1, MakeDelegatedFrame(2.f, frame_size, gfx::Rect(frame_size)));
1327 // When we get a new frame with the same frame size in physical pixels, but a
1328 // different scale, we should generate a new frame provider, as the final
1329 // result will need to be scaled differently to the screen.
1330 EXPECT_NE(frame_provider.get(), view_->frame_provider_.get());
1333 class RenderWidgetHostViewAuraCopyRequestTest
1334 : public RenderWidgetHostViewAuraShutdownTest {
1336 RenderWidgetHostViewAuraCopyRequestTest()
1337 : callback_count_(0), result_(false) {}
1339 void CallbackMethod(bool result) {
1344 int callback_count_;
1348 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraCopyRequestTest);
1351 TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
1352 gfx::Rect view_rect(100, 100);
1353 scoped_ptr<cc::CopyOutputRequest> request;
1355 view_->InitAsChild(NULL);
1356 aura::client::ParentWindowWithContext(
1357 view_->GetNativeView(),
1358 parent_view_->GetNativeView()->GetRootWindow(),
1360 view_->SetSize(view_rect.size());
1363 scoped_ptr<FakeFrameSubscriber> frame_subscriber(new FakeFrameSubscriber(
1365 base::Bind(&RenderWidgetHostViewAuraCopyRequestTest::CallbackMethod,
1366 base::Unretained(this))));
1368 EXPECT_EQ(0, callback_count_);
1369 EXPECT_FALSE(view_->last_copy_request_);
1371 view_->BeginFrameSubscription(
1372 frame_subscriber.PassAs<RenderWidgetHostViewFrameSubscriber>());
1373 view_->OnSwapCompositorFrame(
1374 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
1376 EXPECT_EQ(0, callback_count_);
1377 EXPECT_TRUE(view_->last_copy_request_);
1378 EXPECT_TRUE(view_->last_copy_request_->has_texture_mailbox());
1379 request = view_->last_copy_request_.Pass();
1381 // There should be one subscriber texture in flight.
1382 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size());
1384 // Send back the mailbox included in the request. There's no release callback
1385 // since the mailbox came from the RWHVA originally.
1386 request->SendTextureResult(view_rect.size(),
1387 request->texture_mailbox(),
1388 scoped_ptr<cc::SingleReleaseCallback>());
1390 base::RunLoop run_loop;
1391 run_loop.RunUntilIdle();
1393 // The callback should succeed.
1394 EXPECT_EQ(0u, view_->active_frame_subscriber_textures_.size());
1395 EXPECT_EQ(1, callback_count_);
1396 EXPECT_TRUE(result_);
1398 view_->OnSwapCompositorFrame(
1399 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
1401 EXPECT_EQ(1, callback_count_);
1402 request = view_->last_copy_request_.Pass();
1404 // There should be one subscriber texture in flight again.
1405 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size());
1407 // Destroy the RenderWidgetHostViewAura and ImageTransportFactory.
1408 TearDownEnvironment();
1410 // Send back the mailbox included in the request. There's no release callback
1411 // since the mailbox came from the RWHVA originally.
1412 request->SendTextureResult(view_rect.size(),
1413 request->texture_mailbox(),
1414 scoped_ptr<cc::SingleReleaseCallback>());
1416 // Because the copy request callback may be holding state within it, that
1417 // state must handle the RWHVA and ImageTransportFactory going away before the
1418 // callback is called. This test passes if it does not crash as a result of
1419 // these things being destroyed.
1420 EXPECT_EQ(2, callback_count_);
1421 EXPECT_FALSE(result_);
1424 } // namespace content