blink: Discard input when render-blocking for SET.

Ensure input events are discarded when rendering is paused for a shared
element transition using the same strategy as paint holding.

Fixed: 1368757
Change-Id: Ief98e2d1a570c5a747e8030e318a02957e1d8b63
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3923394
Commit-Queue: Khushal Sagar <khushalsagar@chromium.org>
Commit-Queue: David Bokan <bokan@chromium.org>
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Reviewed-by: Bo Liu <boliu@chromium.org>
Auto-Submit: Khushal Sagar <khushalsagar@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Reviewed-by: Vladimir Levin <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1052556}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index cac114e8..49ff1e4a 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -423,6 +423,7 @@
       bool,
       PaintHoldingReason,
       absl::optional<PaintHoldingCommitTrigger>) override {}
+  void OnPauseRenderingChanged(bool) override {}
 
   void RecordStartOfFrameMetrics() override {}
   void RecordEndOfFrameMetrics(base::TimeTicks,
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h
index 0f19a274..23d2a2ee 100644
--- a/cc/test/stub_layer_tree_host_client.h
+++ b/cc/test/stub_layer_tree_host_client.h
@@ -31,6 +31,7 @@
       bool,
       PaintHoldingReason,
       absl::optional<PaintHoldingCommitTrigger>) override {}
+  void OnPauseRenderingChanged(bool) override {}
   void RecordStartOfFrameMetrics() override {}
   void RecordEndOfFrameMetrics(base::TimeTicks,
                                ActiveFrameSequenceTrackers) override {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index fb69944..3418f6a 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -650,6 +650,11 @@
   return std::make_unique<ScopedPauseRendering>(this);
 }
 
+void LayerTreeHost::OnPauseRenderingChanged(bool paused) {
+  DCHECK(IsMainThread());
+  client_->OnPauseRenderingChanged(paused);
+}
+
 void LayerTreeHost::OnDeferMainFrameUpdatesChanged(bool defer_status) {
   DCHECK(IsMainThread());
   client_->OnDeferMainFrameUpdatesChanged(defer_status);
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index fc51c668..d3e9ef7ae 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -315,6 +315,9 @@
   // during the main frame) updates are presented before rendering is paused.
   [[nodiscard]] std::unique_ptr<ScopedPauseRendering> PauseRendering();
 
+  // Notification that the proxy paused or resumed rendering.
+  void OnPauseRenderingChanged(bool);
+
   // Returns whether main frame updates are deferred. See conditions above.
   bool MainFrameUpdatesAreDeferred() const;
 
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index 0383093..17f7e90 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -134,6 +134,9 @@
       PaintHoldingReason reason,
       absl::optional<PaintHoldingCommitTrigger> trigger) = 0;
 
+  // Notification that rendering has been paused or resumed.
+  virtual void OnPauseRenderingChanged(bool) = 0;
+
   // Visual frame-based updates to the state of the LayerTreeHost are expected
   // to happen only in calls to LayerTreeHostClient::UpdateLayerTreeHost, which
   // should mutate/invalidate the layer tree or other page parameters as
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index 63f6d35..ac0d588 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -611,6 +611,8 @@
                                     TRACE_ID_LOCAL(this));
   }
 
+  layer_tree_host_->OnPauseRenderingChanged(pause_rendering_);
+
   // The impl thread needs to know that it should not issue BeginFrames.
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE,
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 050d79a..ad5e3b1 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -362,6 +362,8 @@
         "cc", "SingleThreadProxy::SetPauseRendering", TRACE_ID_LOCAL(this));
   }
 
+  layer_tree_host_->OnPauseRenderingChanged(pause_rendering_);
+
   // The scheduler needs to know that it should not issue BeginFrame.
   DebugScopedSetImplThread impl(task_runner_provider_);
   scheduler_on_impl_thread_->SetPauseRendering(pause_rendering_);
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 5952508..2e34173 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -138,6 +138,7 @@
       bool,
       cc::PaintHoldingReason,
       absl::optional<cc::PaintHoldingCommitTrigger>) override {}
+  void OnPauseRenderingChanged(bool) override {}
   void BeginMainFrameNotExpectedSoon() override {}
   void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {}
   void UpdateLayerTreeHost() override;
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
index b2d9a4f2..8758536 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
@@ -200,6 +200,12 @@
   delegate_->OnDeferMainFrameUpdatesChanged(status);
 }
 
+void LayerTreeView::OnPauseRenderingChanged(bool paused) {
+  if (!delegate_)
+    return;
+  delegate_->OnPauseRenderingChanged(paused);
+}
+
 void LayerTreeView::OnDeferCommitsChanged(
     bool status,
     cc::PaintHoldingReason reason,
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
index 883abd7..b9c73329 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.h
@@ -78,6 +78,7 @@
       bool defer_status,
       cc::PaintHoldingReason reason,
       absl::optional<cc::PaintHoldingCommitTrigger> trigger) override;
+  void OnPauseRenderingChanged(bool) override;
   void BeginMainFrameNotExpectedSoon() override;
   void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override;
   void UpdateLayerTreeHost() override;
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
index 5fc4149..e881f38 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view_delegate.h
@@ -45,6 +45,7 @@
       bool defer_status,
       cc::PaintHoldingReason reason,
       absl::optional<cc::PaintHoldingCommitTrigger> trigger) = 0;
+  virtual void OnPauseRenderingChanged(bool) = 0;
 
   // Notifies that the layer tree host has completed a call to
   // RequestMainFrameUpdate in response to a BeginMainFrame.
diff --git a/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h b/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h
index 0bd9d897..e76e8be8 100644
--- a/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h
+++ b/third_party/blink/renderer/platform/widget/compositing/test/stub_layer_tree_view_delegate.h
@@ -32,6 +32,7 @@
       bool defer_status,
       cc::PaintHoldingReason reason,
       absl::optional<cc::PaintHoldingCommitTrigger> trigger) override {}
+  void OnPauseRenderingChanged(bool) override {}
   void DidBeginMainFrame() override {}
   void DidCommitAndDrawCompositorFrame() override {}
   void WillCommitCompositorFrame() override {}
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
index 7530ed0..7c0bd953 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
+++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
@@ -766,6 +766,16 @@
   }
 }
 
+void WidgetInputHandlerManager::OnPauseRenderingChanged(bool paused) {
+  if (paused) {
+    suppressing_input_events_state_ |=
+        static_cast<uint16_t>(SuppressingInputEventsBits::kRenderingPaused);
+  } else {
+    suppressing_input_events_state_ &=
+        ~static_cast<uint16_t>(SuppressingInputEventsBits::kRenderingPaused);
+  }
+}
+
 void WidgetInputHandlerManager::InitOnInputHandlingThread(
     const base::WeakPtr<cc::CompositorDelegateForInput>& compositor_delegate,
     bool sync_compositing) {
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
index 94ed0856..b238849 100644
--- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
+++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
@@ -75,6 +75,9 @@
     kDeferCommits = 1 << 1,
     // if set, we have not painted a main frame from the current navigation yet
     kHasNotPainted = 1 << 2,
+    // if set, suppress events because pipeline has paused rendering (both main
+    // and compositor thread driven updates).
+    kRenderingPaused = 1 << 3,
   };
 
  public:
@@ -167,6 +170,9 @@
   // Called to inform us when the system starts or stops deferring commits.
   void OnDeferCommitsChanged(bool defer_status, cc::PaintHoldingReason reason);
 
+  // Called to inform us when the system pauses or resumes rendering.
+  void OnPauseRenderingChanged(bool);
+
   // Allow tests, headless etc. to have input events processed before the
   // compositor is ready to commit frames.
   // TODO(schenney): Fix this somehow, forcing all tests to wait for
diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc
index 8589009..c6c278a 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.cc
+++ b/third_party/blink/renderer/platform/widget/widget_base.cc
@@ -549,6 +549,10 @@
   widget_input_handler_manager_->OnDeferCommitsChanged(defer, reason);
 }
 
+void WidgetBase::OnPauseRenderingChanged(bool paused) {
+  widget_input_handler_manager_->OnPauseRenderingChanged(paused);
+}
+
 void WidgetBase::DidBeginMainFrame() {
   if (base::FeatureList::IsEnabled(features::kRunTextInputUpdatePostLifecycle))
     UpdateTextInputState();
diff --git a/third_party/blink/renderer/platform/widget/widget_base.h b/third_party/blink/renderer/platform/widget/widget_base.h
index 03bbf1d..b73ee82 100644
--- a/third_party/blink/renderer/platform/widget/widget_base.h
+++ b/third_party/blink/renderer/platform/widget/widget_base.h
@@ -157,6 +157,7 @@
       bool defer_status,
       cc::PaintHoldingReason reason,
       absl::optional<cc::PaintHoldingCommitTrigger> trigger) override;
+  void OnPauseRenderingChanged(bool) override;
   void DidBeginMainFrame() override;
   void RequestNewLayerTreeFrameSink(
       LayerTreeFrameSinkCallback callback) override;
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/input-blocked-when-rendering-suppressed.html b/third_party/blink/web_tests/wpt_internal/document-transition/input-blocked-when-rendering-suppressed.html
new file mode 100644
index 0000000..12708f4
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/document-transition/input-blocked-when-rendering-suppressed.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>Shared transitions: ensure input is discarded when rendering is suppressed</title>
+<link rel="help" href="https://github.com/WICG/shared-element-transitions">
+<link rel="author" href="mailto:khushalsagar@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background: blue;
+  contain: paint;
+}
+</style>
+
+<div id=first></div>
+
+<script>
+async function runTest(resolve, reject) {
+  window.addEventListener('mousedown', (event) => {
+      let point = event.clientX + "," + event.clientY;
+      if (event.clientX == 20 && event.clientY == 20)
+        resolve();
+      else
+        reject(point);
+    });
+
+    let transition = document.createDocumentTransition();
+
+    // Send an event while rendering is suppressed.
+    await transition.start(() => {
+      return new Promise(async (inner_resolve) => {
+        new test_driver.Actions()
+                 .setContext(window)
+                 .addPointer("finger1", "touch")
+                 .pointerMove(10, 10, {origin: "viewport", sourceName: "finger1"})
+                 .pointerDown({sourceName: "finger1"})
+                 .pointerUp({sourceName: "finger1"})
+                 .send();
+
+        // Use a timeout to ensure the input has been queued up. await
+        // times out because the event is discarded.
+        step_timeout(inner_resolve, 1000);
+      });
+    });
+
+    await new test_driver.Actions()
+             .setContext(window)
+             .addPointer("finger1", "touch")
+             .pointerMove(20, 20, {origin: "viewport", sourceName: "finger1"})
+             .pointerDown({sourceName: "finger1"})
+             .pointerUp({sourceName: "finger1"})
+             .send();
+}
+
+promise_test(async t => {
+  return new Promise(async (resolve, reject) => {
+    // Dispatch an event before starting the test to finish init logic in
+    // synthetic input dispatch.
+    await new test_driver.Actions()
+                 .setContext(window)
+                 .addPointer("finger1", "touch")
+                 .pointerMove(0, 0, {origin: "viewport", sourceName: "finger1"})
+                 .pointerDown({sourceName: "finger1"})
+                 .pointerUp({sourceName: "finger1"})
+                 .send();
+    runTest(resolve, reject);
+  });
+}, "Input when rendering suppressed is ignored");
+</script>
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 4cb37cf..ad691e7 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -359,6 +359,7 @@
       bool,
       cc::PaintHoldingReason,
       absl::optional<cc::PaintHoldingCommitTrigger>) override {}
+  void OnPauseRenderingChanged(bool) override {}
   void WillUpdateLayers() override {}
   void DidUpdateLayers() override;
   void BeginMainFrame(const viz::BeginFrameArgs& args) override;