Skip to content

Commit

Permalink
Disable input events per browsing context group
Browse files Browse the repository at this point in the history
DevTools debugger disables input events in addition to pausing pages.
To make DevTools debugger work with multiple browsing context groups,
this CL modifies WebFrameWidgetImpl so that it disables input events
per browsing context group instead of disabling input events for all
frames. The new behavior is behind the
PausePagesPerBrowsingContextGroup flag.

Bug: 1475531
Change-Id: If2317d6402f3091e26cdf0554abc6cc384a5a97d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4812575
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Kenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1188203}
  • Loading branch information
bashi authored and Chromium LUCI CQ committed Aug 25, 2023
1 parent 01bcc60 commit 3b473fe
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <utility>

#include "base/auto_reset.h"
#include "base/unguessable_token.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_scoped_page_pauser.h"
#include "third_party/blink/public/platform/web_string.h"
Expand Down Expand Up @@ -131,7 +132,29 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
}

private:
ClientMessageLoopAdapter(
// A RAII class that disables input events for frames that belong to the
// same browsing context group. Note that this does not support nesting, as
// DevTools doesn't require nested pauses.
class ScopedInputEventsDisabler {
public:
explicit ScopedInputEventsDisabler(WebLocalFrameImpl& frame)
: browsing_context_group_token_(WebFrame::ToCoreFrame(frame)
->GetPage()
->BrowsingContextGroupToken()) {
WebFrameWidgetImpl::SetIgnoreInputEvents(browsing_context_group_token_,
true);
}

~ScopedInputEventsDisabler() {
WebFrameWidgetImpl::SetIgnoreInputEvents(browsing_context_group_token_,
false);
}

private:
const base::UnguessableToken browsing_context_group_token_;
};

explicit ClientMessageLoopAdapter(
std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop)
: message_loop_(std::move(message_loop)) {
DCHECK(message_loop_.get());
Expand Down Expand Up @@ -214,7 +237,9 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
agent->FlushProtocolNotifications();

// 1. Disable input events.
WebFrameWidgetImpl::SetIgnoreInputEvents(true);
CHECK(!input_events_disabler_);
input_events_disabler_ =
std::make_unique<ScopedInputEventsDisabler>(*frame);
for (auto* const view : WebViewImpl::AllInstances())
view->GetChromeClient().NotifyPopupOpeningObservers();

Expand Down Expand Up @@ -242,12 +267,13 @@ class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
*running_for_debug_break_kind_ == kNormalPause);
message_loop_->QuitNow();
page_pauser_.reset();
WebFrameWidgetImpl::SetIgnoreInputEvents(false);
input_events_disabler_.reset();
}

absl::optional<MessageLoopKind> running_for_debug_break_kind_;
bool running_for_page_wait_ = false;
std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop_;
std::unique_ptr<ScopedInputEventsDisabler> input_events_disabler_;
std::unique_ptr<WebScopedPagePauser> page_pauser_;
scoped_refptr<InspectorTaskRunner>
inspector_task_runner_for_instrumentation_pause_;
Expand Down
50 changes: 44 additions & 6 deletions third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,45 @@ bool IsElementNotNullAndEditable(Element* element) {
return false;
}

bool& InputDisabledPerBrowsingContextGroup(
const base::UnguessableToken& token) {
using BrowsingContextGroupMap = std::map<base::UnguessableToken, bool>;
DEFINE_STATIC_LOCAL(BrowsingContextGroupMap, values, ());
return values[token];
}

} // namespace

// WebFrameWidget ------------------------------------------------------------

bool WebFrameWidgetImpl::ignore_input_events_ = false;

// static
void WebFrameWidgetImpl::SetIgnoreInputEvents(
const base::UnguessableToken& browsing_context_group_token,
bool value) {
if (base::FeatureList::IsEnabled(
features::kPausePagesPerBrowsingContextGroup)) {
CHECK_NE(InputDisabledPerBrowsingContextGroup(browsing_context_group_token),
value);
InputDisabledPerBrowsingContextGroup(browsing_context_group_token) = value;
} else {
CHECK_NE(ignore_input_events_, value);
ignore_input_events_ = value;
}
}

// static
bool WebFrameWidgetImpl::IgnoreInputEvents(
const base::UnguessableToken& browsing_context_group_token) {
if (base::FeatureList::IsEnabled(
features::kPausePagesPerBrowsingContextGroup)) {
return InputDisabledPerBrowsingContextGroup(browsing_context_group_token);
} else {
return ignore_input_events_;
}
}

WebFrameWidgetImpl::WebFrameWidgetImpl(
base::PassKey<WebLocalFrame>,
CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
Expand Down Expand Up @@ -488,8 +521,7 @@ void WebFrameWidgetImpl::DragTargetDragLeave(
const gfx::PointF& screen_point) {
base::ScopedClosureRunner runner(
WTF::BindOnce(&WebFrameWidgetImpl::CancelDrag, WrapWeakPersistent(this)));

if (IgnoreInputEvents() || !current_drag_data_) {
if (ShouldIgnoreInputEvents() || !current_drag_data_) {
return;
}

Expand All @@ -512,7 +544,7 @@ void WebFrameWidgetImpl::DragTargetDrop(const WebDragData& web_drag_data,
base::ScopedClosureRunner runner(
WTF::BindOnce(&WebFrameWidgetImpl::CancelDrag, WrapWeakPersistent(this)));

if (IgnoreInputEvents() || !current_drag_data_) {
if (ShouldIgnoreInputEvents() || !current_drag_data_) {
return;
}

Expand Down Expand Up @@ -552,7 +584,7 @@ void WebFrameWidgetImpl::DragSourceEndedAt(const gfx::PointF& point_in_viewport,
WTF::BindOnce(&WebFrameWidgetImpl::DragSourceSystemDragEnded,
WrapWeakPersistent(this)));

if (IgnoreInputEvents()) {
if (ShouldIgnoreInputEvents()) {
return;
}

Expand Down Expand Up @@ -1233,7 +1265,7 @@ void WebFrameWidgetImpl::DragTargetDragEnterOrOver(
const gfx::PointF& screen_point,
DragAction drag_action,
uint32_t key_modifiers) {
if (IgnoreInputEvents() || !current_drag_data_) {
if (ShouldIgnoreInputEvents() || !current_drag_data_) {
CancelDrag();
return;
}
Expand Down Expand Up @@ -1459,6 +1491,11 @@ void WebFrameWidgetImpl::NotifyViewTransitionRenderingHasBegun() {
});
}

bool WebFrameWidgetImpl::ShouldIgnoreInputEvents() {
CHECK(GetPage());
return IgnoreInputEvents(GetPage()->BrowsingContextGroupToken());
}

std::unique_ptr<cc::LayerTreeFrameSink>
WebFrameWidgetImpl::AllocateNewLayerTreeFrameSink() {
return nullptr;
Expand Down Expand Up @@ -2754,8 +2791,9 @@ WebInputEventResult WebFrameWidgetImpl::HandleInputEvent(

// Report the event to be NOT processed by WebKit, so that the browser can
// handle it appropriately.
if (IgnoreInputEvents())
if (ShouldIgnoreInputEvents()) {
return WebInputEventResult::kNotHandled;
}

base::AutoReset<const WebInputEvent*> current_event_change(
&CurrentInputEvent::current_input_event_, &input_event);
Expand Down
11 changes: 9 additions & 2 deletions third_party/blink/renderer/core/frame/web_frame_widget_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "cc/input/event_listener_properties.h"
#include "cc/input/overscroll_behavior.h"
Expand Down Expand Up @@ -383,8 +384,11 @@ class CORE_EXPORT WebFrameWidgetImpl
const gfx::Rect& drag_obj_rect);

bool DoingDragAndDrop() { return doing_drag_and_drop_; }
static void SetIgnoreInputEvents(bool value) { ignore_input_events_ = value; }
static bool IgnoreInputEvents() { return ignore_input_events_; }
static void SetIgnoreInputEvents(
const base::UnguessableToken& browsing_context_group_token,
bool value);
static bool IgnoreInputEvents(
const base::UnguessableToken& browsing_context_group_token);

// Resets the layout tracking steps for the main frame. When
// `UpdateLifecycle()` is called it generates `WebMeaningfulLayout` events
Expand Down Expand Up @@ -953,6 +957,9 @@ class CORE_EXPORT WebFrameWidgetImpl
// Satisfy the render blocking condition for cross-document view transitions.
void NotifyViewTransitionRenderingHasBegun();

// True when `this` should ignore input events.
bool ShouldIgnoreInputEvents();

// Stores the current composition line bounds. These bounds are rectangles
// which surround each line of text in a currently focused input or textarea
// element.
Expand Down
38 changes: 33 additions & 5 deletions third_party/blink/renderer/core/frame/web_frame_widget_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/test/property_tree_test_utils.h"
Expand Down Expand Up @@ -783,9 +784,31 @@ TEST_F(WebFrameWidgetSimTest, ActivePinchGestureUpdatesLayerTreeHost) {
EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
}

class WebFrameWidgetInputEventsSimTest
: public WebFrameWidgetSimTest,
public testing::WithParamInterface<bool> {
public:
WebFrameWidgetInputEventsSimTest() {
if (GetParam()) {
feature_list_.InitAndEnableFeature(
features::kPausePagesPerBrowsingContextGroup);
} else {
feature_list_.InitAndDisableFeature(
features::kPausePagesPerBrowsingContextGroup);
}
}

private:
base::test::ScopedFeatureList feature_list_;
};

INSTANTIATE_TEST_SUITE_P(All,
WebFrameWidgetInputEventsSimTest,
testing::Values(true, false));

// Tests that dispatch buffered touch events does not process events during
// drag and devtools handling.
TEST_F(WebFrameWidgetSimTest, DispatchBufferedTouchEvents) {
TEST_P(WebFrameWidgetInputEventsSimTest, DispatchBufferedTouchEvents) {
auto* widget = WebView().MainFrameViewWidget();

auto* listener = MakeGarbageCollected<TouchMoveEventListener>();
Expand All @@ -809,15 +832,19 @@ TEST_F(WebFrameWidgetSimTest, DispatchBufferedTouchEvents) {
base::DoNothing());
EXPECT_TRUE(listener->GetInvokedStateAndReset());

const base::UnguessableToken browsing_context_group_token =
WebView().GetPage()->BrowsingContextGroupToken();

// Expect listener does not get called, due to devtools flag.
touch.MovePoint(0, 12, 12);
WebFrameWidgetImpl::SetIgnoreInputEvents(true);
WebFrameWidgetImpl::SetIgnoreInputEvents(browsing_context_group_token, true);
widget->ProcessInputEventSynchronouslyForTesting(
WebCoalescedInputEvent(touch.Clone(), {}, {}, ui::LatencyInfo()),
base::DoNothing());
EXPECT_TRUE(WebFrameWidgetImpl::IgnoreInputEvents());
EXPECT_TRUE(
WebFrameWidgetImpl::IgnoreInputEvents(browsing_context_group_token));
EXPECT_FALSE(listener->GetInvokedStateAndReset());
WebFrameWidgetImpl::SetIgnoreInputEvents(false);
WebFrameWidgetImpl::SetIgnoreInputEvents(browsing_context_group_token, false);

// Expect listener does not get called, due to drag.
touch.MovePoint(0, 14, 14);
Expand All @@ -827,7 +854,8 @@ TEST_F(WebFrameWidgetSimTest, DispatchBufferedTouchEvents) {
WebCoalescedInputEvent(touch.Clone(), {}, {}, ui::LatencyInfo()),
base::DoNothing());
EXPECT_TRUE(widget->DoingDragAndDrop());
EXPECT_FALSE(WebFrameWidgetImpl::IgnoreInputEvents());
EXPECT_FALSE(
WebFrameWidgetImpl::IgnoreInputEvents(browsing_context_group_token));
EXPECT_FALSE(listener->GetInvokedStateAndReset());
}

Expand Down

0 comments on commit 3b473fe

Please sign in to comment.