1 // Copyright 2014 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_child_frame.h"
6 
7 #include <stdint.h>
8 
9 #include <tuple>
10 #include <utility>
11 
12 #include "base/macros.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "base/test/task_environment.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "build/build_config.h"
19 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
20 #include "components/viz/test/begin_frame_args_test.h"
21 #include "components/viz/test/fake_external_begin_frame_source.h"
22 #include "content/browser/compositor/test/test_image_transport_factory.h"
23 #include "content/browser/gpu/compositor_util.h"
24 #include "content/browser/renderer_host/frame_connector_delegate.h"
25 #include "content/browser/renderer_host/frame_token_message_queue.h"
26 #include "content/browser/renderer_host/render_widget_host_delegate.h"
27 #include "content/browser/renderer_host/render_widget_host_impl.h"
28 #include "content/common/frame_visual_properties.h"
29 #include "content/common/view_messages.h"
30 #include "content/common/widget_messages.h"
31 #include "content/public/browser/render_widget_host_view.h"
32 #include "content/public/test/browser_task_environment.h"
33 #include "content/public/test/mock_render_process_host.h"
34 #include "content/public/test/test_browser_context.h"
35 #include "content/test/mock_render_widget_host_delegate.h"
36 #include "content/test/mock_widget_impl.h"
37 #include "content/test/test_render_view_host.h"
38 #include "mojo/public/cpp/bindings/pending_receiver.h"
39 #include "mojo/public/cpp/bindings/pending_remote.h"
40 #include "mojo/public/cpp/bindings/remote.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/blink/public/platform/viewport_intersection_state.h"
43 #include "ui/base/ui_base_features.h"
44 #include "ui/compositor/compositor.h"
45 
46 namespace content {
47 namespace {
48 
49 const viz::LocalSurfaceId kArbitraryLocalSurfaceId(
50     1,
51     base::UnguessableToken::Deserialize(2, 3));
52 
53 }  // namespace
54 
55 class MockFrameConnectorDelegate : public FrameConnectorDelegate {
56  public:
MockFrameConnectorDelegate(bool use_zoom_for_device_scale_factor)57   MockFrameConnectorDelegate(bool use_zoom_for_device_scale_factor)
58       : FrameConnectorDelegate(use_zoom_for_device_scale_factor) {}
~MockFrameConnectorDelegate()59   ~MockFrameConnectorDelegate() override {}
60 
FirstSurfaceActivation(const viz::SurfaceInfo & surface_info)61   void FirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override {
62     last_surface_info_ = surface_info;
63   }
64 
SetViewportIntersection(const blink::WebRect & viewport_intersection,const blink::WebRect & main_frame_document_intersection,const blink::WebRect & compositor_visible_rect,blink::FrameOcclusionState occlusion_state)65   void SetViewportIntersection(
66       const blink::WebRect& viewport_intersection,
67       const blink::WebRect& main_frame_document_intersection,
68       const blink::WebRect& compositor_visible_rect,
69       blink::FrameOcclusionState occlusion_state) {
70     intersection_state_.viewport_intersection = viewport_intersection;
71     intersection_state_.main_frame_document_intersection =
72         main_frame_document_intersection;
73     intersection_state_.compositor_visible_rect = compositor_visible_rect;
74     intersection_state_.occlusion_state = occlusion_state;
75   }
76 
GetParentRenderWidgetHostView()77   RenderWidgetHostViewBase* GetParentRenderWidgetHostView() override {
78     return nullptr;
79   }
80 
BubbleScrollEvent(const blink::WebGestureEvent & event)81   bool BubbleScrollEvent(const blink::WebGestureEvent& event) override {
82     last_bubbled_event_type_ = event.GetType();
83     return can_bubble_;
84   }
85 
GetAndResetLastBubbledEventType()86   blink::WebInputEvent::Type GetAndResetLastBubbledEventType() {
87     blink::WebInputEvent::Type last = last_bubbled_event_type_;
88     last_bubbled_event_type_ = blink::WebInputEvent::kUndefined;
89     return last;
90   }
91 
SetCanBubble(bool can_bubble)92   void SetCanBubble(bool can_bubble) { can_bubble_ = can_bubble; }
93 
94   viz::SurfaceInfo last_surface_info_;
95 
96  private:
97   blink::WebInputEvent::Type last_bubbled_event_type_ =
98       blink::WebInputEvent::kUndefined;
99   bool can_bubble_ = true;
100 };
101 
102 class RenderWidgetHostViewChildFrameTest : public testing::Test {
103  public:
RenderWidgetHostViewChildFrameTest()104   RenderWidgetHostViewChildFrameTest() {}
105 
SetUp()106   void SetUp() override {
107     SetUpEnvironment(false /* use_zoom_for_device_scale_factor */);
108   }
109 
SetUpEnvironment(bool use_zoom_for_device_scale_factor)110   void SetUpEnvironment(bool use_zoom_for_device_scale_factor) {
111     browser_context_.reset(new TestBrowserContext);
112 
113 // ImageTransportFactory doesn't exist on Android.
114 #if !defined(OS_ANDROID)
115     ImageTransportFactory::SetFactory(
116         std::make_unique<TestImageTransportFactory>());
117 #endif
118 
119     MockRenderProcessHost* process_host =
120         new MockRenderProcessHost(browser_context_.get());
121 
122     int32_t routing_id = process_host->GetNextRoutingID();
123     sink_ = &process_host->sink();
124 
125     mojo::PendingRemote<mojom::Widget> widget;
126     widget_impl_ = std::make_unique<MockWidgetImpl>(
127         widget.InitWithNewPipeAndPassReceiver());
128     widget_host_ = new RenderWidgetHostImpl(
129         &delegate_, process_host, routing_id, std::move(widget),
130         /*hidden=*/false, std::make_unique<FrameTokenMessageQueue>());
131     view_ = RenderWidgetHostViewChildFrame::Create(widget_host_);
132 
133     test_frame_connector_ =
134         new MockFrameConnectorDelegate(use_zoom_for_device_scale_factor);
135     test_frame_connector_->SetView(view_);
136     view_->SetFrameConnectorDelegate(test_frame_connector_);
137   }
138 
TearDown()139   void TearDown() override {
140     sink_ = nullptr;
141     if (view_)
142       view_->Destroy();
143     delete widget_host_;
144     delete test_frame_connector_;
145 
146     browser_context_.reset();
147 
148     base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
149                                                     browser_context_.release());
150     base::RunLoop().RunUntilIdle();
151 #if !defined(OS_ANDROID)
152     ImageTransportFactory::Terminate();
153 #endif
154   }
155 
GetSurfaceId() const156   viz::SurfaceId GetSurfaceId() const {
157     return view_->last_activated_surface_info_.id();
158   }
159 
GetLocalSurfaceId() const160   viz::LocalSurfaceId GetLocalSurfaceId() const {
161     return GetSurfaceId().local_surface_id();
162   }
163 
164  protected:
165   BrowserTaskEnvironment task_environment_;
166 
167   std::unique_ptr<BrowserContext> browser_context_;
168   IPC::TestSink* sink_ = nullptr;
169   MockRenderWidgetHostDelegate delegate_;
170 
171   // Tests should set these to NULL if they've already triggered their
172   // destruction.
173   std::unique_ptr<MockWidgetImpl> widget_impl_;
174   RenderWidgetHostImpl* widget_host_;
175   RenderWidgetHostViewChildFrame* view_;
176   MockFrameConnectorDelegate* test_frame_connector_;
177 };
178 
TEST_F(RenderWidgetHostViewChildFrameTest,VisibilityTest)179 TEST_F(RenderWidgetHostViewChildFrameTest, VisibilityTest) {
180   // Calling show and hide also needs to be propagated to child frame by the
181   // |frame_connector_| which itself requires a |frame_proxy_in_parent_renderer|
182   // (set to nullptr for MockFrameConnectorDelegate). To avoid crashing the test
183   // |frame_connector_| is to set to nullptr.
184   view_->SetFrameConnectorDelegate(nullptr);
185 
186   view_->Show();
187   ASSERT_TRUE(view_->IsShowing());
188 
189   view_->Hide();
190   ASSERT_FALSE(view_->IsShowing());
191 }
192 
193 // Tests that the viewport intersection rect is dispatched to the RenderWidget
194 // whenever screen rects are updated.
TEST_F(RenderWidgetHostViewChildFrameTest,ViewportIntersectionUpdated)195 TEST_F(RenderWidgetHostViewChildFrameTest, ViewportIntersectionUpdated) {
196   blink::WebRect intersection_rect(5, 5, 100, 80);
197   blink::WebRect main_frame_document_intersection(5, 10, 200, 200);
198   blink::FrameOcclusionState occlusion_state =
199       blink::FrameOcclusionState::kPossiblyOccluded;
200   test_frame_connector_->SetViewportIntersection(
201       intersection_rect, main_frame_document_intersection, intersection_rect,
202       occlusion_state);
203 
204   MockRenderProcessHost* process =
205       static_cast<MockRenderProcessHost*>(widget_host_->GetProcess());
206   process->Init();
207 
208   widget_host_->Init();
209 
210   const IPC::Message* intersection_update =
211       process->sink().GetUniqueMessageMatching(
212           WidgetMsg_SetViewportIntersection::ID);
213   ASSERT_TRUE(intersection_update);
214   std::tuple<blink::ViewportIntersectionState> intersection_state;
215 
216   WidgetMsg_SetViewportIntersection::Read(intersection_update,
217                                           &intersection_state);
218   EXPECT_EQ(intersection_rect,
219             std::get<0>(intersection_state).viewport_intersection);
220   EXPECT_EQ(main_frame_document_intersection,
221             std::get<0>(intersection_state).main_frame_document_intersection);
222   EXPECT_EQ(intersection_rect,
223             std::get<0>(intersection_state).compositor_visible_rect);
224   EXPECT_EQ(occlusion_state, std::get<0>(intersection_state).occlusion_state);
225 }
226 
227 class RenderWidgetHostViewChildFrameZoomForDSFTest
228     : public RenderWidgetHostViewChildFrameTest {
229  public:
RenderWidgetHostViewChildFrameZoomForDSFTest()230   RenderWidgetHostViewChildFrameZoomForDSFTest() {}
231 
SetUp()232   void SetUp() override {
233     SetUpEnvironment(true /* use_zoom_for_device_scale_factor */);
234   }
235 
236  private:
237   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewChildFrameZoomForDSFTest);
238 };
239 
240 // Tests that moving the child around does not affect the physical backing size.
TEST_F(RenderWidgetHostViewChildFrameZoomForDSFTest,CompositorViewportPixelSize)241 TEST_F(RenderWidgetHostViewChildFrameZoomForDSFTest,
242        CompositorViewportPixelSize) {
243   ScreenInfo screen_info;
244   screen_info.device_scale_factor = 2.0f;
245   test_frame_connector_->SetScreenInfoForTesting(screen_info);
246 
247   gfx::Size local_frame_size(1276, 410);
248   test_frame_connector_->SetLocalFrameSize(local_frame_size);
249   EXPECT_EQ(local_frame_size, view_->GetCompositorViewportPixelSize());
250 
251   gfx::Rect screen_space_rect(local_frame_size);
252   screen_space_rect.set_origin(gfx::Point(230, 263));
253   test_frame_connector_->SetScreenSpaceRect(screen_space_rect);
254   EXPECT_EQ(local_frame_size, view_->GetCompositorViewportPixelSize());
255   EXPECT_EQ(gfx::Point(115, 131), view_->GetViewBounds().origin());
256   EXPECT_EQ(gfx::Point(230, 263),
257             test_frame_connector_->screen_space_rect_in_pixels().origin());
258 }
259 
260 // Tests that SynchronizeVisualProperties is called only once and all the
261 // parameters change atomically.
TEST_F(RenderWidgetHostViewChildFrameTest,SynchronizeVisualPropertiesOncePerChange)262 TEST_F(RenderWidgetHostViewChildFrameTest,
263        SynchronizeVisualPropertiesOncePerChange) {
264   MockRenderProcessHost* process =
265       static_cast<MockRenderProcessHost*>(widget_host_->GetProcess());
266   process->Init();
267 
268   widget_host_->Init();
269 
270   constexpr gfx::Rect compositor_viewport_pixel_rect(100, 100);
271   constexpr gfx::Rect screen_space_rect(compositor_viewport_pixel_rect);
272   viz::ParentLocalSurfaceIdAllocator allocator;
273   allocator.GenerateId();
274   viz::LocalSurfaceIdAllocation local_surface_id_allocation =
275       allocator.GetCurrentLocalSurfaceIdAllocation();
276   constexpr viz::FrameSinkId frame_sink_id(1, 1);
277 
278   FrameVisualProperties visual_properties;
279   visual_properties.screen_space_rect = screen_space_rect;
280   visual_properties.compositor_viewport = compositor_viewport_pixel_rect;
281   visual_properties.local_frame_size = compositor_viewport_pixel_rect.size();
282   visual_properties.capture_sequence_number = 123u;
283   visual_properties.local_surface_id_allocation = local_surface_id_allocation;
284 
285   sink_->ClearMessages();
286   test_frame_connector_->SynchronizeVisualProperties(frame_sink_id,
287                                                      visual_properties);
288 
289   // Update to the renderer.
290   ASSERT_EQ(1u, sink_->message_count());
291   {
292     const IPC::Message* msg = sink_->GetMessageAt(0);
293     ASSERT_EQ(WidgetMsg_UpdateVisualProperties::ID, msg->type());
294     WidgetMsg_UpdateVisualProperties::Param params;
295     WidgetMsg_UpdateVisualProperties::Read(msg, &params);
296     VisualProperties sent_visual_properties = std::get<0>(params);
297 
298     EXPECT_EQ(compositor_viewport_pixel_rect,
299               sent_visual_properties.compositor_viewport_pixel_rect);
300     EXPECT_EQ(screen_space_rect.size(), sent_visual_properties.new_size);
301     EXPECT_EQ(local_surface_id_allocation,
302               sent_visual_properties.local_surface_id_allocation);
303     EXPECT_EQ(123u, sent_visual_properties.capture_sequence_number);
304   }
305 }
306 
307 // Test that when we have a gesture scroll sequence that is not consumed by the
308 // child, the events are bubbled so that the parent may consume them.
TEST_F(RenderWidgetHostViewChildFrameTest,UncomsumedGestureScrollBubbled)309 TEST_F(RenderWidgetHostViewChildFrameTest, UncomsumedGestureScrollBubbled) {
310   blink::WebGestureEvent scroll_begin =
311       SyntheticWebGestureEventBuilder::BuildScrollBegin(
312           0.f, 10.f, blink::WebGestureDevice::kTouchscreen);
313   blink::WebGestureEvent scroll_update =
314       SyntheticWebGestureEventBuilder::BuildScrollUpdate(
315           0.f, 10.f, 0, blink::WebGestureDevice::kTouchscreen);
316   blink::WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
317       blink::WebInputEvent::kGestureScrollEnd,
318       blink::WebGestureDevice::kTouchscreen);
319 
320   view_->GestureEventAck(scroll_begin,
321                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
322   EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
323             test_frame_connector_->GetAndResetLastBubbledEventType());
324   view_->GestureEventAck(scroll_update,
325                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
326   EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate,
327             test_frame_connector_->GetAndResetLastBubbledEventType());
328   view_->GestureEventAck(scroll_end, INPUT_EVENT_ACK_STATE_IGNORED);
329   EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
330             test_frame_connector_->GetAndResetLastBubbledEventType());
331 }
332 
333 // Test that when we have a gesture scroll sequence that is consumed by the
334 // child, the events are not bubbled to the parent.
TEST_F(RenderWidgetHostViewChildFrameTest,ConsumedGestureScrollNotBubbled)335 TEST_F(RenderWidgetHostViewChildFrameTest, ConsumedGestureScrollNotBubbled) {
336   blink::WebGestureEvent scroll_begin =
337       SyntheticWebGestureEventBuilder::BuildScrollBegin(
338           0.f, 10.f, blink::WebGestureDevice::kTouchscreen);
339   blink::WebGestureEvent scroll_update =
340       SyntheticWebGestureEventBuilder::BuildScrollUpdate(
341           0.f, 10.f, 0, blink::WebGestureDevice::kTouchscreen);
342   blink::WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
343       blink::WebInputEvent::kGestureScrollEnd,
344       blink::WebGestureDevice::kTouchscreen);
345 
346   view_->GestureEventAck(scroll_begin, INPUT_EVENT_ACK_STATE_CONSUMED);
347   EXPECT_EQ(blink::WebInputEvent::kUndefined,
348             test_frame_connector_->GetAndResetLastBubbledEventType());
349   view_->GestureEventAck(scroll_update, INPUT_EVENT_ACK_STATE_CONSUMED);
350   EXPECT_EQ(blink::WebInputEvent::kUndefined,
351             test_frame_connector_->GetAndResetLastBubbledEventType());
352 
353   // Scrolling in a child my reach its extent and no longer be consumed, however
354   // scrolling is latched to the child so we do not bubble the update.
355   view_->GestureEventAck(scroll_update,
356                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
357   EXPECT_EQ(blink::WebInputEvent::kUndefined,
358             test_frame_connector_->GetAndResetLastBubbledEventType());
359 
360   view_->GestureEventAck(scroll_end, INPUT_EVENT_ACK_STATE_IGNORED);
361   EXPECT_EQ(blink::WebInputEvent::kUndefined,
362             test_frame_connector_->GetAndResetLastBubbledEventType());
363 }
364 
365 // Test that the child does not continue to attempt to bubble scroll events if
366 // bubbling has failed for the current scroll gesture.
TEST_F(RenderWidgetHostViewChildFrameTest,DoNotBubbleRemainingEventsOfRejectedScrollGesture)367 TEST_F(RenderWidgetHostViewChildFrameTest,
368        DoNotBubbleRemainingEventsOfRejectedScrollGesture) {
369   blink::WebGestureEvent scroll_begin =
370       SyntheticWebGestureEventBuilder::BuildScrollBegin(
371           0.f, 10.f, blink::WebGestureDevice::kTouchscreen);
372   blink::WebGestureEvent scroll_update =
373       SyntheticWebGestureEventBuilder::BuildScrollUpdate(
374           0.f, 10.f, 0, blink::WebGestureDevice::kTouchscreen);
375   blink::WebGestureEvent scroll_end = SyntheticWebGestureEventBuilder::Build(
376       blink::WebInputEvent::kGestureScrollEnd,
377       blink::WebGestureDevice::kTouchscreen);
378 
379   test_frame_connector_->SetCanBubble(false);
380 
381   view_->GestureEventAck(scroll_begin,
382                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
383   EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
384             test_frame_connector_->GetAndResetLastBubbledEventType());
385 
386   // The GSB was rejected, so the child view must not attempt to bubble the
387   // remaining events of the scroll sequence.
388   view_->GestureEventAck(scroll_update,
389                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
390   EXPECT_EQ(blink::WebInputEvent::kUndefined,
391             test_frame_connector_->GetAndResetLastBubbledEventType());
392   view_->GestureEventAck(scroll_end, INPUT_EVENT_ACK_STATE_IGNORED);
393   EXPECT_EQ(blink::WebInputEvent::kUndefined,
394             test_frame_connector_->GetAndResetLastBubbledEventType());
395 
396   test_frame_connector_->SetCanBubble(true);
397 
398   // When we have a new scroll gesture, the view may try bubbling again.
399   view_->GestureEventAck(scroll_begin,
400                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
401   EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin,
402             test_frame_connector_->GetAndResetLastBubbledEventType());
403   view_->GestureEventAck(scroll_update,
404                          INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
405   EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate,
406             test_frame_connector_->GetAndResetLastBubbledEventType());
407   view_->GestureEventAck(scroll_end, INPUT_EVENT_ACK_STATE_IGNORED);
408   EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd,
409             test_frame_connector_->GetAndResetLastBubbledEventType());
410 }
411 
412 }  // namespace content
413