render_widget_host_view_aura_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/owned_mailbox.h" 18#include "content/browser/compositor/resize_lock.h" 19#include "content/browser/renderer_host/render_widget_host_delegate.h" 20#include "content/browser/renderer_host/render_widget_host_impl.h" 21#include "content/common/gpu/gpu_messages.h" 22#include "content/common/input_messages.h" 23#include "content/common/view_messages.h" 24#include "content/port/browser/render_widget_host_view_frame_subscriber.h" 25#include "content/public/browser/render_widget_host_view.h" 26#include "content/public/test/mock_render_process_host.h" 27#include "content/public/test/test_browser_context.h" 28#include "ipc/ipc_test_sink.h" 29#include "testing/gmock/include/gmock/gmock.h" 30#include "testing/gtest/include/gtest/gtest.h" 31#include "ui/aura/client/aura_constants.h" 32#include "ui/aura/client/screen_position_client.h" 33#include "ui/aura/client/window_tree_client.h" 34#include "ui/aura/env.h" 35#include "ui/aura/layout_manager.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_event_dispatcher.h" 43#include "ui/aura/window_observer.h" 44#include "ui/base/ui_base_types.h" 45#include "ui/compositor/compositor.h" 46#include "ui/compositor/test/draw_waiter_for_test.h" 47#include "ui/compositor/test/in_process_context_factory.h" 48#include "ui/events/event.h" 49#include "ui/events/event_utils.h" 50 51using testing::_; 52 53namespace content { 54namespace { 55 56// Simple screen position client to test coordinate system conversion. 57class TestScreenPositionClient 58 : public aura::client::ScreenPositionClient { 59 public: 60 TestScreenPositionClient() {} 61 virtual ~TestScreenPositionClient() {} 62 63 // aura::client::ScreenPositionClient overrides: 64 virtual void ConvertPointToScreen(const aura::Window* window, 65 gfx::Point* point) OVERRIDE { 66 point->Offset(-1, -1); 67 } 68 69 virtual void ConvertPointFromScreen(const aura::Window* window, 70 gfx::Point* point) OVERRIDE { 71 point->Offset(1, 1); 72 } 73 74 virtual void ConvertHostPointToScreen(aura::Window* window, 75 gfx::Point* point) OVERRIDE { 76 ConvertPointToScreen(window, point); 77 } 78 79 virtual void SetBounds(aura::Window* window, 80 const gfx::Rect& bounds, 81 const gfx::Display& display) OVERRIDE { 82 } 83}; 84 85class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { 86 public: 87 MockRenderWidgetHostDelegate() {} 88 virtual ~MockRenderWidgetHostDelegate() {} 89}; 90 91// Simple observer that keeps track of changes to a window for tests. 92class TestWindowObserver : public aura::WindowObserver { 93 public: 94 explicit TestWindowObserver(aura::Window* window_to_observe) 95 : window_(window_to_observe) { 96 window_->AddObserver(this); 97 } 98 virtual ~TestWindowObserver() { 99 if (window_) 100 window_->RemoveObserver(this); 101 } 102 103 bool destroyed() const { return destroyed_; } 104 105 // aura::WindowObserver overrides: 106 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 107 CHECK_EQ(window, window_); 108 destroyed_ = true; 109 window_ = NULL; 110 } 111 112 private: 113 // Window that we're observing, or NULL if it's been destroyed. 114 aura::Window* window_; 115 116 // Was |window_| destroyed? 117 bool destroyed_; 118 119 DISALLOW_COPY_AND_ASSIGN(TestWindowObserver); 120}; 121 122class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 123 public: 124 FakeFrameSubscriber(gfx::Size size, base::Callback<void(bool)> callback) 125 : size_(size), callback_(callback) {} 126 127 virtual bool ShouldCaptureFrame(base::TimeTicks present_time, 128 scoped_refptr<media::VideoFrame>* storage, 129 DeliverFrameCallback* callback) OVERRIDE { 130 *storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, 131 size_, 132 gfx::Rect(size_), 133 size_, 134 base::TimeDelta()); 135 *callback = base::Bind(&FakeFrameSubscriber::CallbackMethod, callback_); 136 return true; 137 } 138 139 static void CallbackMethod(base::Callback<void(bool)> callback, 140 base::TimeTicks timestamp, 141 bool success) { 142 callback.Run(success); 143 } 144 145 private: 146 gfx::Size size_; 147 base::Callback<void(bool)> callback_; 148}; 149 150class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { 151 public: 152 FakeRenderWidgetHostViewAura(RenderWidgetHost* widget) 153 : RenderWidgetHostViewAura(widget), has_resize_lock_(false) {} 154 155 virtual ~FakeRenderWidgetHostViewAura() {} 156 157 virtual bool ShouldCreateResizeLock() OVERRIDE { 158 gfx::Size desired_size = window()->bounds().size(); 159 return desired_size != current_frame_size(); 160 } 161 162 virtual scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock) 163 OVERRIDE { 164 gfx::Size desired_size = window()->bounds().size(); 165 return scoped_ptr<ResizeLock>( 166 new FakeResizeLock(desired_size, defer_compositor_lock)); 167 } 168 169 virtual void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request) 170 OVERRIDE { 171 last_copy_request_ = request.Pass(); 172 if (last_copy_request_->has_texture_mailbox()) { 173 // Give the resulting texture a size. 174 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper(); 175 GLuint texture = gl_helper->ConsumeMailboxToTexture( 176 last_copy_request_->texture_mailbox().mailbox(), 177 last_copy_request_->texture_mailbox().sync_point()); 178 gl_helper->ResizeTexture(texture, window()->bounds().size()); 179 gl_helper->DeleteTexture(texture); 180 } 181 } 182 183 void RunOnCompositingDidCommit() { 184 OnCompositingDidCommit(window()->GetHost()->compositor()); 185 } 186 187 // A lock that doesn't actually do anything to the compositor, and does not 188 // time out. 189 class FakeResizeLock : public ResizeLock { 190 public: 191 FakeResizeLock(const gfx::Size new_size, bool defer_compositor_lock) 192 : ResizeLock(new_size, defer_compositor_lock) {} 193 }; 194 195 bool has_resize_lock_; 196 gfx::Size last_frame_size_; 197 scoped_ptr<cc::CopyOutputRequest> last_copy_request_; 198}; 199 200class RenderWidgetHostViewAuraTest : public testing::Test { 201 public: 202 RenderWidgetHostViewAuraTest() 203 : browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {} 204 205 void SetUpEnvironment() { 206 ImageTransportFactory::InitializeForUnitTests( 207 scoped_ptr<ui::ContextFactory>(new ui::InProcessContextFactory)); 208 aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_)); 209 aura_test_helper_->SetUp(); 210 211 browser_context_.reset(new TestBrowserContext); 212 process_host_ = new MockRenderProcessHost(browser_context_.get()); 213 214 sink_ = &process_host_->sink(); 215 216 parent_host_ = new RenderWidgetHostImpl( 217 &delegate_, process_host_, MSG_ROUTING_NONE, false); 218 parent_view_ = static_cast<RenderWidgetHostViewAura*>( 219 RenderWidgetHostView::CreateViewForWidget(parent_host_)); 220 parent_view_->InitAsChild(NULL); 221 aura::client::ParentWindowWithContext(parent_view_->GetNativeView(), 222 aura_test_helper_->root_window(), 223 gfx::Rect()); 224 225 widget_host_ = new RenderWidgetHostImpl( 226 &delegate_, process_host_, MSG_ROUTING_NONE, false); 227 widget_host_->Init(); 228 widget_host_->OnMessageReceived( 229 ViewHostMsg_DidActivateAcceleratedCompositing(0, true)); 230 view_ = new FakeRenderWidgetHostViewAura(widget_host_); 231 } 232 233 void TearDownEnvironment() { 234 sink_ = NULL; 235 process_host_ = NULL; 236 if (view_) 237 view_->Destroy(); 238 delete widget_host_; 239 240 parent_view_->Destroy(); 241 delete parent_host_; 242 243 browser_context_.reset(); 244 aura_test_helper_->TearDown(); 245 246 message_loop_.DeleteSoon(FROM_HERE, browser_context_.release()); 247 message_loop_.RunUntilIdle(); 248 ImageTransportFactory::Terminate(); 249 } 250 251 virtual void SetUp() { SetUpEnvironment(); } 252 253 virtual void TearDown() { TearDownEnvironment(); } 254 255 protected: 256 base::MessageLoopForUI message_loop_; 257 BrowserThreadImpl browser_thread_for_ui_; 258 scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_; 259 scoped_ptr<BrowserContext> browser_context_; 260 MockRenderWidgetHostDelegate delegate_; 261 MockRenderProcessHost* process_host_; 262 263 // Tests should set these to NULL if they've already triggered their 264 // destruction. 265 RenderWidgetHostImpl* parent_host_; 266 RenderWidgetHostViewAura* parent_view_; 267 268 // Tests should set these to NULL if they've already triggered their 269 // destruction. 270 RenderWidgetHostImpl* widget_host_; 271 FakeRenderWidgetHostViewAura* view_; 272 273 IPC::TestSink* sink_; 274 275 private: 276 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest); 277}; 278 279class RenderWidgetHostViewAuraShutdownTest 280 : public RenderWidgetHostViewAuraTest { 281 public: 282 RenderWidgetHostViewAuraShutdownTest() {} 283 284 virtual void TearDown() OVERRIDE { 285 // No TearDownEnvironment here, we do this explicitly during the test. 286 } 287 288 private: 289 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraShutdownTest); 290}; 291 292// A layout manager that always resizes a child to the root window size. 293class FullscreenLayoutManager : public aura::LayoutManager { 294 public: 295 explicit FullscreenLayoutManager(aura::Window* owner) 296 : owner_(owner) {} 297 virtual ~FullscreenLayoutManager() {} 298 299 // Overridden from aura::LayoutManager: 300 virtual void OnWindowResized() OVERRIDE { 301 aura::Window::Windows::const_iterator i; 302 for (i = owner_->children().begin(); i != owner_->children().end(); ++i) { 303 (*i)->SetBounds(gfx::Rect()); 304 } 305 } 306 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { 307 child->SetBounds(gfx::Rect()); 308 } 309 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE { 310 } 311 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE { 312 } 313 virtual void OnChildWindowVisibilityChanged(aura::Window* child, 314 bool visible) OVERRIDE { 315 } 316 virtual void SetChildBounds(aura::Window* child, 317 const gfx::Rect& requested_bounds) OVERRIDE { 318 SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size())); 319 } 320 321 private: 322 aura::Window* owner_; 323 DISALLOW_COPY_AND_ASSIGN(FullscreenLayoutManager); 324}; 325 326class MockWindowObserver : public aura::WindowObserver { 327 public: 328 MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&)); 329}; 330 331} // namespace 332 333// Checks that a fullscreen view has the correct show-state and receives the 334// focus. 335TEST_F(RenderWidgetHostViewAuraTest, FocusFullscreen) { 336 view_->InitAsFullscreen(parent_view_); 337 aura::Window* window = view_->GetNativeView(); 338 ASSERT_TRUE(window != NULL); 339 EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, 340 window->GetProperty(aura::client::kShowStateKey)); 341 342 // Check that we requested and received the focus. 343 EXPECT_TRUE(window->HasFocus()); 344 345 // Check that we'll also say it's okay to activate the window when there's an 346 // ActivationClient defined. 347 EXPECT_TRUE(view_->ShouldActivate()); 348} 349 350// Checks that a popup is positioned correctly relative to its parent using 351// screen coordinates. 352TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) { 353 TestScreenPositionClient screen_position_client; 354 355 aura::Window* window = parent_view_->GetNativeView(); 356 aura::Window* root = window->GetRootWindow(); 357 aura::client::SetScreenPositionClient(root, &screen_position_client); 358 359 parent_view_->SetBounds(gfx::Rect(10, 10, 800, 600)); 360 gfx::Rect bounds_in_screen = parent_view_->GetViewBounds(); 361 int horiz = bounds_in_screen.width() / 4; 362 int vert = bounds_in_screen.height() / 4; 363 bounds_in_screen.Inset(horiz, vert); 364 365 // Verify that when the popup is initialized for the first time, it correctly 366 // treats the input bounds as screen coordinates. 367 view_->InitAsPopup(parent_view_, bounds_in_screen); 368 369 gfx::Rect final_bounds_in_screen = view_->GetViewBounds(); 370 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString()); 371 372 // Verify that directly setting the bounds via SetBounds() treats the input 373 // as screen coordinates. 374 bounds_in_screen = gfx::Rect(60, 60, 100, 100); 375 view_->SetBounds(bounds_in_screen); 376 final_bounds_in_screen = view_->GetViewBounds(); 377 EXPECT_EQ(final_bounds_in_screen.ToString(), bounds_in_screen.ToString()); 378 379 // Verify that setting the size does not alter the origin. 380 gfx::Point original_origin = window->bounds().origin(); 381 view_->SetSize(gfx::Size(120, 120)); 382 gfx::Point new_origin = window->bounds().origin(); 383 EXPECT_EQ(original_origin.ToString(), new_origin.ToString()); 384 385 aura::client::SetScreenPositionClient(root, NULL); 386} 387 388// Checks that a fullscreen view is destroyed when it loses the focus. 389TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) { 390 view_->InitAsFullscreen(parent_view_); 391 aura::Window* window = view_->GetNativeView(); 392 ASSERT_TRUE(window != NULL); 393 ASSERT_TRUE(window->HasFocus()); 394 395 // After we create and focus another window, the RWHVA's window should be 396 // destroyed. 397 TestWindowObserver observer(window); 398 aura::test::TestWindowDelegate delegate; 399 scoped_ptr<aura::Window> sibling(new aura::Window(&delegate)); 400 sibling->Init(aura::WINDOW_LAYER_TEXTURED); 401 sibling->Show(); 402 window->parent()->AddChild(sibling.get()); 403 sibling->Focus(); 404 ASSERT_TRUE(sibling->HasFocus()); 405 ASSERT_TRUE(observer.destroyed()); 406 407 widget_host_ = NULL; 408 view_ = NULL; 409} 410 411// Checks that a popup view is destroyed when a user clicks outside of the popup 412// view and focus does not change. This is the case when the user clicks on the 413// desktop background on Chrome OS. 414TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupClickOutsidePopup) { 415 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400)); 416 parent_view_->Focus(); 417 EXPECT_TRUE(parent_view_->HasFocus()); 418 419 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); 420 aura::Window* window = view_->GetNativeView(); 421 ASSERT_TRUE(window != NULL); 422 423 gfx::Point click_point; 424 EXPECT_FALSE(window->GetBoundsInRootWindow().Contains(click_point)); 425 aura::Window* parent_window = parent_view_->GetNativeView(); 426 EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(click_point)); 427 428 TestWindowObserver observer(window); 429 aura::test::EventGenerator generator(window->GetRootWindow(), click_point); 430 generator.ClickLeftButton(); 431 ASSERT_TRUE(parent_view_->HasFocus()); 432 ASSERT_TRUE(observer.destroyed()); 433 434 widget_host_ = NULL; 435 view_ = NULL; 436} 437 438// Checks that a popup view is destroyed when a user taps outside of the popup 439// view and focus does not change. This is the case when the user taps the 440// desktop background on Chrome OS. 441TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupTapOutsidePopup) { 442 parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400)); 443 parent_view_->Focus(); 444 EXPECT_TRUE(parent_view_->HasFocus()); 445 446 view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100)); 447 aura::Window* window = view_->GetNativeView(); 448 ASSERT_TRUE(window != NULL); 449 450 gfx::Point tap_point; 451 EXPECT_FALSE(window->GetBoundsInRootWindow().Contains(tap_point)); 452 aura::Window* parent_window = parent_view_->GetNativeView(); 453 EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(tap_point)); 454 455 TestWindowObserver observer(window); 456 aura::test::EventGenerator generator(window->GetRootWindow(), tap_point); 457 generator.GestureTapAt(tap_point); 458 ASSERT_TRUE(parent_view_->HasFocus()); 459 ASSERT_TRUE(observer.destroyed()); 460 461 widget_host_ = NULL; 462 view_ = NULL; 463} 464 465// Checks that IME-composition-event state is maintained correctly. 466TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) { 467 view_->InitAsChild(NULL); 468 view_->Show(); 469 470 ui::CompositionText composition_text; 471 composition_text.text = base::ASCIIToUTF16("|a|b"); 472 473 // Focused segment 474 composition_text.underlines.push_back( 475 ui::CompositionUnderline(0, 3, 0xff000000, true)); 476 477 // Non-focused segment 478 composition_text.underlines.push_back( 479 ui::CompositionUnderline(3, 4, 0xff000000, false)); 480 481 const ui::CompositionUnderlines& underlines = composition_text.underlines; 482 483 // Caret is at the end. (This emulates Japanese MSIME 2007 and later) 484 composition_text.selection = gfx::Range(4); 485 486 sink_->ClearMessages(); 487 view_->SetCompositionText(composition_text); 488 EXPECT_TRUE(view_->has_composition_text_); 489 { 490 const IPC::Message* msg = 491 sink_->GetFirstMessageMatching(ViewMsg_ImeSetComposition::ID); 492 ASSERT_TRUE(msg != NULL); 493 494 ViewMsg_ImeSetComposition::Param params; 495 ViewMsg_ImeSetComposition::Read(msg, ¶ms); 496 // composition text 497 EXPECT_EQ(composition_text.text, params.a); 498 // underlines 499 ASSERT_EQ(underlines.size(), params.b.size()); 500 for (size_t i = 0; i < underlines.size(); ++i) { 501 EXPECT_EQ(underlines[i].start_offset, params.b[i].startOffset); 502 EXPECT_EQ(underlines[i].end_offset, params.b[i].endOffset); 503 EXPECT_EQ(underlines[i].color, params.b[i].color); 504 EXPECT_EQ(underlines[i].thick, params.b[i].thick); 505 } 506 // highlighted range 507 EXPECT_EQ(4, params.c) << "Should be the same to the caret pos"; 508 EXPECT_EQ(4, params.d) << "Should be the same to the caret pos"; 509 } 510 511 view_->ImeCancelComposition(); 512 EXPECT_FALSE(view_->has_composition_text_); 513} 514 515// Checks that touch-event state is maintained correctly. 516TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) { 517 view_->InitAsChild(NULL); 518 view_->Show(); 519 520 // Start with no touch-event handler in the renderer. 521 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); 522 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent()); 523 524 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 525 gfx::Point(30, 30), 526 0, 527 ui::EventTimeForNow()); 528 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 529 gfx::Point(20, 20), 530 0, 531 ui::EventTimeForNow()); 532 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, 533 gfx::Point(20, 20), 534 0, 535 ui::EventTimeForNow()); 536 537 view_->OnTouchEvent(&press); 538 EXPECT_FALSE(press.handled()); 539 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type); 540 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 541 EXPECT_EQ(blink::WebTouchPoint::StatePressed, 542 view_->touch_event_.touches[0].state); 543 544 view_->OnTouchEvent(&move); 545 EXPECT_FALSE(move.handled()); 546 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type); 547 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 548 EXPECT_EQ(blink::WebTouchPoint::StateMoved, 549 view_->touch_event_.touches[0].state); 550 551 view_->OnTouchEvent(&release); 552 EXPECT_FALSE(release.handled()); 553 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type); 554 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 555 556 // Now install some touch-event handlers and do the same steps. The touch 557 // events should now be consumed. However, the touch-event state should be 558 // updated as before. 559 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); 560 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent()); 561 562 view_->OnTouchEvent(&press); 563 EXPECT_TRUE(press.stopped_propagation()); 564 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type); 565 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 566 EXPECT_EQ(blink::WebTouchPoint::StatePressed, 567 view_->touch_event_.touches[0].state); 568 569 view_->OnTouchEvent(&move); 570 EXPECT_TRUE(move.stopped_propagation()); 571 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type); 572 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 573 EXPECT_EQ(blink::WebTouchPoint::StateMoved, 574 view_->touch_event_.touches[0].state); 575 576 view_->OnTouchEvent(&release); 577 EXPECT_TRUE(release.stopped_propagation()); 578 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type); 579 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 580 581 // Now start a touch event, and remove the event-handlers before the release. 582 view_->OnTouchEvent(&press); 583 EXPECT_TRUE(press.stopped_propagation()); 584 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type); 585 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 586 EXPECT_EQ(blink::WebTouchPoint::StatePressed, 587 view_->touch_event_.touches[0].state); 588 589 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); 590 EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent()); 591 592 ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0, 593 base::Time::NowFromSystemTime() - base::Time()); 594 view_->OnTouchEvent(&move2); 595 EXPECT_FALSE(move2.handled()); 596 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type); 597 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 598 EXPECT_EQ(blink::WebTouchPoint::StateMoved, 599 view_->touch_event_.touches[0].state); 600 601 ui::TouchEvent release2(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 0, 602 base::Time::NowFromSystemTime() - base::Time()); 603 view_->OnTouchEvent(&release2); 604 EXPECT_FALSE(release2.handled()); 605 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type); 606 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 607} 608 609// Checks that touch-events are queued properly when there is a touch-event 610// handler on the page. 611TEST_F(RenderWidgetHostViewAuraTest, TouchEventSyncAsync) { 612 view_->InitAsChild(NULL); 613 view_->Show(); 614 615 widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); 616 EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent()); 617 618 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 619 gfx::Point(30, 30), 620 0, 621 ui::EventTimeForNow()); 622 ui::TouchEvent move(ui::ET_TOUCH_MOVED, 623 gfx::Point(20, 20), 624 0, 625 ui::EventTimeForNow()); 626 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, 627 gfx::Point(20, 20), 628 0, 629 ui::EventTimeForNow()); 630 631 view_->OnTouchEvent(&press); 632 EXPECT_TRUE(press.stopped_propagation()); 633 EXPECT_EQ(blink::WebInputEvent::TouchStart, view_->touch_event_.type); 634 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 635 EXPECT_EQ(blink::WebTouchPoint::StatePressed, 636 view_->touch_event_.touches[0].state); 637 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 // Send the same move event. Since the point hasn't moved, it won't affect the 646 // queue. However, the view should consume the event. 647 view_->OnTouchEvent(&move); 648 EXPECT_TRUE(move.stopped_propagation()); 649 EXPECT_EQ(blink::WebInputEvent::TouchMove, view_->touch_event_.type); 650 EXPECT_EQ(1U, view_->touch_event_.touchesLength); 651 EXPECT_EQ(blink::WebTouchPoint::StateMoved, 652 view_->touch_event_.touches[0].state); 653 654 view_->OnTouchEvent(&release); 655 EXPECT_TRUE(release.stopped_propagation()); 656 EXPECT_EQ(blink::WebInputEvent::TouchEnd, view_->touch_event_.type); 657 EXPECT_EQ(0U, view_->touch_event_.touchesLength); 658} 659 660TEST_F(RenderWidgetHostViewAuraTest, PhysicalBackingSizeWithScale) { 661 view_->InitAsChild(NULL); 662 aura::client::ParentWindowWithContext( 663 view_->GetNativeView(), 664 parent_view_->GetNativeView()->GetRootWindow(), 665 gfx::Rect()); 666 sink_->ClearMessages(); 667 view_->SetSize(gfx::Size(100, 100)); 668 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString()); 669 EXPECT_EQ(1u, sink_->message_count()); 670 EXPECT_EQ(ViewMsg_Resize::ID, sink_->GetMessageAt(0)->type()); 671 { 672 const IPC::Message* msg = sink_->GetMessageAt(0); 673 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 674 ViewMsg_Resize::Param params; 675 ViewMsg_Resize::Read(msg, ¶ms); 676 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size 677 EXPECT_EQ("100x100", 678 params.a.physical_backing_size.ToString()); // backing size 679 } 680 681 widget_host_->ResetSizeAndRepaintPendingFlags(); 682 sink_->ClearMessages(); 683 684 aura_test_helper_->test_screen()->SetDeviceScaleFactor(2.0f); 685 EXPECT_EQ("200x200", view_->GetPhysicalBackingSize().ToString()); 686 // Extra ScreenInfoChanged message for |parent_view_|. 687 EXPECT_EQ(1u, sink_->message_count()); 688 { 689 const IPC::Message* msg = sink_->GetMessageAt(0); 690 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 691 ViewMsg_Resize::Param params; 692 ViewMsg_Resize::Read(msg, ¶ms); 693 EXPECT_EQ(2.0f, params.a.screen_info.deviceScaleFactor); 694 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size 695 EXPECT_EQ("200x200", 696 params.a.physical_backing_size.ToString()); // backing size 697 } 698 699 widget_host_->ResetSizeAndRepaintPendingFlags(); 700 sink_->ClearMessages(); 701 702 aura_test_helper_->test_screen()->SetDeviceScaleFactor(1.0f); 703 // Extra ScreenInfoChanged message for |parent_view_|. 704 EXPECT_EQ(1u, sink_->message_count()); 705 EXPECT_EQ("100x100", view_->GetPhysicalBackingSize().ToString()); 706 { 707 const IPC::Message* msg = sink_->GetMessageAt(0); 708 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 709 ViewMsg_Resize::Param params; 710 ViewMsg_Resize::Read(msg, ¶ms); 711 EXPECT_EQ(1.0f, params.a.screen_info.deviceScaleFactor); 712 EXPECT_EQ("100x100", params.a.new_size.ToString()); // dip size 713 EXPECT_EQ("100x100", 714 params.a.physical_backing_size.ToString()); // backing size 715 } 716} 717 718// Checks that InputMsg_CursorVisibilityChange IPC messages are dispatched 719// to the renderer at the correct times. 720TEST_F(RenderWidgetHostViewAuraTest, CursorVisibilityChange) { 721 view_->InitAsChild(NULL); 722 aura::client::ParentWindowWithContext( 723 view_->GetNativeView(), 724 parent_view_->GetNativeView()->GetRootWindow(), 725 gfx::Rect()); 726 view_->SetSize(gfx::Size(100, 100)); 727 728 aura::test::TestCursorClient cursor_client( 729 parent_view_->GetNativeView()->GetRootWindow()); 730 731 cursor_client.AddObserver(view_); 732 733 // Expect a message the first time the cursor is shown. 734 view_->WasShown(); 735 sink_->ClearMessages(); 736 cursor_client.ShowCursor(); 737 EXPECT_EQ(1u, sink_->message_count()); 738 EXPECT_TRUE(sink_->GetUniqueMessageMatching( 739 InputMsg_CursorVisibilityChange::ID)); 740 741 // No message expected if the renderer already knows the cursor is visible. 742 sink_->ClearMessages(); 743 cursor_client.ShowCursor(); 744 EXPECT_EQ(0u, sink_->message_count()); 745 746 // Hiding the cursor should send a message. 747 sink_->ClearMessages(); 748 cursor_client.HideCursor(); 749 EXPECT_EQ(1u, sink_->message_count()); 750 EXPECT_TRUE(sink_->GetUniqueMessageMatching( 751 InputMsg_CursorVisibilityChange::ID)); 752 753 // No message expected if the renderer already knows the cursor is invisible. 754 sink_->ClearMessages(); 755 cursor_client.HideCursor(); 756 EXPECT_EQ(0u, sink_->message_count()); 757 758 // No messages should be sent while the view is invisible. 759 view_->WasHidden(); 760 sink_->ClearMessages(); 761 cursor_client.ShowCursor(); 762 EXPECT_EQ(0u, sink_->message_count()); 763 cursor_client.HideCursor(); 764 EXPECT_EQ(0u, sink_->message_count()); 765 766 // Show the view. Since the cursor was invisible when the view was hidden, 767 // no message should be sent. 768 sink_->ClearMessages(); 769 view_->WasShown(); 770 EXPECT_FALSE(sink_->GetUniqueMessageMatching( 771 InputMsg_CursorVisibilityChange::ID)); 772 773 // No message expected if the renderer already knows the cursor is invisible. 774 sink_->ClearMessages(); 775 cursor_client.HideCursor(); 776 EXPECT_EQ(0u, sink_->message_count()); 777 778 // Showing the cursor should send a message. 779 sink_->ClearMessages(); 780 cursor_client.ShowCursor(); 781 EXPECT_EQ(1u, sink_->message_count()); 782 EXPECT_TRUE(sink_->GetUniqueMessageMatching( 783 InputMsg_CursorVisibilityChange::ID)); 784 785 // No messages should be sent while the view is invisible. 786 view_->WasHidden(); 787 sink_->ClearMessages(); 788 cursor_client.HideCursor(); 789 EXPECT_EQ(0u, sink_->message_count()); 790 791 // Show the view. Since the cursor was visible when the view was hidden, 792 // a message is expected to be sent. 793 sink_->ClearMessages(); 794 view_->WasShown(); 795 EXPECT_TRUE(sink_->GetUniqueMessageMatching( 796 InputMsg_CursorVisibilityChange::ID)); 797 798 cursor_client.RemoveObserver(view_); 799} 800 801TEST_F(RenderWidgetHostViewAuraTest, UpdateCursorIfOverSelf) { 802 view_->InitAsChild(NULL); 803 aura::client::ParentWindowWithContext( 804 view_->GetNativeView(), 805 parent_view_->GetNativeView()->GetRootWindow(), 806 gfx::Rect()); 807 808 // Note that all coordinates in this test are screen coordinates. 809 view_->SetBounds(gfx::Rect(60, 60, 100, 100)); 810 view_->Show(); 811 812 aura::test::TestCursorClient cursor_client( 813 parent_view_->GetNativeView()->GetRootWindow()); 814 815 // Cursor is in the middle of the window. 816 cursor_client.reset_calls_to_set_cursor(); 817 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(110, 110)); 818 view_->UpdateCursorIfOverSelf(); 819 EXPECT_EQ(1, cursor_client.calls_to_set_cursor()); 820 821 // Cursor is near the top of the window. 822 cursor_client.reset_calls_to_set_cursor(); 823 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(80, 65)); 824 view_->UpdateCursorIfOverSelf(); 825 EXPECT_EQ(1, cursor_client.calls_to_set_cursor()); 826 827 // Cursor is near the bottom of the window. 828 cursor_client.reset_calls_to_set_cursor(); 829 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(159, 159)); 830 view_->UpdateCursorIfOverSelf(); 831 EXPECT_EQ(1, cursor_client.calls_to_set_cursor()); 832 833 // Cursor is above the window. 834 cursor_client.reset_calls_to_set_cursor(); 835 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(67, 59)); 836 view_->UpdateCursorIfOverSelf(); 837 EXPECT_EQ(0, cursor_client.calls_to_set_cursor()); 838 839 // Cursor is below the window. 840 cursor_client.reset_calls_to_set_cursor(); 841 aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(161, 161)); 842 view_->UpdateCursorIfOverSelf(); 843 EXPECT_EQ(0, cursor_client.calls_to_set_cursor()); 844} 845 846scoped_ptr<cc::CompositorFrame> MakeGLFrame(float scale_factor, 847 gfx::Size size, 848 gfx::Rect damage, 849 OwnedMailbox* owned_mailbox) { 850 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame); 851 frame->metadata.device_scale_factor = scale_factor; 852 frame->gl_frame_data.reset(new cc::GLFrameData); 853 DCHECK(owned_mailbox->sync_point()); 854 frame->gl_frame_data->sync_point = owned_mailbox->sync_point(); 855 memcpy(frame->gl_frame_data->mailbox.name, 856 owned_mailbox->mailbox().name, 857 sizeof(frame->gl_frame_data->mailbox.name)); 858 frame->gl_frame_data->size = size; 859 frame->gl_frame_data->sub_buffer_rect = damage; 860 return frame.Pass(); 861} 862 863scoped_ptr<cc::CompositorFrame> MakeSoftwareFrame(float scale_factor, 864 gfx::Size size, 865 gfx::Rect damage) { 866 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame); 867 frame->metadata.device_scale_factor = scale_factor; 868 frame->software_frame_data.reset(new cc::SoftwareFrameData); 869 frame->software_frame_data->id = 1; 870 frame->software_frame_data->size = size; 871 frame->software_frame_data->damage_rect = damage; 872 base::SharedMemory shm; 873 shm.CreateAndMapAnonymous(size.GetArea() * 4); 874 shm.GiveToProcess(base::GetCurrentProcessHandle(), 875 &frame->software_frame_data->handle); 876 return frame.Pass(); 877} 878 879scoped_ptr<cc::CompositorFrame> MakeDelegatedFrame(float scale_factor, 880 gfx::Size size, 881 gfx::Rect damage) { 882 scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame); 883 frame->metadata.device_scale_factor = scale_factor; 884 frame->delegated_frame_data.reset(new cc::DelegatedFrameData); 885 886 scoped_ptr<cc::RenderPass> pass = cc::RenderPass::Create(); 887 pass->SetNew(cc::RenderPass::Id(1, 1), 888 gfx::Rect(size), 889 gfx::RectF(damage), 890 gfx::Transform()); 891 frame->delegated_frame_data->render_pass_list.push_back(pass.Pass()); 892 return frame.Pass(); 893} 894 895// Resizing in fullscreen mode should send the up-to-date screen info. 896TEST_F(RenderWidgetHostViewAuraTest, FullscreenResize) { 897 aura::Window* root_window = aura_test_helper_->root_window(); 898 root_window->SetLayoutManager(new FullscreenLayoutManager(root_window)); 899 view_->InitAsFullscreen(parent_view_); 900 view_->WasShown(); 901 widget_host_->ResetSizeAndRepaintPendingFlags(); 902 sink_->ClearMessages(); 903 904 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper(); 905 scoped_refptr<OwnedMailbox> owned_mailbox = new OwnedMailbox(gl_helper); 906 gl_helper->ResizeTexture(owned_mailbox->texture_id(), gfx::Size(1, 1)); 907 owned_mailbox->UpdateSyncPoint(gl_helper->InsertSyncPoint()); 908 909 // Call WasResized to flush the old screen info. 910 view_->GetRenderWidgetHost()->WasResized(); 911 { 912 // 0 is CreatingNew message. 913 const IPC::Message* msg = sink_->GetMessageAt(0); 914 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 915 ViewMsg_Resize::Param params; 916 ViewMsg_Resize::Read(msg, ¶ms); 917 EXPECT_EQ("0,0 800x600", 918 gfx::Rect(params.a.screen_info.availableRect).ToString()); 919 EXPECT_EQ("800x600", params.a.new_size.ToString()); 920 // Resizes are blocked until we swapped a frame of the correct size, and 921 // we've committed it. 922 view_->OnSwapCompositorFrame(0, 923 MakeGLFrame(1.f, 924 params.a.new_size, 925 gfx::Rect(params.a.new_size), 926 owned_mailbox.get())); 927 ui::DrawWaiterForTest::WaitForCommit( 928 root_window->GetHost()->compositor()); 929 } 930 931 widget_host_->ResetSizeAndRepaintPendingFlags(); 932 sink_->ClearMessages(); 933 934 // Make sure the corrent screen size is set along in the resize 935 // request when the screen size has changed. 936 aura_test_helper_->test_screen()->SetUIScale(0.5); 937 EXPECT_EQ(1u, sink_->message_count()); 938 { 939 const IPC::Message* msg = sink_->GetMessageAt(0); 940 EXPECT_EQ(ViewMsg_Resize::ID, msg->type()); 941 ViewMsg_Resize::Param params; 942 ViewMsg_Resize::Read(msg, ¶ms); 943 EXPECT_EQ("0,0 1600x1200", 944 gfx::Rect(params.a.screen_info.availableRect).ToString()); 945 EXPECT_EQ("1600x1200", params.a.new_size.ToString()); 946 view_->OnSwapCompositorFrame(0, 947 MakeGLFrame(1.f, 948 params.a.new_size, 949 gfx::Rect(params.a.new_size), 950 owned_mailbox.get())); 951 ui::DrawWaiterForTest::WaitForCommit( 952 root_window->GetHost()->compositor()); 953 } 954} 955 956// Swapping a frame should notify the window. 957TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) { 958 gfx::Size view_size(100, 100); 959 gfx::Rect view_rect(view_size); 960 961 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper(); 962 scoped_refptr<OwnedMailbox> owned_mailbox = new OwnedMailbox(gl_helper); 963 gl_helper->ResizeTexture(owned_mailbox->texture_id(), gfx::Size(400, 400)); 964 owned_mailbox->UpdateSyncPoint(gl_helper->InsertSyncPoint()); 965 966 view_->InitAsChild(NULL); 967 aura::client::ParentWindowWithContext( 968 view_->GetNativeView(), 969 parent_view_->GetNativeView()->GetRootWindow(), 970 gfx::Rect()); 971 view_->SetSize(view_size); 972 view_->WasShown(); 973 974 MockWindowObserver observer; 975 view_->window_->AddObserver(&observer); 976 977 // Swap a frame through the GPU path. 978 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; 979 params.surface_id = widget_host_->surface_id(); 980 params.route_id = widget_host_->GetRoutingID(); 981 memcpy(params.mailbox.name, 982 owned_mailbox->mailbox().name, 983 sizeof(params.mailbox.name)); 984 params.size = view_size; 985 params.scale_factor = 1.f; 986 987 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 988 view_->AcceleratedSurfaceBuffersSwapped(params, 0); 989 testing::Mock::VerifyAndClearExpectations(&observer); 990 991 // DSF = 2 992 params.size = gfx::Size(200, 200); 993 params.scale_factor = 2.f; 994 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 995 view_->AcceleratedSurfaceBuffersSwapped(params, 0); 996 testing::Mock::VerifyAndClearExpectations(&observer); 997 998 // Partial frames though GPU path 999 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params post_params; 1000 post_params.surface_id = widget_host_->surface_id(); 1001 post_params.route_id = widget_host_->GetRoutingID(); 1002 memcpy(post_params.mailbox.name, 1003 owned_mailbox->mailbox().name, 1004 sizeof(params.mailbox.name)); 1005 post_params.surface_size = gfx::Size(200, 200); 1006 post_params.surface_scale_factor = 2.f; 1007 post_params.x = 40; 1008 post_params.y = 40; 1009 post_params.width = 80; 1010 post_params.height = 80; 1011 // rect from params is upside down, and is inflated in RWHVA, just because. 1012 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, 1013 gfx::Rect(19, 39, 42, 42))); 1014 view_->AcceleratedSurfacePostSubBuffer(post_params, 0); 1015 testing::Mock::VerifyAndClearExpectations(&observer); 1016 1017 // Composite-to-mailbox path 1018 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1019 view_->OnSwapCompositorFrame( 1020 0, MakeGLFrame(1.f, view_size, view_rect, owned_mailbox.get())); 1021 testing::Mock::VerifyAndClearExpectations(&observer); 1022 1023 // rect from GL frame is upside down, and is inflated in RWHVA, just because. 1024 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, 1025 gfx::Rect(4, 89, 7, 7))); 1026 view_->OnSwapCompositorFrame( 1027 0, 1028 MakeGLFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5), owned_mailbox.get())); 1029 testing::Mock::VerifyAndClearExpectations(&observer); 1030 1031 // Software path 1032 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1033 view_->OnSwapCompositorFrame(0, MakeSoftwareFrame(1.f, view_size, view_rect)); 1034 testing::Mock::VerifyAndClearExpectations(&observer); 1035 1036 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, 1037 gfx::Rect(5, 5, 5, 5))); 1038 view_->OnSwapCompositorFrame( 1039 0, MakeSoftwareFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5))); 1040 testing::Mock::VerifyAndClearExpectations(&observer); 1041 1042 // Delegated renderer path 1043 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1044 view_->OnSwapCompositorFrame( 1045 0, MakeDelegatedFrame(1.f, view_size, view_rect)); 1046 testing::Mock::VerifyAndClearExpectations(&observer); 1047 1048 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, 1049 gfx::Rect(5, 5, 5, 5))); 1050 view_->OnSwapCompositorFrame( 1051 0, MakeDelegatedFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5))); 1052 testing::Mock::VerifyAndClearExpectations(&observer); 1053 1054 view_->window_->RemoveObserver(&observer); 1055} 1056 1057// Skipped frames should not drop their damage. 1058TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) { 1059 gfx::Rect view_rect(100, 100); 1060 gfx::Size frame_size = view_rect.size(); 1061 1062 view_->InitAsChild(NULL); 1063 aura::client::ParentWindowWithContext( 1064 view_->GetNativeView(), 1065 parent_view_->GetNativeView()->GetRootWindow(), 1066 gfx::Rect()); 1067 view_->SetSize(view_rect.size()); 1068 1069 MockWindowObserver observer; 1070 view_->window_->AddObserver(&observer); 1071 1072 // A full frame of damage. 1073 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1074 view_->OnSwapCompositorFrame( 1075 0, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1076 testing::Mock::VerifyAndClearExpectations(&observer); 1077 view_->RunOnCompositingDidCommit(); 1078 1079 // A partial damage frame. 1080 gfx::Rect partial_view_rect(30, 30, 20, 20); 1081 EXPECT_CALL(observer, 1082 OnWindowPaintScheduled(view_->window_, partial_view_rect)); 1083 view_->OnSwapCompositorFrame( 1084 0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect)); 1085 testing::Mock::VerifyAndClearExpectations(&observer); 1086 view_->RunOnCompositingDidCommit(); 1087 1088 // Lock the compositor. Now we should drop frames. 1089 view_rect = gfx::Rect(150, 150); 1090 view_->SetSize(view_rect.size()); 1091 view_->MaybeCreateResizeLock(); 1092 1093 // This frame is dropped. 1094 gfx::Rect dropped_damage_rect_1(10, 20, 30, 40); 1095 EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0); 1096 view_->OnSwapCompositorFrame( 1097 0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_1)); 1098 testing::Mock::VerifyAndClearExpectations(&observer); 1099 view_->RunOnCompositingDidCommit(); 1100 1101 gfx::Rect dropped_damage_rect_2(40, 50, 10, 20); 1102 EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0); 1103 view_->OnSwapCompositorFrame( 1104 0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_2)); 1105 testing::Mock::VerifyAndClearExpectations(&observer); 1106 view_->RunOnCompositingDidCommit(); 1107 1108 // Unlock the compositor. This frame should damage everything. 1109 frame_size = view_rect.size(); 1110 1111 gfx::Rect new_damage_rect(5, 6, 10, 10); 1112 EXPECT_CALL(observer, 1113 OnWindowPaintScheduled(view_->window_, view_rect)); 1114 view_->OnSwapCompositorFrame( 1115 0, MakeDelegatedFrame(1.f, frame_size, new_damage_rect)); 1116 testing::Mock::VerifyAndClearExpectations(&observer); 1117 view_->RunOnCompositingDidCommit(); 1118 1119 // A partial damage frame, this should not be dropped. 1120 EXPECT_CALL(observer, 1121 OnWindowPaintScheduled(view_->window_, partial_view_rect)); 1122 view_->OnSwapCompositorFrame( 1123 0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect)); 1124 testing::Mock::VerifyAndClearExpectations(&observer); 1125 view_->RunOnCompositingDidCommit(); 1126 1127 1128 view_->window_->RemoveObserver(&observer); 1129} 1130 1131TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) { 1132 gfx::Rect view_rect(100, 100); 1133 gfx::Size frame_size = view_rect.size(); 1134 1135 view_->InitAsChild(NULL); 1136 aura::client::ParentWindowWithContext( 1137 view_->GetNativeView(), 1138 parent_view_->GetNativeView()->GetRootWindow(), 1139 gfx::Rect()); 1140 view_->SetSize(view_rect.size()); 1141 1142 MockWindowObserver observer; 1143 view_->window_->AddObserver(&observer); 1144 1145 // Swap a frame. 1146 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1147 view_->OnSwapCompositorFrame( 1148 0, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1149 testing::Mock::VerifyAndClearExpectations(&observer); 1150 view_->RunOnCompositingDidCommit(); 1151 1152 // Swap a frame with a different surface id. 1153 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1154 view_->OnSwapCompositorFrame( 1155 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1156 testing::Mock::VerifyAndClearExpectations(&observer); 1157 view_->RunOnCompositingDidCommit(); 1158 1159 // Swap an empty frame, with a different surface id. 1160 view_->OnSwapCompositorFrame( 1161 2, MakeDelegatedFrame(1.f, gfx::Size(), gfx::Rect())); 1162 testing::Mock::VerifyAndClearExpectations(&observer); 1163 view_->RunOnCompositingDidCommit(); 1164 1165 // Swap another frame, with a different surface id. 1166 EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect)); 1167 view_->OnSwapCompositorFrame(3, 1168 MakeDelegatedFrame(1.f, frame_size, view_rect)); 1169 testing::Mock::VerifyAndClearExpectations(&observer); 1170 view_->RunOnCompositingDidCommit(); 1171 1172 view_->window_->RemoveObserver(&observer); 1173} 1174 1175TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) { 1176 size_t max_renderer_frames = 1177 RendererFrameManager::GetInstance()->max_number_of_saved_frames(); 1178 ASSERT_LE(2u, max_renderer_frames); 1179 size_t renderer_count = max_renderer_frames + 1; 1180 gfx::Rect view_rect(100, 100); 1181 gfx::Size frame_size = view_rect.size(); 1182 1183 scoped_ptr<RenderWidgetHostImpl * []> hosts( 1184 new RenderWidgetHostImpl* [renderer_count]); 1185 scoped_ptr<FakeRenderWidgetHostViewAura * []> views( 1186 new FakeRenderWidgetHostViewAura* [renderer_count]); 1187 1188 // Create a bunch of renderers. 1189 for (size_t i = 0; i < renderer_count; ++i) { 1190 hosts[i] = new RenderWidgetHostImpl( 1191 &delegate_, process_host_, MSG_ROUTING_NONE, false); 1192 hosts[i]->Init(); 1193 hosts[i]->OnMessageReceived( 1194 ViewHostMsg_DidActivateAcceleratedCompositing(0, true)); 1195 views[i] = new FakeRenderWidgetHostViewAura(hosts[i]); 1196 views[i]->InitAsChild(NULL); 1197 aura::client::ParentWindowWithContext( 1198 views[i]->GetNativeView(), 1199 parent_view_->GetNativeView()->GetRootWindow(), 1200 gfx::Rect()); 1201 views[i]->SetSize(view_rect.size()); 1202 } 1203 1204 // Make each renderer visible, and swap a frame on it, then make it invisible. 1205 for (size_t i = 0; i < renderer_count; ++i) { 1206 views[i]->WasShown(); 1207 views[i]->OnSwapCompositorFrame( 1208 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1209 EXPECT_TRUE(views[i]->frame_provider_); 1210 views[i]->WasHidden(); 1211 } 1212 1213 // There should be max_renderer_frames with a frame in it, and one without it. 1214 // Since the logic is LRU eviction, the first one should be without. 1215 EXPECT_FALSE(views[0]->frame_provider_); 1216 for (size_t i = 1; i < renderer_count; ++i) 1217 EXPECT_TRUE(views[i]->frame_provider_); 1218 1219 // LRU renderer is [0], make it visible, it shouldn't evict anything yet. 1220 views[0]->WasShown(); 1221 EXPECT_FALSE(views[0]->frame_provider_); 1222 EXPECT_TRUE(views[1]->frame_provider_); 1223 1224 // Swap a frame on it, it should evict the next LRU [1]. 1225 views[0]->OnSwapCompositorFrame( 1226 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1227 EXPECT_TRUE(views[0]->frame_provider_); 1228 EXPECT_FALSE(views[1]->frame_provider_); 1229 views[0]->WasHidden(); 1230 1231 // LRU renderer is [1], still hidden. Swap a frame on it, it should evict 1232 // the next LRU [2]. 1233 views[1]->OnSwapCompositorFrame( 1234 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1235 EXPECT_TRUE(views[0]->frame_provider_); 1236 EXPECT_TRUE(views[1]->frame_provider_); 1237 EXPECT_FALSE(views[2]->frame_provider_); 1238 for (size_t i = 3; i < renderer_count; ++i) 1239 EXPECT_TRUE(views[i]->frame_provider_); 1240 1241 // Make all renderers but [0] visible and swap a frame on them, keep [0] 1242 // hidden, it becomes the LRU. 1243 for (size_t i = 1; i < renderer_count; ++i) { 1244 views[i]->WasShown(); 1245 views[i]->OnSwapCompositorFrame( 1246 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1247 EXPECT_TRUE(views[i]->frame_provider_); 1248 } 1249 EXPECT_FALSE(views[0]->frame_provider_); 1250 1251 // Swap a frame on [0], it should be evicted immediately. 1252 views[0]->OnSwapCompositorFrame( 1253 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1254 EXPECT_FALSE(views[0]->frame_provider_); 1255 1256 // Make [0] visible, and swap a frame on it. Nothing should be evicted 1257 // although we're above the limit. 1258 views[0]->WasShown(); 1259 views[0]->OnSwapCompositorFrame( 1260 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1261 for (size_t i = 0; i < renderer_count; ++i) 1262 EXPECT_TRUE(views[i]->frame_provider_); 1263 1264 // Make [0] hidden, it should evict its frame. 1265 views[0]->WasHidden(); 1266 EXPECT_FALSE(views[0]->frame_provider_); 1267 1268 for (size_t i = 0; i < renderer_count; ++i) { 1269 views[i]->Destroy(); 1270 delete hosts[i]; 1271 } 1272} 1273 1274TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) { 1275 size_t max_renderer_frames = 1276 RendererFrameManager::GetInstance()->max_number_of_saved_frames(); 1277 ASSERT_LE(2u, max_renderer_frames); 1278 size_t renderer_count = max_renderer_frames + 1; 1279 gfx::Rect view_rect(100, 100); 1280 gfx::Size frame_size = view_rect.size(); 1281 1282 scoped_ptr<RenderWidgetHostImpl * []> hosts( 1283 new RenderWidgetHostImpl* [renderer_count]); 1284 scoped_ptr<FakeRenderWidgetHostViewAura * []> views( 1285 new FakeRenderWidgetHostViewAura* [renderer_count]); 1286 1287 // Create a bunch of renderers. 1288 for (size_t i = 0; i < renderer_count; ++i) { 1289 hosts[i] = new RenderWidgetHostImpl( 1290 &delegate_, process_host_, MSG_ROUTING_NONE, false); 1291 hosts[i]->Init(); 1292 hosts[i]->OnMessageReceived( 1293 ViewHostMsg_DidActivateAcceleratedCompositing(0, true)); 1294 views[i] = new FakeRenderWidgetHostViewAura(hosts[i]); 1295 views[i]->InitAsChild(NULL); 1296 aura::client::ParentWindowWithContext( 1297 views[i]->GetNativeView(), 1298 parent_view_->GetNativeView()->GetRootWindow(), 1299 gfx::Rect()); 1300 views[i]->SetSize(view_rect.size()); 1301 } 1302 1303 // Make each renderer visible and swap a frame on it. No eviction should 1304 // occur because all frames are visible. 1305 for (size_t i = 0; i < renderer_count; ++i) { 1306 views[i]->WasShown(); 1307 views[i]->OnSwapCompositorFrame( 1308 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1309 EXPECT_TRUE(views[i]->frame_provider_); 1310 } 1311 1312 // If we hide [0], then [0] should be evicted. 1313 views[0]->WasHidden(); 1314 EXPECT_FALSE(views[0]->frame_provider_); 1315 1316 // If we lock [0] before hiding it, then [0] should not be evicted. 1317 views[0]->WasShown(); 1318 views[0]->OnSwapCompositorFrame( 1319 1, MakeDelegatedFrame(1.f, frame_size, view_rect)); 1320 EXPECT_TRUE(views[0]->frame_provider_); 1321 views[0]->LockResources(); 1322 views[0]->WasHidden(); 1323 EXPECT_TRUE(views[0]->frame_provider_); 1324 1325 // If we unlock [0] now, then [0] should be evicted. 1326 views[0]->UnlockResources(); 1327 EXPECT_FALSE(views[0]->frame_provider_); 1328 1329 for (size_t i = 0; i < renderer_count; ++i) { 1330 views[i]->Destroy(); 1331 delete hosts[i]; 1332 } 1333} 1334 1335TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) { 1336 gfx::Rect view_rect(100, 100); 1337 gfx::Size frame_size(100, 100); 1338 1339 view_->InitAsChild(NULL); 1340 aura::client::ParentWindowWithContext( 1341 view_->GetNativeView(), 1342 parent_view_->GetNativeView()->GetRootWindow(), 1343 gfx::Rect()); 1344 view_->SetSize(view_rect.size()); 1345 view_->WasShown(); 1346 1347 // With a 1x DPI UI and 1x DPI Renderer. 1348 view_->OnSwapCompositorFrame( 1349 1, MakeDelegatedFrame(1.f, frame_size, gfx::Rect(frame_size))); 1350 1351 // Save the frame provider. 1352 scoped_refptr<cc::DelegatedFrameProvider> frame_provider = 1353 view_->frame_provider_; 1354 1355 // This frame will have the same number of physical pixels, but has a new 1356 // scale on it. 1357 view_->OnSwapCompositorFrame( 1358 1, MakeDelegatedFrame(2.f, frame_size, gfx::Rect(frame_size))); 1359 1360 // When we get a new frame with the same frame size in physical pixels, but a 1361 // different scale, we should generate a new frame provider, as the final 1362 // result will need to be scaled differently to the screen. 1363 EXPECT_NE(frame_provider.get(), view_->frame_provider_.get()); 1364} 1365 1366class RenderWidgetHostViewAuraCopyRequestTest 1367 : public RenderWidgetHostViewAuraShutdownTest { 1368 public: 1369 RenderWidgetHostViewAuraCopyRequestTest() 1370 : callback_count_(0), result_(false) {} 1371 1372 void CallbackMethod(const base::Closure& quit_closure, bool result) { 1373 result_ = result; 1374 callback_count_++; 1375 quit_closure.Run(); 1376 } 1377 1378 int callback_count_; 1379 bool result_; 1380 1381 private: 1382 DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraCopyRequestTest); 1383}; 1384 1385TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) { 1386 base::RunLoop run_loop; 1387 1388 gfx::Rect view_rect(100, 100); 1389 scoped_ptr<cc::CopyOutputRequest> request; 1390 1391 view_->InitAsChild(NULL); 1392 aura::client::ParentWindowWithContext( 1393 view_->GetNativeView(), 1394 parent_view_->GetNativeView()->GetRootWindow(), 1395 gfx::Rect()); 1396 view_->SetSize(view_rect.size()); 1397 view_->WasShown(); 1398 1399 scoped_ptr<FakeFrameSubscriber> frame_subscriber(new FakeFrameSubscriber( 1400 view_rect.size(), 1401 base::Bind(&RenderWidgetHostViewAuraCopyRequestTest::CallbackMethod, 1402 base::Unretained(this), 1403 run_loop.QuitClosure()))); 1404 1405 EXPECT_EQ(0, callback_count_); 1406 EXPECT_FALSE(view_->last_copy_request_); 1407 1408 view_->BeginFrameSubscription( 1409 frame_subscriber.PassAs<RenderWidgetHostViewFrameSubscriber>()); 1410 view_->OnSwapCompositorFrame( 1411 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect))); 1412 1413 EXPECT_EQ(0, callback_count_); 1414 EXPECT_TRUE(view_->last_copy_request_); 1415 EXPECT_TRUE(view_->last_copy_request_->has_texture_mailbox()); 1416 request = view_->last_copy_request_.Pass(); 1417 1418 // There should be one subscriber texture in flight. 1419 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size()); 1420 1421 // Send back the mailbox included in the request. There's no release callback 1422 // since the mailbox came from the RWHVA originally. 1423 request->SendTextureResult(view_rect.size(), 1424 request->texture_mailbox(), 1425 scoped_ptr<cc::SingleReleaseCallback>()); 1426 1427 // This runs until the callback happens. 1428 run_loop.Run(); 1429 1430 // The callback should succeed. 1431 EXPECT_EQ(0u, view_->active_frame_subscriber_textures_.size()); 1432 EXPECT_EQ(1, callback_count_); 1433 EXPECT_TRUE(result_); 1434 1435 view_->OnSwapCompositorFrame( 1436 1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect))); 1437 1438 EXPECT_EQ(1, callback_count_); 1439 request = view_->last_copy_request_.Pass(); 1440 1441 // There should be one subscriber texture in flight again. 1442 EXPECT_EQ(1u, view_->active_frame_subscriber_textures_.size()); 1443 1444 // Destroy the RenderWidgetHostViewAura and ImageTransportFactory. 1445 TearDownEnvironment(); 1446 1447 // Send back the mailbox included in the request. There's no release callback 1448 // since the mailbox came from the RWHVA originally. 1449 request->SendTextureResult(view_rect.size(), 1450 request->texture_mailbox(), 1451 scoped_ptr<cc::SingleReleaseCallback>()); 1452 1453 // Because the copy request callback may be holding state within it, that 1454 // state must handle the RWHVA and ImageTransportFactory going away before the 1455 // callback is called. This test passes if it does not crash as a result of 1456 // these things being destroyed. 1457 EXPECT_EQ(2, callback_count_); 1458 EXPECT_FALSE(result_); 1459} 1460 1461} // namespace content 1462