Skip to content

Commit a3ed100

Browse files
authored
[web] Use eventTarget when computing pointer offset (flutter/engine#56949)
These changes are mainly things I missed in flutter/engine#56719 Fixes flutter#159804
1 parent ba21393 commit a3ed100

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

engine/src/flutter/lib/web_ui/lib/src/engine/pointer_binding/event_position_helper.dart

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ import '../window.dart';
1818
/// The offset is *not* multiplied by DPR or anything else, it's the closest
1919
/// to what the DOM would return if we had currentTarget readily available.
2020
///
21-
/// This needs an `eventTarget`, because the `event.target` (which is what
22-
/// this would really need to use) gets lost when the `event` comes from a
23-
/// "coalesced" event (see https://github.com/flutter/flutter/issues/155987).
21+
/// This takes an optional `eventTarget`, because the `event.target` may have
22+
/// the wrong value for "coalesced" events. See:
23+
///
24+
/// - https://github.com/flutter/flutter/issues/155987
25+
/// - https://github.com/flutter/flutter/issues/159804
26+
/// - https://g-issues.chromium.org/issues/382473107
2427
///
2528
/// It also takes into account semantics being enabled to fix the case where
2629
/// offsetX, offsetY == 0 (TalkBack events).
@@ -41,12 +44,12 @@ ui.Offset computeEventOffsetToTarget(
4144
if (isInput) {
4245
final EditableTextGeometry? inputGeometry = textEditing.strategy.geometry;
4346
if (inputGeometry != null) {
44-
return _computeOffsetForInputs(event, inputGeometry);
47+
return _computeOffsetForInputs(event, eventTarget, inputGeometry);
4548
}
4649
}
4750

4851
// On another DOM Element (normally a platform view)
49-
final bool isTargetOutsideOfShadowDOM = event.target != actualTarget;
52+
final bool isTargetOutsideOfShadowDOM = eventTarget != actualTarget;
5053
if (isTargetOutsideOfShadowDOM) {
5154
final DomRect origin = actualTarget.getBoundingClientRect();
5255
// event.clientX/Y and origin.x/y are relative **to the viewport**.
@@ -70,8 +73,14 @@ ui.Offset computeEventOffsetToTarget(
7073
/// sent from the framework, which includes information on how to transform the
7174
/// underlying input element. We transform the `event.offset` points we receive
7275
/// using the values from the input's transform matrix.
73-
ui.Offset _computeOffsetForInputs(DomMouseEvent event, EditableTextGeometry inputGeometry) {
74-
final DomElement targetElement = event.target! as DomHTMLElement;
76+
///
77+
/// See [computeEventOffsetToTarget] for more information about `eventTarget`.
78+
ui.Offset _computeOffsetForInputs(
79+
DomMouseEvent event,
80+
DomEventTarget eventTarget,
81+
EditableTextGeometry inputGeometry,
82+
) {
83+
final DomElement targetElement = eventTarget as DomElement;
7584
final DomHTMLElement domElement = textEditing.strategy.activeDomElement;
7685
assert(targetElement == domElement, 'The targeted input element must be the active input element');
7786
final Float32List transformValues = inputGeometry.globalTransform;

engine/src/flutter/lib/web_ui/test/engine/pointer_binding/event_position_helper_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ void doTests() {
3232
group('computeEventOffsetToTarget', () {
3333
setUp(() {
3434
view = EngineFlutterView(EnginePlatformDispatcher.instance, domDocument.body!);
35+
EnginePlatformDispatcher.instance.viewManager.registerView(view);
3536
rootElement = view.dom.rootElement;
3637
eventSource = createDomElement('div-event-source');
3738
rootElement.append(eventSource);
@@ -58,6 +59,7 @@ void doTests() {
5859
});
5960

6061
tearDown(() {
62+
EnginePlatformDispatcher.instance.viewManager.unregisterView(view.viewId);
6163
view.dispose();
6264
});
6365

@@ -101,6 +103,36 @@ void doTests() {
101103
expect(offset.dy, 110);
102104
});
103105

106+
test('eventTarget takes precedence', () async {
107+
final input = view.dom.textEditingHost.appendChild(createDomElement('input'));
108+
109+
textEditing.strategy.enable(
110+
InputConfiguration(viewId: view.viewId),
111+
onChange: (_, __) {},
112+
onAction: (_) {},
113+
);
114+
115+
addTearDown(() {
116+
textEditing.strategy.disable();
117+
});
118+
119+
final moveEvent = createDomPointerEvent('pointermove', <String, Object>{
120+
'bubbles': true,
121+
'clientX': 10,
122+
'clientY': 20,
123+
});
124+
125+
expect(
126+
() => computeEventOffsetToTarget(moveEvent, view),
127+
throwsA(anything),
128+
);
129+
130+
expect(
131+
() => computeEventOffsetToTarget(moveEvent, view, eventTarget: input),
132+
returnsNormally,
133+
);
134+
});
135+
104136
test('Event dispatched by TalkBack gets a computed offset', () async {
105137
// Fill this in to test _computeOffsetForTalkbackEvent
106138
}, skip: 'To be implemented!');

0 commit comments

Comments
 (0)