1 // Copyright 2013 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/renderer/render_widget.h"
6 
7 #include <tuple>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/macros.h"
13 #include "base/optional.h"
14 #include "base/run_loop.h"
15 #include "base/test/metrics/histogram_tester.h"
16 #include "base/test/task_environment.h"
17 #include "base/unguessable_token.h"
18 #include "build/build_config.h"
19 #include "cc/layers/solid_color_layer.h"
20 #include "cc/test/fake_layer_tree_frame_sink.h"
21 #include "cc/trees/layer_tree_host.h"
22 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
23 #include "content/common/frame_replication_state.h"
24 #include "content/common/input/input_handler.mojom.h"
25 #include "content/common/input/synthetic_web_input_event_builders.h"
26 #include "content/common/input_messages.h"
27 #include "content/common/view_messages.h"
28 #include "content/common/visual_properties.h"
29 #include "content/common/widget_messages.h"
30 #include "content/public/common/content_features.h"
31 #include "content/public/test/mock_render_thread.h"
32 #include "content/renderer/input/widget_input_handler_manager.h"
33 #include "content/renderer/render_frame_proxy.h"
34 #include "content/renderer/render_widget_delegate.h"
35 #include "content/renderer/render_widget_screen_metrics_emulator.h"
36 #include "content/test/fake_compositor_dependencies.h"
37 #include "content/test/mock_render_process.h"
38 #include "ipc/ipc_test_sink.h"
39 #include "testing/gmock/include/gmock/gmock.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
42 #include "third_party/blink/public/platform/web_coalesced_input_event.h"
43 #include "third_party/blink/public/web/web_device_emulation_params.h"
44 #include "third_party/blink/public/web/web_external_widget.h"
45 #include "third_party/blink/public/web/web_external_widget_client.h"
46 #include "third_party/blink/public/web/web_frame_widget.h"
47 #include "third_party/blink/public/web/web_local_frame.h"
48 #include "third_party/blink/public/web/web_local_frame_client.h"
49 #include "third_party/blink/public/web/web_view.h"
50 #include "third_party/blink/public/web/web_view_client.h"
51 #include "ui/base/cursor/cursor.h"
52 #include "ui/base/mojom/cursor_type.mojom-shared.h"
53 #include "ui/events/base_event_utils.h"
54 #include "ui/events/blink/web_input_event_traits.h"
55 #include "ui/gfx/geometry/rect.h"
56 
57 using testing::_;
58 
59 namespace ui {
60 
operator ==(const ui::DidOverscrollParams & lhs,const ui::DidOverscrollParams & rhs)61 bool operator==(const ui::DidOverscrollParams& lhs,
62                 const ui::DidOverscrollParams& rhs) {
63   return lhs.accumulated_overscroll == rhs.accumulated_overscroll &&
64          lhs.latest_overscroll_delta == rhs.latest_overscroll_delta &&
65          lhs.current_fling_velocity == rhs.current_fling_velocity &&
66          lhs.causal_event_viewport_point == rhs.causal_event_viewport_point &&
67          lhs.overscroll_behavior == rhs.overscroll_behavior;
68 }
69 
70 }  // namespace ui
71 
72 namespace cc {
73 class AnimationHost;
74 }
75 
76 namespace content {
77 
78 namespace {
79 
80 const char* EVENT_LISTENER_RESULT_HISTOGRAM = "Event.PassiveListeners";
81 
82 // Keep in sync with enum defined in
83 // RenderWidgetInputHandler::LogPassiveEventListenersUma.
84 enum {
85   PASSIVE_LISTENER_UMA_ENUM_PASSIVE,
86   PASSIVE_LISTENER_UMA_ENUM_UNCANCELABLE,
87   PASSIVE_LISTENER_UMA_ENUM_SUPPRESSED,
88   PASSIVE_LISTENER_UMA_ENUM_CANCELABLE,
89   PASSIVE_LISTENER_UMA_ENUM_CANCELABLE_AND_CANCELED,
90   PASSIVE_LISTENER_UMA_ENUM_FORCED_NON_BLOCKING_DUE_TO_FLING,
91   PASSIVE_LISTENER_UMA_ENUM_FORCED_NON_BLOCKING_DUE_TO_MAIN_THREAD_RESPONSIVENESS_DEPRECATED,
92   PASSIVE_LISTENER_UMA_ENUM_COUNT
93 };
94 
95 class MockWidgetInputHandlerHost : public mojom::WidgetInputHandlerHost {
96  public:
MockWidgetInputHandlerHost()97   MockWidgetInputHandlerHost() {}
98 #if defined(OS_ANDROID)
99   MOCK_METHOD4(FallbackCursorModeLockCursor, void(bool, bool, bool, bool));
100 
101   MOCK_METHOD1(FallbackCursorModeSetCursorVisibility, void(bool));
102 #endif
103 
104   MOCK_METHOD1(SetTouchActionFromMain, void(cc::TouchAction));
105 
106   MOCK_METHOD3(SetWhiteListedTouchAction,
107                void(cc::TouchAction, uint32_t, content::InputEventAckState));
108 
109   MOCK_METHOD1(DidOverscroll, void(const ui::DidOverscrollParams&));
110 
111   MOCK_METHOD0(DidStopFlinging, void());
112 
113   MOCK_METHOD0(DidStartScrollingViewport, void());
114 
115   MOCK_METHOD0(ImeCancelComposition, void());
116 
117   MOCK_METHOD2(ImeCompositionRangeChanged,
118                void(const gfx::Range&, const std::vector<gfx::Rect>&));
119 
120   MOCK_METHOD1(SetMouseCapture, void(bool));
121 
122   MOCK_METHOD0(UnlockMouse, void());
123 
124   MOCK_METHOD4(RequestMouseLock,
125                void((bool,
126                      bool,
127                      bool,
128                      mojom::WidgetInputHandlerHost::RequestMouseLockCallback)));
129 
130   MOCK_METHOD2(RequestMouseLockChange,
131                void((bool,
132                      mojom::WidgetInputHandlerHost::RequestMouseLockCallback)));
133 
134   mojo::PendingRemote<mojom::WidgetInputHandlerHost>
BindNewPipeAndPassRemote()135   BindNewPipeAndPassRemote() {
136     return receiver_.BindNewPipeAndPassRemote();
137   }
138 
139  private:
140   mojo::Receiver<mojom::WidgetInputHandlerHost> receiver_{this};
141 
142   DISALLOW_COPY_AND_ASSIGN(MockWidgetInputHandlerHost);
143 };
144 
145 // Since std::unique_ptr isn't copyable we can't use the
146 // MockCallback template.
147 class MockHandledEventCallback {
148  public:
149   MockHandledEventCallback() = default;
150   MOCK_METHOD4_T(Run,
151                  void(InputEventAckState,
152                       const ui::LatencyInfo&,
153                       std::unique_ptr<ui::DidOverscrollParams>&,
154                       base::Optional<cc::TouchAction>));
155 
GetCallback()156   HandledEventCallback GetCallback() {
157     return base::BindOnce(&MockHandledEventCallback::HandleCallback,
158                           base::Unretained(this));
159   }
160 
161  private:
HandleCallback(InputEventAckState ack_state,const ui::LatencyInfo & latency_info,std::unique_ptr<ui::DidOverscrollParams> overscroll,base::Optional<cc::TouchAction> touch_action)162   void HandleCallback(InputEventAckState ack_state,
163                       const ui::LatencyInfo& latency_info,
164                       std::unique_ptr<ui::DidOverscrollParams> overscroll,
165                       base::Optional<cc::TouchAction> touch_action) {
166     Run(ack_state, latency_info, overscroll, touch_action);
167   }
168 
169   DISALLOW_COPY_AND_ASSIGN(MockHandledEventCallback);
170 };
171 
172 class MockWebExternalWidgetClient : public blink::WebExternalWidgetClient {
173  public:
174   MockWebExternalWidgetClient() = default;
175 
176   // WebExternalWidgetClient implementation.
177   MOCK_METHOD1(DidResize, void(const gfx::Size& size));
178   MOCK_METHOD0(DispatchBufferedTouchEvents, blink::WebInputEventResult());
179   MOCK_METHOD1(
180       HandleInputEvent,
181       blink::WebInputEventResult(const blink::WebCoalescedInputEvent&));
182 };
183 
184 }  // namespace
185 
186 class InteractiveRenderWidget : public RenderWidget {
187  public:
InteractiveRenderWidget(CompositorDependencies * compositor_deps)188   explicit InteractiveRenderWidget(CompositorDependencies* compositor_deps)
189       : RenderWidget(++next_routing_id_,
190                      compositor_deps,
191                      blink::mojom::DisplayMode::kUndefined,
192                      /*is_hidden=*/false,
193                      /*never_composited=*/false,
194                      mojo::NullReceiver()) {}
195 
Init(blink::WebWidget * widget,const ScreenInfo & screen_info)196   void Init(blink::WebWidget* widget, const ScreenInfo& screen_info) {
197     Initialize(base::NullCallback(), widget, screen_info);
198 
199     mock_input_handler_host_ = std::make_unique<MockWidgetInputHandlerHost>();
200 
201     widget_input_handler_manager_->AddInterface(
202         mojo::PendingReceiver<mojom::WidgetInputHandler>(),
203         mock_input_handler_host_->BindNewPipeAndPassRemote());
204   }
205 
206   using RenderWidget::Close;
207 
SendInputEvent(const blink::WebInputEvent & event,HandledEventCallback callback)208   void SendInputEvent(const blink::WebInputEvent& event,
209                       HandledEventCallback callback) {
210     HandleInputEvent(blink::WebCoalescedInputEvent(
211                          event, std::vector<const blink::WebInputEvent*>(),
212                          std::vector<const blink::WebInputEvent*>()),
213                      ui::LatencyInfo(), std::move(callback));
214   }
215 
set_always_overscroll(bool overscroll)216   void set_always_overscroll(bool overscroll) {
217     always_overscroll_ = overscroll;
218   }
219 
sink()220   IPC::TestSink* sink() { return &sink_; }
221 
mock_input_handler_host()222   MockWidgetInputHandlerHost* mock_input_handler_host() {
223     return mock_input_handler_host_.get();
224   }
225 
local_surface_id_allocation_from_parent() const226   const viz::LocalSurfaceIdAllocation& local_surface_id_allocation_from_parent()
227       const {
228     return local_surface_id_allocation_from_parent_;
229   }
230 
231  protected:
232   // Overridden from RenderWidget:
WillHandleGestureEvent(const blink::WebGestureEvent & event)233   bool WillHandleGestureEvent(const blink::WebGestureEvent& event) override {
234     if (always_overscroll_ &&
235         event.GetType() == blink::WebInputEvent::kGestureScrollUpdate) {
236       DidOverscroll(gfx::Vector2dF(event.data.scroll_update.delta_x,
237                                    event.data.scroll_update.delta_y),
238                     gfx::Vector2dF(event.data.scroll_update.delta_x,
239                                    event.data.scroll_update.delta_y),
240                     event.PositionInWidget(),
241                     gfx::Vector2dF(event.data.scroll_update.velocity_x,
242                                    event.data.scroll_update.velocity_y));
243       return true;
244     }
245 
246     return false;
247   }
248 
Send(IPC::Message * msg)249   bool Send(IPC::Message* msg) override {
250     sink_.OnMessageReceived(*msg);
251     delete msg;
252     return true;
253   }
254 
255  private:
256   IPC::TestSink sink_;
257   bool always_overscroll_ = false;
258   std::unique_ptr<MockWidgetInputHandlerHost> mock_input_handler_host_;
259   static int next_routing_id_;
260 
261   DISALLOW_COPY_AND_ASSIGN(InteractiveRenderWidget);
262 };
263 
264 int InteractiveRenderWidget::next_routing_id_ = 0;
265 
266 class RenderWidgetUnittest : public testing::Test {
267  public:
SetUp()268   void SetUp() override {
269     web_view_ = blink::WebView::Create(/*client=*/&web_view_client_,
270                                        /*is_hidden=*/false,
271                                        /*compositing_enabled=*/true, nullptr,
272                                        mojo::ScopedInterfaceEndpointHandle());
273     widget_ = std::make_unique<InteractiveRenderWidget>(&compositor_deps_);
274     web_local_frame_ = blink::WebLocalFrame::CreateMainFrame(
275         web_view_, &web_frame_client_, nullptr, nullptr);
276     web_frame_widget_ = blink::WebFrameWidget::CreateForMainFrame(
277         widget_.get(), web_local_frame_,
278         blink::CrossVariantMojoAssociatedRemote<
279             blink::mojom::FrameWidgetHostInterfaceBase>(),
280         blink::CrossVariantMojoAssociatedReceiver<
281             blink::mojom::FrameWidgetInterfaceBase>(),
282         blink::CrossVariantMojoAssociatedRemote<
283             blink::mojom::WidgetHostInterfaceBase>(),
284         blink::CrossVariantMojoAssociatedReceiver<
285             blink::mojom::WidgetInterfaceBase>());
286     widget_->Init(web_frame_widget_, ScreenInfo());
287     web_view_->DidAttachLocalMainFrame();
288   }
289 
TearDown()290   void TearDown() override {
291     widget_->Close(std::move(widget_));
292     web_local_frame_ = nullptr;
293     web_frame_widget_ = nullptr;
294     web_view_ = nullptr;
295     // RenderWidget::Close() posts some destruction. Don't leak them.
296     base::RunLoop loop;
297     compositor_deps_.GetCleanupTaskRunner()->PostTask(FROM_HERE,
298                                                       loop.QuitClosure());
299     loop.Run();
300   }
301 
widget() const302   InteractiveRenderWidget* widget() const { return widget_.get(); }
303 
frame_widget() const304   blink::WebFrameWidget* frame_widget() const { return web_frame_widget_; }
305 
histogram_tester() const306   const base::HistogramTester& histogram_tester() const {
307     return histogram_tester_;
308   }
309 
GetFrameSink()310   cc::FakeLayerTreeFrameSink* GetFrameSink() {
311     return compositor_deps_.last_created_frame_sink();
312   }
313 
314  private:
315   base::test::TaskEnvironment task_environment_;
316   MockRenderProcess render_process_;
317   MockRenderThread render_thread_;
318   blink::WebViewClient web_view_client_;
319   blink::WebView* web_view_;
320   blink::WebLocalFrame* web_local_frame_;
321   blink::WebFrameWidget* web_frame_widget_;
322   blink::WebLocalFrameClient web_frame_client_;
323   FakeCompositorDependencies compositor_deps_;
324   std::unique_ptr<InteractiveRenderWidget> widget_;
325   base::HistogramTester histogram_tester_;
326 };
327 
328 class RenderWidgetExternalWidgetUnittest : public testing::Test {
329  public:
SetUp()330   void SetUp() override {
331     external_web_widget_ = blink::WebExternalWidget::Create(
332         &mock_web_external_widget_client_, blink::WebURL(),
333         blink::CrossVariantMojoAssociatedRemote<
334             blink::mojom::WidgetHostInterfaceBase>(),
335         blink::CrossVariantMojoAssociatedReceiver<
336             blink::mojom::WidgetInterfaceBase>());
337 
338     widget_ = std::make_unique<InteractiveRenderWidget>(&compositor_deps_);
339     widget_->Init(external_web_widget_.get(), ScreenInfo());
340   }
341 
TearDown()342   void TearDown() override {
343     widget_->Close(std::move(widget_));
344     // RenderWidget::Close() posts some destruction. Don't leak them.
345     base::RunLoop loop;
346     compositor_deps_.GetCleanupTaskRunner()->PostTask(FROM_HERE,
347                                                       loop.QuitClosure());
348     loop.Run();
349   }
350 
widget() const351   InteractiveRenderWidget* widget() const { return widget_.get(); }
352 
mock_web_external_widget_client()353   MockWebExternalWidgetClient* mock_web_external_widget_client() {
354     return &mock_web_external_widget_client_;
355   }
356 
external_web_widget()357   blink::WebExternalWidget* external_web_widget() {
358     return external_web_widget_.get();
359   }
360 
histogram_tester() const361   const base::HistogramTester& histogram_tester() const {
362     return histogram_tester_;
363   }
364 
GetFrameSink()365   cc::FakeLayerTreeFrameSink* GetFrameSink() {
366     return compositor_deps_.last_created_frame_sink();
367   }
368 
369  private:
370   base::test::TaskEnvironment task_environment_;
371   MockRenderProcess render_process_;
372   MockRenderThread render_thread_;
373   FakeCompositorDependencies compositor_deps_;
374   MockWebExternalWidgetClient mock_web_external_widget_client_;
375   std::unique_ptr<blink::WebExternalWidget> external_web_widget_;
376   std::unique_ptr<InteractiveRenderWidget> widget_;
377   base::HistogramTester histogram_tester_;
378 };
379 
TEST_F(RenderWidgetExternalWidgetUnittest,CursorChange)380 TEST_F(RenderWidgetExternalWidgetUnittest, CursorChange) {
381   ui::Cursor cursor;
382 
383   widget()->DidChangeCursor(cursor);
384   EXPECT_EQ(widget()->sink()->message_count(), 1U);
385   EXPECT_EQ(widget()->sink()->GetMessageAt(0)->type(),
386             WidgetHostMsg_SetCursor::ID);
387   widget()->sink()->ClearMessages();
388 
389   widget()->DidChangeCursor(cursor);
390   EXPECT_EQ(widget()->sink()->message_count(), 0U);
391 
392   EXPECT_CALL(*mock_web_external_widget_client(), HandleInputEvent(_))
393       .WillOnce(::testing::Return(blink::WebInputEventResult::kNotHandled));
394   widget()->SendInputEvent(SyntheticWebMouseEventBuilder::Build(
395                                blink::WebInputEvent::Type::kMouseLeave),
396                            HandledEventCallback());
397   EXPECT_EQ(widget()->sink()->message_count(), 0U);
398 
399   widget()->DidChangeCursor(cursor);
400   EXPECT_EQ(widget()->sink()->message_count(), 1U);
401   EXPECT_EQ(widget()->sink()->GetMessageAt(0)->type(),
402             WidgetHostMsg_SetCursor::ID);
403 }
404 
TEST_F(RenderWidgetExternalWidgetUnittest,EventOverscroll)405 TEST_F(RenderWidgetExternalWidgetUnittest, EventOverscroll) {
406   widget()->set_always_overscroll(true);
407 
408   EXPECT_CALL(*mock_web_external_widget_client(), HandleInputEvent(_))
409       .WillRepeatedly(
410           ::testing::Return(blink::WebInputEventResult::kNotHandled));
411 
412   blink::WebGestureEvent scroll(blink::WebInputEvent::kGestureScrollUpdate,
413                                 blink::WebInputEvent::kNoModifiers,
414                                 ui::EventTimeForNow());
415   scroll.SetPositionInWidget(gfx::PointF(-10, 0));
416   scroll.data.scroll_update.delta_y = 10;
417   MockHandledEventCallback handled_event;
418 
419   ui::DidOverscrollParams expected_overscroll;
420   expected_overscroll.latest_overscroll_delta = gfx::Vector2dF(0, 10);
421   expected_overscroll.accumulated_overscroll = gfx::Vector2dF(0, 10);
422   expected_overscroll.causal_event_viewport_point = gfx::PointF(-10, 0);
423   expected_overscroll.current_fling_velocity = gfx::Vector2dF();
424 
425   // Overscroll notifications received while handling an input event should
426   // be bundled with the event ack IPC.
427   EXPECT_CALL(handled_event, Run(INPUT_EVENT_ACK_STATE_CONSUMED, _,
428                                  testing::Pointee(expected_overscroll), _))
429       .Times(1);
430 
431   widget()->SendInputEvent(scroll, handled_event.GetCallback());
432 }
433 
TEST_F(RenderWidgetExternalWidgetUnittest,RenderWidgetInputEventUmaMetrics)434 TEST_F(RenderWidgetExternalWidgetUnittest, RenderWidgetInputEventUmaMetrics) {
435   SyntheticWebTouchEvent touch;
436   touch.PressPoint(10, 10);
437   touch.touch_start_or_first_touch_move = true;
438 
439   EXPECT_CALL(*mock_web_external_widget_client(), HandleInputEvent(_))
440       .Times(5)
441       .WillRepeatedly(
442           ::testing::Return(blink::WebInputEventResult::kNotHandled));
443 
444   EXPECT_CALL(*mock_web_external_widget_client(), DispatchBufferedTouchEvents())
445       .Times(5)
446       .WillRepeatedly(
447           ::testing::Return(blink::WebInputEventResult::kNotHandled));
448 
449   widget()->SendInputEvent(touch, HandledEventCallback());
450   histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM,
451                                        PASSIVE_LISTENER_UMA_ENUM_CANCELABLE, 1);
452 
453   touch.dispatch_type = blink::WebInputEvent::DispatchType::kEventNonBlocking;
454   widget()->SendInputEvent(touch, HandledEventCallback());
455   histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM,
456                                        PASSIVE_LISTENER_UMA_ENUM_UNCANCELABLE,
457                                        1);
458 
459   touch.dispatch_type =
460       blink::WebInputEvent::DispatchType::kListenersNonBlockingPassive;
461   widget()->SendInputEvent(touch, HandledEventCallback());
462   histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM,
463                                        PASSIVE_LISTENER_UMA_ENUM_PASSIVE, 1);
464 
465   touch.dispatch_type =
466       blink::WebInputEvent::DispatchType::kListenersForcedNonBlockingDueToFling;
467   widget()->SendInputEvent(touch, HandledEventCallback());
468   histogram_tester().ExpectBucketCount(
469       EVENT_LISTENER_RESULT_HISTOGRAM,
470       PASSIVE_LISTENER_UMA_ENUM_FORCED_NON_BLOCKING_DUE_TO_FLING, 1);
471 
472   touch.MovePoint(0, 10, 10);
473   touch.touch_start_or_first_touch_move = true;
474   touch.dispatch_type =
475       blink::WebInputEvent::DispatchType::kListenersForcedNonBlockingDueToFling;
476   widget()->SendInputEvent(touch, HandledEventCallback());
477   histogram_tester().ExpectBucketCount(
478       EVENT_LISTENER_RESULT_HISTOGRAM,
479       PASSIVE_LISTENER_UMA_ENUM_FORCED_NON_BLOCKING_DUE_TO_FLING, 2);
480 
481   EXPECT_CALL(*mock_web_external_widget_client(), HandleInputEvent(_))
482       .WillOnce(::testing::Return(blink::WebInputEventResult::kNotHandled));
483   EXPECT_CALL(*mock_web_external_widget_client(), DispatchBufferedTouchEvents())
484       .WillOnce(
485           ::testing::Return(blink::WebInputEventResult::kHandledSuppressed));
486   touch.dispatch_type = blink::WebInputEvent::DispatchType::kBlocking;
487   widget()->SendInputEvent(touch, HandledEventCallback());
488   histogram_tester().ExpectBucketCount(EVENT_LISTENER_RESULT_HISTOGRAM,
489                                        PASSIVE_LISTENER_UMA_ENUM_SUPPRESSED, 1);
490 
491   EXPECT_CALL(*mock_web_external_widget_client(), HandleInputEvent(_))
492       .WillOnce(::testing::Return(blink::WebInputEventResult::kNotHandled));
493   EXPECT_CALL(*mock_web_external_widget_client(), DispatchBufferedTouchEvents())
494       .WillOnce(
495           ::testing::Return(blink::WebInputEventResult::kHandledApplication));
496   touch.dispatch_type = blink::WebInputEvent::DispatchType::kBlocking;
497   widget()->SendInputEvent(touch, HandledEventCallback());
498   histogram_tester().ExpectBucketCount(
499       EVENT_LISTENER_RESULT_HISTOGRAM,
500       PASSIVE_LISTENER_UMA_ENUM_CANCELABLE_AND_CANCELED, 1);
501 }
502 
503 // Tests that if a RenderWidget is auto-resized, it requests a new
504 // viz::LocalSurfaceId to be allocated on the impl thread.
TEST_F(RenderWidgetUnittest,AutoResizeAllocatedLocalSurfaceId)505 TEST_F(RenderWidgetUnittest, AutoResizeAllocatedLocalSurfaceId) {
506   viz::ParentLocalSurfaceIdAllocator allocator;
507 
508   // Enable auto-resize.
509   content::VisualProperties visual_properties;
510   visual_properties.auto_resize_enabled = true;
511   visual_properties.min_size_for_auto_resize = gfx::Size(100, 100);
512   visual_properties.max_size_for_auto_resize = gfx::Size(200, 200);
513   allocator.GenerateId();
514   visual_properties.local_surface_id_allocation =
515       allocator.GetCurrentLocalSurfaceIdAllocation();
516   {
517     WidgetMsg_UpdateVisualProperties msg(widget()->routing_id(),
518                                          visual_properties);
519     widget()->OnMessageReceived(msg);
520   }
521   EXPECT_EQ(allocator.GetCurrentLocalSurfaceIdAllocation(),
522             widget()->local_surface_id_allocation_from_parent());
523   EXPECT_FALSE(widget()
524                    ->layer_tree_host()
525                    ->new_local_surface_id_request_for_testing());
526 
527   constexpr gfx::Size size(200, 200);
528   widget()->DidAutoResize(size);
529   EXPECT_EQ(allocator.GetCurrentLocalSurfaceIdAllocation(),
530             widget()->local_surface_id_allocation_from_parent());
531   EXPECT_TRUE(widget()
532                   ->layer_tree_host()
533                   ->new_local_surface_id_request_for_testing());
534 }
535 
536 class StubRenderWidgetDelegate : public RenderWidgetDelegate {
537  public:
SetActiveForWidget(bool active)538   void SetActiveForWidget(bool active) override {}
SupportsMultipleWindowsForWidget()539   bool SupportsMultipleWindowsForWidget() override { return true; }
ShouldAckSyntheticInputImmediately()540   bool ShouldAckSyntheticInputImmediately() override { return true; }
ApplyNewDisplayModeForWidget(blink::mojom::DisplayMode new_display_mode)541   void ApplyNewDisplayModeForWidget(
542       blink::mojom::DisplayMode new_display_mode) override {}
ApplyAutoResizeLimitsForWidget(const gfx::Size & min_size,const gfx::Size & max_size)543   void ApplyAutoResizeLimitsForWidget(const gfx::Size& min_size,
544                                       const gfx::Size& max_size) override {}
DisableAutoResizeForWidget()545   void DisableAutoResizeForWidget() override {}
ScrollFocusedNodeIntoViewForWidget()546   void ScrollFocusedNodeIntoViewForWidget() override {}
DidReceiveSetFocusEventForWidget()547   void DidReceiveSetFocusEventForWidget() override {}
DidCommitCompositorFrameForWidget()548   void DidCommitCompositorFrameForWidget() override {}
DidCompletePageScaleAnimationForWidget()549   void DidCompletePageScaleAnimationForWidget() override {}
ResizeWebWidgetForWidget(const gfx::Size & main_frame_widget_size,const gfx::Size & visible_viewport_size,cc::BrowserControlsParams)550   void ResizeWebWidgetForWidget(const gfx::Size& main_frame_widget_size,
551                                 const gfx::Size& visible_viewport_size,
552                                 cc::BrowserControlsParams) override {}
SetScreenMetricsEmulationParametersForWidget(bool enabled,const blink::WebDeviceEmulationParams & params)553   void SetScreenMetricsEmulationParametersForWidget(
554       bool enabled,
555       const blink::WebDeviceEmulationParams& params) override {}
556 };
557 
558 // Tests that the value of VisualProperties::is_pinch_gesture_active is
559 // propagated to the LayerTreeHost when properties are synced for subframes.
TEST_F(RenderWidgetUnittest,ActivePinchGestureUpdatesLayerTreeHostSubFrame)560 TEST_F(RenderWidgetUnittest, ActivePinchGestureUpdatesLayerTreeHostSubFrame) {
561   cc::LayerTreeHost* layer_tree_host = widget()->layer_tree_host();
562   EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
563   content::VisualProperties visual_properties;
564 
565   // Sync visual properties on a child RenderWidget.
566   visual_properties.is_pinch_gesture_active = true;
567   {
568     WidgetMsg_UpdateVisualProperties msg(widget()->routing_id(),
569                                          visual_properties);
570     widget()->OnMessageReceived(msg);
571   }
572   // We expect the |is_pinch_gesture_active| value to propagate to the
573   // LayerTreeHost for sub-frames. Since GesturePinch events are handled
574   // directly in the main-frame's layer tree (and only there), information about
575   // whether or not we're in a pinch gesture must be communicated separately to
576   // sub-frame layer trees, via OnUpdateVisualProperties. This information
577   // is required to allow sub-frame compositors to throttle rastering while
578   // pinch gestures are active.
579   EXPECT_TRUE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
580   visual_properties.is_pinch_gesture_active = false;
581   {
582     WidgetMsg_UpdateVisualProperties msg(widget()->routing_id(),
583                                          visual_properties);
584     widget()->OnMessageReceived(msg);
585   }
586   EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
587 }
588 
589 // Verify desktop memory limit calculations.
590 #if !defined(OS_ANDROID)
TEST(RenderWidgetTest,IgnoreGivenMemoryPolicy)591 TEST(RenderWidgetTest, IgnoreGivenMemoryPolicy) {
592   auto policy = RenderWidget::GetGpuMemoryPolicy(cc::ManagedMemoryPolicy(256),
593                                                  gfx::Size(), 1.f);
594   EXPECT_EQ(512u * 1024u * 1024u, policy.bytes_limit_when_visible);
595   EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
596             policy.priority_cutoff_when_visible);
597 }
598 
TEST(RenderWidgetTest,LargeScreensUseMoreMemory)599 TEST(RenderWidgetTest, LargeScreensUseMoreMemory) {
600   auto policy = RenderWidget::GetGpuMemoryPolicy(cc::ManagedMemoryPolicy(256),
601                                                  gfx::Size(4096, 2160), 1.f);
602   EXPECT_EQ(2u * 512u * 1024u * 1024u, policy.bytes_limit_when_visible);
603   EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
604             policy.priority_cutoff_when_visible);
605 
606   policy = RenderWidget::GetGpuMemoryPolicy(cc::ManagedMemoryPolicy(256),
607                                             gfx::Size(2048, 1080), 2.f);
608   EXPECT_EQ(2u * 512u * 1024u * 1024u, policy.bytes_limit_when_visible);
609   EXPECT_EQ(gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
610             policy.priority_cutoff_when_visible);
611 }
612 #endif
613 
614 #if defined(OS_ANDROID)
TEST_F(RenderWidgetUnittest,ForceSendMetadataOnInput)615 TEST_F(RenderWidgetUnittest, ForceSendMetadataOnInput) {
616   cc::LayerTreeHost* layer_tree_host = widget()->layer_tree_host();
617   // We should not have any force send metadata requests at start.
618   EXPECT_FALSE(layer_tree_host->TakeForceSendMetadataRequest());
619   // ShowVirtualKeyboard will trigger a text input state update.
620   widget()->ShowVirtualKeyboard();
621   // We should now have a force send metadata request.
622   EXPECT_TRUE(layer_tree_host->TakeForceSendMetadataRequest());
623 }
624 #endif  // !defined(OS_ANDROID)
625 
626 class NotifySwapTimesRenderWidgetUnittest : public RenderWidgetUnittest {
627  public:
SetUp()628   void SetUp() override {
629     RenderWidgetUnittest::SetUp();
630 
631     viz::ParentLocalSurfaceIdAllocator allocator;
632     WidgetMsg_WasShown msg(widget()->routing_id(),
633                            /*show_request_timestamp=*/base::TimeTicks(),
634                            /*was_evicted=*/false,
635                            /*record_tab_switch_time_request=*/base::nullopt);
636     widget()->OnMessageReceived(msg);
637 
638     // TODO(danakj): This usually happens through
639     // RenderWidget::OnUpdateVisualProperties() and we are cutting past that for
640     // some reason.
641     allocator.GenerateId();
642     widget()->layer_tree_host()->SetViewportRectAndScale(
643         gfx::Rect(200, 100), 1.f,
644         allocator.GetCurrentLocalSurfaceIdAllocation());
645 
646     auto root_layer = cc::SolidColorLayer::Create();
647     root_layer->SetBounds(gfx::Size(200, 100));
648     root_layer->SetBackgroundColor(SK_ColorGREEN);
649     widget()->layer_tree_host()->SetNonBlinkManagedRootLayer(root_layer);
650 
651     auto color_layer = cc::SolidColorLayer::Create();
652     color_layer->SetBounds(gfx::Size(100, 100));
653     root_layer->AddChild(color_layer);
654     color_layer->SetBackgroundColor(SK_ColorRED);
655   }
656 
657   // |swap_to_presentation| determines how long after swap should presentation
658   // happen. This can be negative, positive, or zero. If zero, an invalid (null)
659   // presentation time is used.
CompositeAndWaitForPresentation(base::TimeDelta swap_to_presentation)660   void CompositeAndWaitForPresentation(base::TimeDelta swap_to_presentation) {
661     base::RunLoop swap_run_loop;
662     base::RunLoop presentation_run_loop;
663 
664     // Register callbacks for swap time and presentation time.
665     base::TimeTicks swap_time;
666     frame_widget()->NotifySwapAndPresentationTime(
667         base::BindOnce(
668             [](base::OnceClosure swap_quit_closure, base::TimeTicks* swap_time,
669                blink::WebSwapResult result, base::TimeTicks timestamp) {
670               DCHECK(!timestamp.is_null());
671               *swap_time = timestamp;
672               std::move(swap_quit_closure).Run();
673             },
674             swap_run_loop.QuitClosure(), &swap_time),
675         base::BindOnce(
676             [](base::OnceClosure presentation_quit_closure,
677                blink::WebSwapResult result, base::TimeTicks timestamp) {
678               DCHECK(!timestamp.is_null());
679               std::move(presentation_quit_closure).Run();
680             },
681             presentation_run_loop.QuitClosure()));
682 
683     // Composite and wait for the swap to complete.
684     widget()->layer_tree_host()->Composite(base::TimeTicks::Now(),
685                                            /*raster=*/true);
686     swap_run_loop.Run();
687 
688     // Present and wait for it to complete.
689     viz::FrameTimingDetails timing_details;
690     if (!swap_to_presentation.is_zero()) {
691       timing_details.presentation_feedback = gfx::PresentationFeedback(
692           /*presentation_time=*/swap_time + swap_to_presentation,
693           base::TimeDelta::FromMilliseconds(16), 0);
694     }
695     GetFrameSink()->NotifyDidPresentCompositorFrame(1, timing_details);
696     presentation_run_loop.Run();
697   }
698 };
699 
TEST_F(NotifySwapTimesRenderWidgetUnittest,PresentationTimestampValid)700 TEST_F(NotifySwapTimesRenderWidgetUnittest, PresentationTimestampValid) {
701   base::HistogramTester histograms;
702 
703   CompositeAndWaitForPresentation(base::TimeDelta::FromMilliseconds(2));
704 
705   EXPECT_THAT(histograms.GetAllSamples(
706                   "PageLoad.Internal.Renderer.PresentationTime.Valid"),
707               testing::ElementsAre(base::Bucket(true, 1)));
708   EXPECT_THAT(
709       histograms.GetAllSamples(
710           "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"),
711       testing::ElementsAre(base::Bucket(2, 1)));
712 }
713 
TEST_F(NotifySwapTimesRenderWidgetUnittest,PresentationTimestampInvalid)714 TEST_F(NotifySwapTimesRenderWidgetUnittest, PresentationTimestampInvalid) {
715   base::HistogramTester histograms;
716 
717   CompositeAndWaitForPresentation(base::TimeDelta());
718 
719   EXPECT_THAT(histograms.GetAllSamples(
720                   "PageLoad.Internal.Renderer.PresentationTime.Valid"),
721               testing::ElementsAre(base::Bucket(false, 1)));
722   EXPECT_THAT(
723       histograms.GetAllSamples(
724           "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"),
725       testing::IsEmpty());
726 }
727 
TEST_F(NotifySwapTimesRenderWidgetUnittest,PresentationTimestampEarlierThanSwaptime)728 TEST_F(NotifySwapTimesRenderWidgetUnittest,
729        PresentationTimestampEarlierThanSwaptime) {
730   base::HistogramTester histograms;
731 
732   CompositeAndWaitForPresentation(base::TimeDelta::FromMilliseconds(-2));
733 
734   EXPECT_THAT(histograms.GetAllSamples(
735                   "PageLoad.Internal.Renderer.PresentationTime.Valid"),
736               testing::ElementsAre(base::Bucket(false, 1)));
737   EXPECT_THAT(
738       histograms.GetAllSamples(
739           "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"),
740       testing::IsEmpty());
741 }
742 
743 }  // namespace content
744