render_widget_host_view_aura_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/renderer_host/render_widget_host_view_aura.h" 6 7#include "base/basictypes.h" 8#include "base/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" 49 50using testing::_; 51 52namespace content { 53namespace { 54 55// Simple screen position client to test coordinate system conversion. 56class TestScreenPositionClient 57 : public aura::client::ScreenPositionClient { 58 public: 59 TestScreenPositionClient() {} 60 virtual ~TestScreenPositionClient() {} 61 62 // aura::client::ScreenPositionClient overrides: 63 virtual void ConvertPointToScreen(const aura::Window* window, 64 gfx::Point* point) OVERRIDE { 65 point->Offset(-1, -1); 66 } 67 68 virtual void ConvertPointFromScreen(const aura::Window* window, 69 gfx::Point* point) OVERRIDE { 70 point->Offset(1, 1); 71 } 72 73 virtual void ConvertHostPointToScreen(aura::Window* window, 74 gfx::Point* point) OVERRIDE { 75 ConvertPointToScreen(window, point); 76 } 77 78 virtual void SetBounds(aura::Window* window, 79 const gfx::Rect& bounds, 80 const gfx::Display& display) OVERRIDE { 81 } 82}; 83 84class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { 85 public: 86 MockRenderWidgetHostDelegate() {} 87 virtual ~MockRenderWidgetHostDelegate() {} 88}; 89 90// Simple observer that keeps track of changes to a window for tests. 91class TestWindowObserver : public aura::WindowObserver { 92 public: 93 explicit TestWindowObserver(aura::Window* window_to_observe) 94 : window_(window_to_observe) { 95 window_->AddObserver(this); 96 } 97 virtual ~TestWindowObserver() { 98 if (window_) 99 window_->RemoveObserver(this); 100 } 101 102 bool destroyed() const { return destroyed_; } 103 104 // aura::WindowObserver overrides: 105 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 106 CHECK_EQ(window, window_); 107 destroyed_ = true; 108 window_ = NULL; 109 } 110 111 private: 112 // Window that we're observing, or NULL if it's been destroyed. 113 aura::Window* window_; 114 115 // Was |window_| destroyed? 116 bool destroyed_; 117 118 DISALLOW_COPY_AND_ASSIGN(TestWindowObserver); 119}; 120 121class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 122 public: 123 FakeFrameSubscriber(gfx::Size size, base::Callback<void(bool)> callback) 124 : size_(size), callback_(callback) {} 125 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, 130 size_, 131 gfx::Rect(size_), 132 size_, 133 base::TimeDelta()); 134 *callback = base::Bind(&FakeFrameSubscriber::CallbackMethod, callback_); 135 return true; 136 } 137 138 static void CallbackMethod(base::Callback<void(bool)> callback, 139 base::TimeTicks timestamp, 140 bool success) { 141 callback.Run(success); 142 } 143 144 private: 145 gfx::Size size_; 146 base::Callback<void(bool)> callback_; 147}; 148 149class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { 150 public: 151 FakeRenderWidgetHostViewAura(RenderWidgetHost* widget) 152 : RenderWidgetHostViewAura(widget), has_resize_lock_(false) {} 153 154 virtual ~FakeRenderWidgetHostViewAura() {} 155 156 virtual bool ShouldCreateResizeLock() OVERRIDE { 157 gfx::Size desired_size = window()->bounds().size(); 158 return desired_size != current_frame_size(); 159 } 160 161 virtual scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock) 162 OVERRIDE { 163 gfx::Size desired_size = window()->bounds().size(); 164 return scoped_ptr<ResizeLock>( 165 new FakeResizeLock(desired_size, defer_compositor_lock)); 166 } 167 168 virtual void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request) 169 OVERRIDE { 170 last_copy_request_ = request.Pass(); 171 } 172 173 void RunOnCompositingDidCommit() { 174 OnCompositingDidCommit(window()->GetDispatcher()->host()->compositor()); 175 } 176 177 // A lock that doesn't actually do anything to the compositor, and does not 178 // time out. 179 class FakeResizeLock : public ResizeLock { 180 public: 181 FakeResizeLock(const gfx::Size new_size, bool defer_compositor_lock) 182 : ResizeLock(new_size, defer_compositor_lock) {} 183 }; 184 185 bool has_resize_lock_; 186 gfx::Size last_frame_size_; 187 scoped_ptr<cc::CopyOutputRequest> last_copy_request_; 188}; 189 190class RenderWidgetHostViewAuraTest : public testing::Test { 191 public: 192 RenderWidgetHostViewAuraTest() 193 : browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {} 194 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); 201 202 browser_context_.reset(new TestBrowserContext); 203 process_host_ = new MockRenderProcessHost(browser_context_.get()); 204 205 sink_ = &process_host_->sink(); 206 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(), 214 gfx::Rect()); 215 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_); 222 } 223 224 void TearDownEnvironment() { 225 sink_ = NULL; 226 process_host_ = NULL; 227 if (view_) 228 view_->Destroy(); 229 delete widget_host_; 230 231 parent_view_->Destroy(); 232 delete parent_host_; 233 234 browser_context_.reset(); 235 aura_test_helper_->TearDown(); 236 237 message_loop_.DeleteSoon(FROM_HERE, browser_context_.release()); 238 message_loop_.RunUntilIdle(); 239 ImageTransportFactory::Terminate(); 240 } 241 242 virtual void SetUp() { SetUpEnvironment(); } 243 244 virtual void TearDown() { TearDownEnvironment(); } 245 246 protected: 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_; 253 254 // Tests should set these to NULL if they've already triggered their 255 // destruction. 256 RenderWidgetHostImpl* parent_host_; 257 RenderWidgetHostViewAura* parent_view_; 258 259 // Tests should set these to NULL if they've already triggered their 260 // destruction. 261 RenderWidgetHostImpl* widget_host_; 262 FakeRenderWidgetHostViewAura* view_; 263 264 IPC::TestSink* sink_; 265 266 private: 267 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest); 268}; 269 270class RenderWidgetHostViewAuraShutdownTest 271 : public RenderWidgetHostViewAuraTest { 272 public: 273 RenderWidgetHostViewAuraShutdownTest() {} 274 275 virtual void TearDown() OVERRIDE { 276 // No TearDownEnvironment here, we do this explicitly during the test. 277 } 278 279 private: 280 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest); 281}; 282 283// A layout manager that always resizes a child to the root window size. 284class FullscreenLayoutManager : public aura::LayoutManager { 285 public: 286 explicit FullscreenLayoutManager(aura::Window* owner) 287 : owner_(owner) {} 288 virtual ~FullscreenLayoutManager() {} 289 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()); 295 } 296 } 297 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { 298 child->SetBounds(gfx::Rect()); 299 } 300 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE { 301 } 302 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE { 303 } 304 virtual void OnChildWindowVisibilityChanged(aura::Window* child, 305 bool visible) OVERRIDE { 306 } 307 virtual void SetChildBounds(aura::Window* child, 308 const gfx::Rect& requested_bounds) OVERRIDE { 309 SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size())); 310 } 311 312 private: 313 aura::Window* owner_; 314 DISALLOW_COPY_AND_ASSIGN(FullscreenLayoutManager); 315}; 316 317class MockWindowObserver : public aura::WindowObserver { 318 public: 319 MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&)); 320}; 321 322} // namespace 323 324// Checks that a fullscreen view has the correct show-state and receives the 325// focus. 326TEST_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)); 332 333 // Check that we requested and received the focus. 334 EXPECT_TRUE(window->HasFocus()); 335 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()); 339} 340 341// Checks that a popup is positioned correctly relative to its parent using 342// screen coordinates. 343TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) { 344 TestScreenPositionClient screen_position_client; 345 346 aura::Window* window = parent_view_->GetNativeView(); 347 aura::Window* root = window->GetRootWindow(); 348 aura::client::SetScreenPositionClient(root, &screen_position_client); 349 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); 355 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); 359 360 gfx::Rect final_bounds_in_screen = view_->GetViewBounds(); 361 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString()); 362 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()); 369 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()); 375 376 aura::client::SetScreenPositionClient(root, NULL); 377} 378 379// Checks that a fullscreen view is destroyed when it loses the focus. 380TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) { 381 view_->InitAsFullscreen(parent_view_); 382 aura::Window* window = view_->GetNativeView(); 383 ASSERT_TRUE(window != NULL); 384 ASSERT_TRUE(window->HasFocus()); 385 386 // After we create and focus another window, the RWHVA's window should be 387 // destroyed. 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); 392 sibling->Show(); 393 window->parent()->AddChild(sibling.get()); 394 sibling->Focus(); 395 ASSERT_TRUE(sibling->HasFocus()); 396 ASSERT_TRUE(observer.destroyed()); 397 398 widget_host_ = NULL; 399 view_ = NULL; 400} 401 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. 405TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupClickOutsidePopup) { 406 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400)); 407 parent_view_->Focus(); 408 EXPECT_TRUE(parent_view_->HasFocus()); 409 410 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); 411 aura::Window* window = view_->GetNativeView(); 412 ASSERT_TRUE(window != NULL); 413 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)); 418 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()); 424 425 widget_host_ = NULL; 426 view_ = NULL; 427} 428 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. 432TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupTapOutsidePopup) { 433 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400)); 434 parent_view_->Focus(); 435 EXPECT_TRUE(parent_view_->HasFocus()); 436 437 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); 438 aura::Window* window = view_->GetNativeView(); 439 ASSERT_TRUE(window != NULL); 440 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)); 445 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()); 451 452 widget_host_ = NULL; 453 view_ = NULL; 454} 455 456// Checks that IME-composition-event state is maintained correctly. 457TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) { 458 view_->InitAsChild(NULL); 459 view_->Show(); 460 461 ui::CompositionText composition_text; 462 composition_text.text = base::ASCIIToUTF16("|a|b"); 463 464 // Focused segment 465 composition_text.underlines.push_back( 466 ui::CompositionUnderline(0, 3, 0xff000000, true)); 467 468 // Non-focused segment 469 composition_text.underlines.push_back( 470 ui::CompositionUnderline(3, 4, 0xff000000, false)); 471 472 const ui::CompositionUnderlines& underlines = composition_text.underlines; 473 474 // Caret is at the end. (This emulates Japanese MSIME 2007 and later) 475 composition_text.selection = gfx::Range(4); 476 477 sink_->ClearMessages(); 478 view_->SetCompositionText(composition_text); 479 EXPECT_TRUE(view_->has_composition_text_); 480 { 481 const IPC::Message* msg = 482 sink_->GetFirstMessageMatching(ViewMsg_ImeSetComposition::ID); 483 ASSERT_TRUE(msg != NULL); 484 485 ViewMsg_ImeSetComposition::Param params; 486 ViewMsg_ImeSetComposition::Read(msg, ¶ms); 487 // composition text 488 EXPECT_EQ(composition_text.text, params.a); 489 // underlines 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); 496 } 497 // highlighted range 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"; 500 } 501 502 view_->ImeCancelComposition(); 503 EXPECT_FALSE(view_->has_composition_text_); 504} 505 506// Checks that touch-event state is maintained correctly. 507TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) { 508 view_->InitAsChild(NULL); 509 view_->Show(); 510 511 // Start with no touch-event handler in the renderer. 512 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); 513 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent()); 514 515 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 516 gfx::Point(30, 30), 517 0, 518 ui::EventTimeForNow()); 519 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 520 gfx::Point(20, 20), 521 0, 522 ui::EventTimeForNow()); 523 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, 524 gfx::Point(20, 20), 525 0, 526 ui::EventTimeForNow()); 527 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); 534 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); 541 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); 546 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()); 552 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); 559 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); 566 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); 571 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); 579 580 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); 581 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent()); 582 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); 591 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); 598} 599 600// Checks that touch-events are queued properly when there is a touch-event 601// handler on the page. 602TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) { 603 view_->InitAsChild(NULL); 604 view_->Show(); 605 606 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); 607 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent()); 608 609 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 610 gfx::Point(30, 30), 611 0, 612 ui::EventTimeForNow()); 613 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 614 gfx::Point(20, 20), 615 0, 616 ui::EventTimeForNow()); 617 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, 618 gfx::Point(20, 20), 619 0, 620 ui::EventTimeForNow()); 621 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); 628 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); 635 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); 644 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); 649} 650 651TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) { 652 view_->InitAsChild(NULL); 653 aura::client::ParentWindowWithContext( 654 view_->GetNativeView(), 655 parent_view_->GetNativeView()->GetRootWindow(), 656 gfx::Rect()); 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()); 662 { 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 668 EXPECT_EQ("100x100", 669 params.a.physical_backing_size.ToString()); // backing size 670 } 671 672 widget_host_->ResetSizeAndRepaintPendingFlags(); 673 sink_->ClearMessages(); 674 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()); 679 { 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 686 EXPECT_EQ("200x200", 687 params.a.physical_backing_size.ToString()); // backing size 688 } 689 690 widget_host_->ResetSizeAndRepaintPendingFlags(); 691 sink_->ClearMessages(); 692 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()); 697 { 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 704 EXPECT_EQ("100x100", 705 params.a.physical_backing_size.ToString()); // backing size 706 } 707} 708 709// Checks that InputMsg_CursorVisibilityChange IPC messages are dispatched 710// to the renderer at the correct times. 711TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) { 712 view_->InitAsChild(NULL); 713 aura::client::ParentWindowWithContext( 714 view_->GetNativeView(), 715 parent_view_->GetNativeView()->GetRootWindow(), 716 gfx::Rect()); 717 view_->SetSize(gfx::Size(100, 100)); 718 719 aura::test::TestCursorClient cursor_client( 720 parent_view_->GetNativeView()->GetRootWindow()); 721 722 cursor_client.AddObserver(view_); 723 724 // Expect a message the first time the cursor is shown. 725 view_->WasShown(); 726 sink_->ClearMessages(); 727 cursor_client.ShowCursor(); 728 EXPECT_EQ(1u, sink_->message_count()); 729 EXPECT_TRUE(sink_->GetUniqueMessageMatching( 730 InputMsg_CursorVisibilityChange::ID)); 731 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()); 736 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)); 743 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()); 748 749 // No messages should be sent while the view is invisible. 750 view_->WasHidden(); 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()); 756 757 // Show the view. Since the cursor was invisible when the view was hidden, 758 // no message should be sent. 759 sink_->ClearMessages(); 760 view_->WasShown(); 761 EXPECT_FALSE(sink_->GetUniqueMessageMatching( 762 InputMsg_CursorVisibilityChange::ID)); 763 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()); 768 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)); 775 776 // No messages should be sent while the view is invisible. 777 view_->WasHidden(); 778 sink_->ClearMessages(); 779 cursor_client.HideCursor(); 780 EXPECT_EQ(0u, sink_->message_count()); 781 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(); 785 view_->WasShown(); 786 EXPECT_TRUE(sink_->GetUniqueMessageMatching( 787 InputMsg_CursorVisibilityChange::ID)); 788 789 cursor_client.RemoveObserver(view_); 790} 791 792TEST_F(RenderWidgetHostViewAuraTest, UpdateCursorIfOverSelf) { 793 view_->InitAsChild(NULL); 794 aura::client::ParentWindowWithContext( 795 view_->GetNativeView(), 796 parent_view_->GetNativeView()->GetRootWindow(), 797 gfx::Rect()); 798 799 // Note that all coordinates in this test are screen coordinates. 800 view_->SetBounds(gfx::Rect(60, 60, 100, 100)); 801 view_->Show(); 802 803 aura::test::TestCursorClient cursor_client( 804 parent_view_->GetNativeView()->GetRootWindow()); 805 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()); 811 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()); 817 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()); 823 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()); 829 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()); 835} 836 837scoped_ptr<cc::CompositorFrame> MakeGLFrame(float scale_factor, 838 gfx::Size size, 839 gfx::Rect damage) { 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, 845 '1', 846 sizeof(frame->gl_frame_data->mailbox.name)); 847 frame->gl_frame_data->size = size; 848 frame->gl_frame_data->sub_buffer_rect = damage; 849 return frame.Pass(); 850} 851 852scoped_ptr<cc::CompositorFrame> MakeSoftwareFrame(float scale_factor, 853 gfx::Size size, 854 gfx::Rect damage) { 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); 865 return frame.Pass(); 866} 867 868scoped_ptr<cc::CompositorFrame> MakeDelegatedFrame(float scale_factor, 869 gfx::Size size, 870 gfx::Rect damage) { 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); 874 875 scoped_ptr<cc::RenderPass> pass = cc::RenderPass::Create(); 876 pass->SetNew(cc::RenderPass::Id(1, 1), 877 gfx::Rect(size), 878 gfx::RectF(damage), 879 gfx::Transform()); 880 frame->delegated_frame_data->render_pass_list.push_back(pass.Pass()); 881 return frame.Pass(); 882} 883 884// Resizing in fullscreen mode should send the up-to-date screen info. 885TEST_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_); 889 view_->WasShown(); 890 widget_host_->ResetSizeAndRepaintPendingFlags(); 891 sink_->ClearMessages(); 892 893 // Call WasResized to flush the old screen info. 894 view_->GetRenderWidgetHost()->WasResized(); 895 { 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()); 910 } 911 912 widget_host_->ResetSizeAndRepaintPendingFlags(); 913 sink_->ClearMessages(); 914 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()); 919 { 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()); 931 } 932} 933 934// Swapping a frame should notify the window. 935TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) { 936 gfx::Size view_size(100, 100); 937 gfx::Rect view_rect(view_size); 938 939 view_->InitAsChild(NULL); 940 aura::client::ParentWindowWithContext( 941 view_->GetNativeView(), 942 parent_view_->GetNativeView()->GetRootWindow(), 943 gfx::Rect()); 944 view_->SetSize(view_size); 945 view_->WasShown(); 946 947 MockWindowObserver observer; 948 view_->window_->AddObserver(&observer); 949 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; 957 958 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 959 view_->AcceleratedSurfaceBuffersSwapped(params, 0); 960 testing::Mock::VerifyAndClearExpectations(&observer); 961 962 // DSF = 2 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); 968 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; 976 post_params.x = 40; 977 post_params.y = 40; 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); 985 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); 990 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); 997 998 // Software path 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); 1002 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); 1008 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); 1014 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); 1020 1021 view_->window_->RemoveObserver(&observer); 1022} 1023 1024// Skipped frames should not drop their damage. 1025TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) { 1026 gfx::Rect view_rect(100, 100); 1027 gfx::Size frame_size = view_rect.size(); 1028 1029 view_->InitAsChild(NULL); 1030 aura::client::ParentWindowWithContext( 1031 view_->GetNativeView(), 1032 parent_view_->GetNativeView()->GetRootWindow(), 1033 gfx::Rect()); 1034 view_->SetSize(view_rect.size()); 1035 1036 MockWindowObserver observer; 1037 view_->window_->AddObserver(&observer); 1038 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(); 1045 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(); 1054 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(); 1059 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(); 1067 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(); 1074 1075 // Unlock the compositor. This frame should damage everything. 1076 frame_size = view_rect.size(); 1077 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(); 1085 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(); 1093 1094 1095 view_->window_->RemoveObserver(&observer); 1096} 1097 1098TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) { 1099 gfx::Rect view_rect(100, 100); 1100 gfx::Size frame_size = view_rect.size(); 1101 1102 view_->InitAsChild(NULL); 1103 aura::client::ParentWindowWithContext( 1104 view_->GetNativeView(), 1105 parent_view_->GetNativeView()->GetRootWindow(), 1106 gfx::Rect()); 1107 view_->SetSize(view_rect.size()); 1108 1109 MockWindowObserver observer; 1110 view_->window_->AddObserver(&observer); 1111 1112 // Swap a frame. 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(); 1118 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(); 1125 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(); 1131 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(); 1138 1139 view_->window_->RemoveObserver(&observer); 1140} 1141 1142TEST_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(); 1149 1150 scoped_ptr<RenderWidgetHostImpl * []> hosts( 1151 new RenderWidgetHostImpl* [renderer_count]); 1152 scoped_ptr<FakeRenderWidgetHostViewAura * []> views( 1153 new FakeRenderWidgetHostViewAura* [renderer_count]); 1154 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); 1159 hosts[i]->Init(); 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(), 1167 gfx::Rect()); 1168 views[i]->SetSize(view_rect.size()); 1169 } 1170 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(); 1178 } 1179 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_); 1185 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_); 1190 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(); 1197 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_); 1207 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_); 1215 } 1216 EXPECT_FALSE(views[0]->frame_provider_); 1217 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_); 1222 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_); 1230 1231 // Make [0] hidden, it should evict its frame. 1232 views[0]->WasHidden(); 1233 EXPECT_FALSE(views[0]->frame_provider_); 1234 1235 for (size_t i = 0; i < renderer_count; ++i) { 1236 views[i]->Destroy(); 1237 delete hosts[i]; 1238 } 1239} 1240 1241TEST_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(); 1248 1249 scoped_ptr<RenderWidgetHostImpl * []> hosts( 1250 new RenderWidgetHostImpl* [renderer_count]); 1251 scoped_ptr<FakeRenderWidgetHostViewAura * []> views( 1252 new FakeRenderWidgetHostViewAura* [renderer_count]); 1253 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); 1258 hosts[i]->Init(); 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(), 1266 gfx::Rect()); 1267 views[i]->SetSize(view_rect.size()); 1268 } 1269 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_); 1277 } 1278 1279 // If we hide [0], then [0] should be evicted. 1280 views[0]->WasHidden(); 1281 EXPECT_FALSE(views[0]->frame_provider_); 1282 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_); 1291 1292 // If we unlock [0] now, then [0] should be evicted. 1293 views[0]->UnlockResources(); 1294 EXPECT_FALSE(views[0]->frame_provider_); 1295 1296 for (size_t i = 0; i < renderer_count; ++i) { 1297 views[i]->Destroy(); 1298 delete hosts[i]; 1299 } 1300} 1301 1302TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) { 1303 gfx::Rect view_rect(100, 100); 1304 gfx::Size frame_size(100, 100); 1305 1306 view_->InitAsChild(NULL); 1307 aura::client::ParentWindowWithContext( 1308 view_->GetNativeView(), 1309 parent_view_->GetNativeView()->GetRootWindow(), 1310 gfx::Rect()); 1311 view_->SetSize(view_rect.size()); 1312 view_->WasShown(); 1313 1314 // With a 1x DPI UI and 1x DPI Renderer. 1315 view_->OnSwapCompositorFrame( 1316 1, MakeDelegatedFrame(1.f, frame_size, gfx::Rect(frame_size))); 1317 1318 // Save the frame provider. 1319 scoped_refptr<cc::DelegatedFrameProvider> frame_provider = 1320 view_->frame_provider_; 1321 1322 // This frame will have the same number of physical pixels, but has a new 1323 // scale on it. 1324 view_->OnSwapCompositorFrame( 1325 1, MakeDelegatedFrame(2.f, frame_size, gfx::Rect(frame_size))); 1326 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()); 1331} 1332 1333class RenderWidgetHostViewAuraCopyRequestTest 1334 : public RenderWidgetHostViewAuraShutdownTest { 1335 public: 1336 RenderWidgetHostViewAuraCopyRequestTest() 1337 : callback_count_(0), result_(false) {} 1338 1339 void CallbackMethod(bool result) { 1340 result_ = result; 1341 callback_count_++; 1342 } 1343 1344 int callback_count_; 1345 bool result_; 1346 1347 private: 1348 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraCopyRequestTest); 1349}; 1350 1351TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) { 1352 gfx::Rect view_rect(100, 100); 1353 scoped_ptr<cc::CopyOutputRequest> request; 1354 1355 view_->InitAsChild(NULL); 1356 aura::client::ParentWindowWithContext( 1357 view_->GetNativeView(), 1358 parent_view_->GetNativeView()->GetRootWindow(), 1359 gfx::Rect()); 1360 view_->SetSize(view_rect.size()); 1361 view_->WasShown(); 1362 1363 scoped_ptr<FakeFrameSubscriber> frame_subscriber(new FakeFrameSubscriber( 1364 view_rect.size(), 1365 base::Bind(&RenderWidgetHostViewAuraCopyRequestTest::CallbackMethod, 1366 base::Unretained(this)))); 1367 1368 EXPECT_EQ(0, callback_count_); 1369 EXPECT_FALSE(view_->last_copy_request_); 1370 1371 view_->BeginFrameSubscription( 1372 frame_subscriber.PassAs<RenderWidgetHostViewFrameSubscriber>()); 1373 view_->OnSwapCompositorFrame( 1374 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect))); 1375 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(); 1380 1381 // There should be one subscriber texture in flight. 1382 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size()); 1383 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>()); 1389 1390 base::RunLoop run_loop; 1391 run_loop.RunUntilIdle(); 1392 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_); 1397 1398 view_->OnSwapCompositorFrame( 1399 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect))); 1400 1401 EXPECT_EQ(1, callback_count_); 1402 request = view_->last_copy_request_.Pass(); 1403 1404 // There should be one subscriber texture in flight again. 1405 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size()); 1406 1407 // Destroy the RenderWidgetHostViewAura and ImageTransportFactory. 1408 TearDownEnvironment(); 1409 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>()); 1415 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_); 1422} 1423 1424} // namespace content 1425