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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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, &params);
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