0

[Interop 2023] Make PE/ME enter/leave events non-composed

Chrome always had mouse/pointer enter/leave events as
"composed", which was matching the specs in the past.
However, the specs were updated in the last few years to
make these events non-composed:
  https://github.com/w3c/uievents/pull/210
  https://github.com/w3c/pointerevents/pull/461
Firefox was update too:
https://bugzilla.mozilla.org/show_bug.cgi?id=1484371

This CL makes Chrome spec compliant.

Fixed: 876994, 874082, 1136584
Change-Id: I861b15cd71bc9c06e28d5d325f8b72c72d7cde16
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4536900
Reviewed-by: Mustaq Ahmed <mustaq@chromium.org>
Reviewed-by: Robert Flack <flackr@chromium.org>
Commit-Queue: Mustaq Ahmed <mustaq@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1146033}
This commit is contained in:
Mustaq Ahmed
2023-05-18 17:40:47 +00:00
committed by Chromium LUCI CQ
parent 90f924d052
commit 7a27f6bc74
8 changed files with 55 additions and 31 deletions

@ -273,8 +273,9 @@ PointerEventInit* PointerEventFactory::ConvertIdTypeButtonsEvent(
void PointerEventFactory::SetEventSpecificFields(
PointerEventInit* pointer_event_init,
const AtomicString& type) {
pointer_event_init->setBubbles(type != event_type_names::kPointerenter &&
type != event_type_names::kPointerleave);
bool is_pointer_enter_or_leave = type == event_type_names::kPointerenter ||
type == event_type_names::kPointerleave;
pointer_event_init->setBubbles(!is_pointer_enter_or_leave);
pointer_event_init->setCancelable(
type != event_type_names::kPointerenter &&
type != event_type_names::kPointerleave &&
@ -282,8 +283,10 @@ void PointerEventFactory::SetEventSpecificFields(
type != event_type_names::kPointerrawupdate &&
type != event_type_names::kGotpointercapture &&
type != event_type_names::kLostpointercapture);
pointer_event_init->setComposed(true);
pointer_event_init->setComposed(
RuntimeEnabledFeatures::NonComposedEnterLeaveEventsEnabled()
? !is_pointer_enter_or_leave
: true);
pointer_event_init->setDetail(0);
}

@ -91,7 +91,10 @@ void SetMouseEventAttributes(MouseEventInit* initializer,
initializer->setButtons(
MouseEvent::WebInputEventModifiersToButtons(mouse_event.GetModifiers()));
initializer->setView(target_node->GetDocument().domWindow());
initializer->setComposed(true);
initializer->setComposed(
RuntimeEnabledFeatures::NonComposedEnterLeaveEventsEnabled()
? !is_mouse_enter_or_leave
: true);
initializer->setDetail(click_count);
initializer->setRelatedTarget(related_target);
UIEventWithKeyState::SetFromWebInputEventModifiers(
@ -996,6 +999,10 @@ bool MouseEventManager::TryStartDrag(
WebInputEventResult MouseEventManager::DispatchDragSrcEvent(
const AtomicString& event_type,
const WebMouseEvent& event) {
CHECK(event_type == event_type_names::kDrag ||
event_type == event_type_names::kDragend ||
event_type == event_type_names::kDragstart);
return DispatchDragEvent(event_type, GetDragState().drag_src_.Get(), nullptr,
event, GetDragState().drag_data_transfer_.Get());
}

@ -2378,6 +2378,13 @@
status: "test",
base_feature: "none",
},
// Makes enter/leave Mouse and Pointer Events non-composed as per
// corresponding specifications.
{
name: "NonComposedEnterLeaveEvents",
public: true,
status: "experimental",
},
{
// Kill switch for crbug.com/1427047 fix.
// TODO(xiaochengh): Remove in M117.

@ -3296,15 +3296,6 @@ crbug.com/626703 external/wpt/xhr/event-readystatechange-loaded.any.html [ Failu
crbug.com/626703 external/wpt/media-source/mediasource-correct-frames-after-reappend.html [ Failure Pass Timeout ]
crbug.com/626703 external/wpt/media-source/mediasource-correct-frames.html [ Failure Pass Timeout ]
crbug.com/626703 external/wpt/payment-method-basic-card/steps_for_selecting_the_payment_handler.html [ Timeout ]
crbug.com/876994 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers.html?mouse [ Failure ]
crbug.com/876994 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers.html?pen [ Failure ]
crbug.com/876994 external/wpt/pointerevents/pointerevent_attributes_nohover_pointers.html [ Failure ]
crbug.com/876994 external/wpt/pointerevents/pointerevent_attributes_hoverable_rightbutton.html?mouse [ Failure ]
crbug.com/876994 external/wpt/pointerevents/pointerevent_attributes_hoverable_rightbutton.html?pen [ Failure ]
crbug.com/876994 external/wpt/uievents/mouse/attributes.html [ Failure ]
crbug.com/1136584 external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?mouse [ Failure ]
crbug.com/1136584 external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?pen [ Failure ]
crbug.com/1136584 external/wpt/pointerevents/capturing_boundary_event_handler_at_ua_shadowdom.html?touch [ Failure ]
crbug.com/626703 external/wpt/payment-method-basic-card/apply_the_modifiers.html [ Timeout ]
crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html [ Skip Timeout ]
crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html [ Skip Timeout ]

@ -26,10 +26,15 @@ target.addEventListener("pointerdown", (e)=>{
function testFunction(test){
return test.step_func(e=>{
assert_equals(e.constructor, window.PointerEvent, "auxclick should use a PointerEvent constructor");
assert_true(e instanceof PointerEvent, "auxclick should be a PointerEvent");
assert_equals(e.pointerId, pointerId, "auxclick's pointerId should match the pointerId of the pointer event that triggers it");
assert_equals(e.pointerType, pointerType, "axclick's pointerType should match the pointerType of the pointer event that triggers it");
assert_equals(e.constructor, window.PointerEvent,
"auxclick should use a PointerEvent constructor");
assert_true(e instanceof PointerEvent,
"auxclick should be a PointerEvent");
assert_equals(e.pointerId, pointerId,
"auxclick's pointerId should match the pointerId of the pointer event that triggers it");
assert_equals(e.pointerType, pointerType,
"auxclick's pointerType should match the pointerType of the pointer event that triggers it");
assert_equals(e.composed, true, "auxclick.composed should be true");
});
}
@ -51,10 +56,15 @@ function run_test(pointerType){
.pointerMove(0,0, {origin:target, sourceName:testPointer})
.pointerDown({button:actions.ButtonType.MIDDLE, sourceName:testPointer})
.pointerUp({button:actions.ButtonType.MIDDLE, sourceName:testPointer});
Promise.all([pointerDownPrevented, eventWatcher.wait_for("auxclick"), actions.send()]).then(()=>resolve());
Promise.all([
pointerDownPrevented,
eventWatcher.wait_for("auxclick"),
actions.send()
]).then(()=>resolve());
}), "auxclick using " + pointerType + " is a PointerEvent");
}
run_test(inputSource);
// TODO(crbug.com/1150441): Add test for auxclick from touch.Note: Calling run_test("touch") here times out.
// TODO(crbug.com/1150441): Add test for auxclick from touch. Note: Calling
// run_test("touch") here times out.
</script>

@ -25,6 +25,7 @@ function assert_click_construction(click_event, window_object) {
"click should use a PointerEvent constructor");
assert_true(click_event instanceof window_object.PointerEvent,
"click should be a PointerEvent instance");
assert_equals(click_event.composed, true, "click.composed should be true");
}
function assert_click_attributes(click_event, pointerdown_event, pointerup_event) {
@ -36,7 +37,7 @@ function assert_click_attributes(click_event, pointerdown_event, pointerup_event
assert_equals(click_event.pointerId, pointerup_event.pointerId,
"click.pointerId should match the pointerId of the triggering pointerup");
assert_equals(click_event.pointerType, pointerup_event.pointerType,
"click.pointerType should match the pointerType of the triggering pointerup");
"click.pointerType should match the pointerType of the triggering pointerup");
}
promise_test(async () => {

@ -20,10 +20,15 @@ let pointerdownPointerId, pointerdownPointerType;
let inputSource = location.search.substring(1);
target.addEventListener("contextmenu", contextmenuTest.step_func((e)=>{
assert_equals(e.constructor, window.PointerEvent, "contextmenu should use a PointerEvent constructor");
assert_true(e instanceof PointerEvent, "contextmenu should be a PointerEvent");
assert_equals(e.pointerId, pointerdownPointerId, "contextmenu's pointerId should match the pointerId of the pointer event that triggers it");
assert_equals(e.pointerType, pointerdownPointerType, "contextmenu's pointerType should match the pointerType of the pointer event that triggers it");
assert_equals(e.constructor, window.PointerEvent,
"contextmenu should use a PointerEvent constructor");
assert_true(e instanceof PointerEvent,
"contextmenu should be a PointerEvent");
assert_equals(e.pointerId, pointerdownPointerId,
"contextmenu's pointerId should match the pointerId of the pointer event that triggers it");
assert_equals(e.pointerType, pointerdownPointerType,
"contextmenu's pointerType should match the pointerType of the pointer event that triggers it");
assert_equals(e.composed, true, "contextmenu.composed should be true");
}));
target.addEventListener("pointerdown", e=>{
pointerdownPointerId = e.pointerId;

@ -18,15 +18,18 @@ const input2 = document.querySelector('#input2');
const composedEventTypes = [
// UI Events
'blur', 'focus', 'focusin', 'focusout',
'click', 'dblclick',
'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover', 'mouseup',
'dblclick',
'wheel',
'beforeinput', 'input',
'keydown', 'keyup',
'compositionstart', 'compositionupdate', 'compositionend',
// Legacy UI Events
'DOMActivate', 'DOMFocusIn', 'DOMFocusOut', 'keypress',
// See LayoutTests/fast/events/touch/basic-single-touch-events.html for Touch Events.
// The following events are covered elsewhere in web_tests:
// - Mouse Events: wpt/uievents/mouse/attributes.html
// - Pointer Events: wpt/pointerevents/pointerevent_*_is_a_pointerevent.html
// and wpt/pointerevents/pointerevent_attributes_*hover*_pointers.html
// - Touch Events: fast/events/touch/basic-single-touch-events.html
];
promise_test( async (t) => {
@ -43,9 +46,6 @@ promise_test( async (t) => {
await mouseClickOn(input.offsetLeft, input.offsetTop);
await mouseDoubleClickOn(input.offsetLeft, input.offsetTop);
// For mouseenter/mouseleave
await mouseMoveTo(input2.offsetLeft, input2.offsetTop);
input.blur();
input.focus();
input.blur();