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