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