Skip to content

Commit

Permalink
Add deviceId to pointer event in blink.
Browse files Browse the repository at this point in the history
This CL is the first in a series that will introduce deviceId as an
attribute of pointer event. This one implements the attribute in blink and the pointer event api.

Specification/Explainer: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/PointerEventDeviceId/explainer.md

Design doc: https://docs.google.com/document/d/1o53mMNRcDnEnt55ftBe8pIPCS0pMlS0CVihs_I8g_UI/edit#heading=h.mx5ptksqe96w

Prototype: https://chromium-review.googlesource.com/c/chromium/src/+/4225372

Change-Id: I4a8e506f2cf1602e4b521491dfed49ff036efbbf
Bug: 1420685
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4298332
Reviewed-by: Chris Bookholt <bookholt@chromium.org>
Reviewed-by: Robert Flack <flackr@chromium.org>
Commit-Queue: Sahir Vellani <sahir.vellani@microsoft.com>
Reviewed-by: Olga Gerchikov <gerchiko@microsoft.com>
Reviewed-by: Mustaq Ahmed <mustaq@chromium.org>
Reviewed-by: Philip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1117672}
  • Loading branch information
Sahir Vellani authored and Chromium LUCI CQ committed Mar 15, 2023
1 parent 5f540a7 commit 90de24e
Show file tree
Hide file tree
Showing 17 changed files with 156 additions and 7 deletions.
Expand Up @@ -36,7 +36,7 @@ blink::mojom::PointerDataPtr PointerDataFromPointerProperties(
pointer.tangential_pressure, pointer.twist, pointer.button,
pointer.pointer_type, pointer.movement_x, pointer.movement_y,
pointer.is_raw_movement_event, pointer.PositionInWidget(),
pointer.PositionInScreen(), std::move(mouse_data));
pointer.PositionInScreen(), std::move(mouse_data), pointer.device_id);
}

void PointerPropertiesFromPointerData(
Expand All @@ -54,6 +54,7 @@ void PointerPropertiesFromPointerData(
pointer_properties->movement_y = pointer_data->movement_y;
pointer_properties->is_raw_movement_event =
pointer_data->is_raw_movement_event;
pointer_properties->device_id = pointer_data->device_id;
}

void TouchPointPropertiesFromPointerData(
Expand Down
Expand Up @@ -109,6 +109,9 @@ class WebPointerProperties {
// TODO(crbug.com/982379): Figure out how to avoid using this boolean.
bool is_raw_movement_event = false;

// Contains unique device id for pen on supported devices.
int32_t device_id = -1;

protected:
// Widget coordinate, which is relative to the bound of current RenderWidget
// (e.g. a plugin or OOPIF inside a RenderView). Similar to viewport
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/public/mojom/input/input_handler.mojom
Expand Up @@ -63,6 +63,7 @@ struct PointerData {
gfx.mojom.PointF widget_position;
gfx.mojom.PointF screen_position;
MouseData? mouse_data;
int32 device_id;
};

struct WheelData {
Expand Down
3 changes: 3 additions & 0 deletions third_party/blink/renderer/core/events/pointer_event.cc
Expand Up @@ -89,6 +89,9 @@ PointerEvent::PointerEvent(const AtomicString& type,
PointerEventUtil::TransformToAzimuthInValidRange(azimuth_angle_),
PointerEventUtil::TransformToAltitudeInValidRange(altitude_angle_));
}
if (initializer->hasDeviceId()) {
device_id_ = initializer->deviceId();
}
}

bool PointerEvent::IsMouseEvent() const {
Expand Down
4 changes: 4 additions & 0 deletions third_party/blink/renderer/core/events/pointer_event.h
Expand Up @@ -103,6 +103,8 @@ class CORE_EXPORT PointerEvent : public MouseEvent {

Document* GetDocument() const;

int32_t deviceId() const { return device_id_; }

void Trace(Visitor*) const override;

private:
Expand All @@ -127,6 +129,8 @@ class CORE_EXPORT PointerEvent : public MouseEvent {
HeapVector<Member<PointerEvent>> coalesced_events_;

HeapVector<Member<PointerEvent>> predicted_events_;

int32_t device_id_;
};

template <>
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/renderer/core/events/pointer_event.idl
Expand Up @@ -20,6 +20,7 @@
[MeasureAs=PointerEventAttributeCount] readonly attribute long twist;
[MeasureAs=PointerEventAttributeCount] readonly attribute DOMString pointerType;
[MeasureAs=PointerEventAttributeCount] readonly attribute boolean isPrimary;
[MeasureAs=PointerEventAttributeCount, RuntimeEnabled=PointerEventDeviceId] readonly attribute long deviceId;

// https://w3c.github.io/pointerevents/extension.html#extensions-to-the-pointerevent-interface
sequence<PointerEvent> getCoalescedEvents();
Expand Down
11 changes: 10 additions & 1 deletion third_party/blink/renderer/core/events/pointer_event_factory.cc
Expand Up @@ -197,6 +197,10 @@ HeapVector<Member<PointerEvent>> PointerEventFactory::CreateEventSequence(

last_global_position = event.PositionInScreen();

if (pointer_event_init->hasDeviceId()) {
new_event_init->setDeviceId(pointer_event_init->deviceId());
}

PointerEvent* pointer_event =
PointerEvent::Create(type, new_event_init, event.TimeStamp());
// Set the trusted flag for these events at the creation time as oppose to
Expand Down Expand Up @@ -352,6 +356,7 @@ PointerEvent* PointerEventFactory::Create(

SetLastPosition(pointer_event_init->pointerId(),
web_pointer_event.PositionInScreen(), event_type);

return PointerEvent::Create(type, pointer_event_init,
web_pointer_event.TimeStamp());
}
Expand Down Expand Up @@ -388,7 +393,8 @@ gfx::PointF PointerEventFactory::GetLastPointerPosition(

PointerEvent* PointerEventFactory::CreatePointerCancelEvent(
const int pointer_id,
base::TimeTicks platfrom_time_stamp) {
base::TimeTicks platfrom_time_stamp,
const int32_t device_id) {
DCHECK(pointer_id_mapping_.Contains(pointer_id));
pointer_id_mapping_.Set(
pointer_id,
Expand All @@ -404,6 +410,8 @@ PointerEvent* PointerEventFactory::CreatePointerCancelEvent(

SetEventSpecificFields(pointer_event_init, event_type_names::kPointercancel);

pointer_event_init->setDeviceId(device_id);

return PointerEvent::Create(event_type_names::kPointercancel,
pointer_event_init, platfrom_time_stamp);
}
Expand Down Expand Up @@ -432,6 +440,7 @@ PointerEvent* PointerEventFactory::CreatePointerEventFrom(
pointer_event->tangentialPressure());
pointer_event_init->setTwist(pointer_event->twist());
pointer_event_init->setView(pointer_event->view());
pointer_event_init->setDeviceId(pointer_event->deviceId());

SetEventSpecificFields(pointer_event_init, type);

Expand Down
Expand Up @@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_POINTER_EVENT_FACTORY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_POINTER_EVENT_FACTORY_H_

#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/input/web_pointer_event.h"
#include "third_party/blink/public/common/input/web_pointer_properties.h"
#include "third_party/blink/renderer/core/core_export.h"
Expand Down Expand Up @@ -42,7 +43,8 @@ class CORE_EXPORT PointerEventFactory {
LocalDOMWindow* view);

PointerEvent* CreatePointerCancelEvent(const PointerId pointer_id,
base::TimeTicks platfrom_time_stamp);
base::TimeTicks platfrom_time_stamp,
const int32_t device_id);

// For creating raw update events in chorded button case.
PointerEvent* CreatePointerRawUpdateEvent(PointerEvent*);
Expand Down
Expand Up @@ -129,7 +129,8 @@ PointerEvent* PointerEventFactoryTest::CreateAndCheckPointerCancel(
int unique_id,
bool is_primary) {
PointerEvent* pointer_event = pointer_event_factory_.CreatePointerCancelEvent(
unique_id, WebInputEvent::GetStaticTimeStampForTests());
unique_id, WebInputEvent::GetStaticTimeStampForTests(),
/* deviceId */ -1);
EXPECT_EQ("pointercancel", pointer_event->type());
EXPECT_EQ(unique_id, pointer_event->pointerId());
EXPECT_EQ(is_primary, pointer_event->isPrimary());
Expand Down
Expand Up @@ -17,6 +17,7 @@ dictionary PointerEventInit : MouseEventInit {
long twist = 0;
DOMString pointerType = "";
boolean isPrimary = false;
long deviceId = -1;

// https://w3c.github.io/pointerevents/extension.html#extensions-to-the-pointerevent-interface
sequence<PointerEvent> coalescedEvents = [];
Expand Down
Expand Up @@ -318,7 +318,8 @@ void PointerEventManager::HandlePointerInterruption(
WebPointerProperties::PointerType::kMouse) {
canceled_pointer_events.push_back(
pointer_event_factory_.CreatePointerCancelEvent(
PointerEventFactory::kMouseId, web_pointer_event.TimeStamp()));
PointerEventFactory::kMouseId, web_pointer_event.TimeStamp(),
web_pointer_event.device_id));
} else {
// TODO(nzolghadr): Maybe canceling all the non-hovering pointers is not
// the best strategy here. See the github issue for more details:
Expand All @@ -332,7 +333,8 @@ void PointerEventManager::HandlePointerInterruption(
for (PointerId pointer_id : non_hovering_pointer_ids) {
canceled_pointer_events.push_back(
pointer_event_factory_.CreatePointerCancelEvent(
pointer_id, web_pointer_event.TimeStamp()));
pointer_id, web_pointer_event.TimeStamp(),
web_pointer_event.device_id));
}

non_hovering_pointers_canceled_ = true;
Expand Down Expand Up @@ -691,7 +693,8 @@ WebInputEventResult PointerEventManager::HandlePointerEvent(
SendTouchPointerEvent(
pointer_event_target.target_element,
pointer_event_factory_.CreatePointerCancelEvent(
core_pointer_event->pointerId(), event.TimeStamp()),
core_pointer_event->pointerId(), event.TimeStamp(),
core_pointer_event->deviceId()),
event.hovering);
}

Expand Down
Expand Up @@ -2563,6 +2563,10 @@
base_feature: "none",
origin_trial_feature_name: "PNaCl",
},
{
name: "PointerEventDeviceId",
status: "test",
},
{
name: "PointerLockOptions",
origin_trial_feature_name: "PointerLockOptions",
Expand Down
9 changes: 9 additions & 0 deletions third_party/blink/web_tests/VirtualTestSuites
Expand Up @@ -1862,6 +1862,15 @@
"args": ["--enable-features=AllowRTCEncodedVideoFrameSetMetadataAllFields"],
"expires": "Jul 1, 2023"
},
{
"prefix": "disable-device-id-pointer-event",
"platforms": ["Linux", "Mac", "Win"],
"bases": ["fast/events/pointerevents/device-id"],
"args": [
"--disable-blink-features=PointerEventDeviceId"
],
"expires": "Jul 1, 2023"
},
{
"prefix": "webrtc-legacy-stats-trial-disabled",
"platforms": ["Linux", "Mac", "Win"],
Expand Down
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<style>
div {
user-select: none; // Prevents text selection on drag.
}
</style>
<div id="logger" draggable="false"></div>
<div id="console"></div>
<!-- This test verifies that if the PointerEventDeviceId flag is enabled,
pointerEvent.deviceId is null. If not, it is undefined. -->
<script>
function sendPenDragAt(x, y) {
return new Promise(function(resolve, reject) {
if (window.chrome && chrome.gpuBenchmarking) {
var pointerActions =
[{source: "pen",
actions: [
{ name: "pointerDown", x: x, y: y },
{ name: "pointerMove", x: x + 3, y: y + 3},
{ name: "pointerUp" },
]}];
chrome.gpuBenchmarking.pointerActionSequence(pointerActions, resolve);
}
else {
reject();
}
});
}

function CheckDeviceId(event) {
eventFired++;
if (self.internals.runtimeFlags.pointerEventDeviceIdEnabled)
assert_equals(event.deviceId, -1, "deviceId is -1");
else
assert_equals(event.deviceId, undefined, "deviceId is undefined")
}

window.addEventListener("pointerdown", CheckDeviceId, false);
window.addEventListener("pointermove", CheckDeviceId, false);

promise_test(async () => {
if (!window.internals)
return;
eventFired = 0;
await sendPenDragAt(100, 100);
assert_true(eventFired == 2);
}, 'PointerEvent.deviceId');
</script>
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<div id="console"></div>

<!-- This test verifies that if the kPointerEventDeviceId flag is enabled,
pointerEvent.deviceId can be set via PointerEventInit. If not, it is
undefined. -->
<script>
function CheckDeviceId(event) {
if (internals.runtimeFlags.pointerEventDeviceIdEnabled)
assert_equals(event.deviceId, 1001, "deviceId is populated");
else
assert_equals(event.deviceId, undefined, "deviceId is undefined");
}

promise_test(async () => {
if (!window.internals)
return;
var downEvent = new PointerEvent("pointerdown",
{pointerId: 1,
bubbles: true,
cancelable: true,
pointerType: "pen",
width: 100,
height: 100,
isPrimary: true,
deviceId: 1001
});
CheckDeviceId(downEvent);
var moveEvent = new PointerEvent("pointermove",
{pointerId: 1,
bubbles: true,
cancelable: true,
pointerType: "pen",
width: 100,
height: 100,
isPrimary: true,
deviceId: 1001
});
CheckDeviceId(moveEvent);
var upEvent = new PointerEvent("pointeup",
{pointerId: 1,
bubbles: true,
cancelable: true,
pointerType: "pen",
width: 100,
height: 100,
isPrimary: true,
deviceId: 1001
});
CheckDeviceId(upEvent);
}, 'PointerEvent.deviceId via PointerEventInit');
</script>
@@ -0,0 +1,2 @@
This test suite runs the tests in fast/events/pointerevents/device-id
with the flag PointerEventDeviceId disabled.
Expand Up @@ -7046,6 +7046,7 @@ interface PointerEvent : MouseEvent
attribute @@toStringTag
getter altitudeAngle
getter azimuthAngle
getter deviceId
getter height
getter isPrimary
getter pointerId
Expand Down

0 comments on commit 90de24e

Please sign in to comment.