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