Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions packages/flutter/lib/src/gestures/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
// We convert pointer data to logical pixels so that e.g. the touch slop can be
// defined in a device-independent manner.
try {
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, platformDispatcher.implicitView!.devicePixelRatio));
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, _devicePixelRatioForView));
if (!locked) {
_flushPointerEventQueue();
}
Expand All @@ -302,6 +302,10 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
}
}

double? _devicePixelRatioForView(int viewId) {
return platformDispatcher.view(id: viewId)?.devicePixelRatio;
}

/// Dispatch a [PointerCancelEvent] for the given pointer soon.
///
/// The pointer event will be dispatched before the next pointer event and
Expand Down Expand Up @@ -368,7 +372,7 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent || event is PointerPanZoomStartEvent) {
assert(!_hitTests.containsKey(event.pointer), 'Pointer of ${event.toString(minLevel: DiagnosticLevel.debug)} unexpectedly has a HitTestResult associated with it.');
hitTestResult = HitTestResult();
hitTest(hitTestResult, event.position);
hitTestInView(hitTestResult, event.position, event.viewId);
if (event is PointerDownEvent || event is PointerPanZoomStartEvent) {
_hitTests[event.pointer] = hitTestResult;
}
Expand Down Expand Up @@ -401,12 +405,22 @@ mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, H
}
}

/// Determine which [HitTestTarget] objects are located at a given position.
/// Determine which [HitTestTarget] objects are located at a given position in
/// the specified view.
@override // from HitTestable
void hitTest(HitTestResult result, Offset position) {
void hitTestInView(HitTestResult result, Offset position, int viewId) {
result.add(HitTestEntry(this));
}

@override // from HitTestable
@Deprecated(
'Use hitTestInView and specify the view to hit test. '
'This feature was deprecated after v3.11.0-20.0.pre.',
)
void hitTest(HitTestResult result, Offset position) {
hitTestInView(result, position, platformDispatcher.implicitView!.viewId);
}

/// Dispatch an event to [pointerRouter] and the path of a hit test result.
///
/// The `event` is routed to [pointerRouter]. If the `hitTestResult` is not
Expand Down
32 changes: 31 additions & 1 deletion packages/flutter/lib/src/gestures/converter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ int _synthesiseDownButtons(int buttons, PointerDeviceKind kind) {
}
}

/// Signature for a callback that returns the device pixel ratio of a
/// [FlutterView] identified by the provided `viewId`.
///
/// Returns null if no view with the provided ID exists.
///
/// Used by [PointerEventConverter.expand].
///
/// See also:
///
/// * [FlutterView.devicePixelRatio] for an explanation of device pixel ratio.
typedef DevicePixelRatioGetter = double? Function(int viewId);

/// Converts from engine pointer data to framework pointer events.
///
/// This takes [PointerDataPacket] objects, as received from the engine via
Expand All @@ -45,10 +57,15 @@ abstract final class PointerEventConverter {
/// [dart:ui.FlutterView.devicePixelRatio]) is used to convert the incoming data
/// from physical coordinates to logical pixels. See the discussion at
/// [PointerEvent] for more details on the [PointerEvent] coordinate space.
static Iterable<PointerEvent> expand(Iterable<ui.PointerData> data, double devicePixelRatio) {
static Iterable<PointerEvent> expand(Iterable<ui.PointerData> data, DevicePixelRatioGetter devicePixelRatioForView) {
return data
.where((ui.PointerData datum) => datum.signalKind != ui.PointerSignalKind.unknown)
.map<PointerEvent?>((ui.PointerData datum) {
final double? devicePixelRatio = devicePixelRatioForView(datum.viewId);
if (devicePixelRatio == null) {
// View doesn't exist anymore.
return null;
}
final Offset position = Offset(datum.physicalX, datum.physicalY) / devicePixelRatio;
final Offset delta = Offset(datum.physicalDeltaX, datum.physicalDeltaY) / devicePixelRatio;
final double radiusMinor = _toLogicalPixels(datum.radiusMinor, devicePixelRatio);
Expand All @@ -62,6 +79,7 @@ abstract final class PointerEventConverter {
switch (datum.change) {
case ui.PointerChange.add:
return PointerAddedEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
kind: kind,
device: datum.device,
Expand All @@ -79,6 +97,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.hover:
return PointerHoverEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
kind: kind,
device: datum.device,
Expand All @@ -102,6 +121,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.down:
return PointerDownEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
kind: kind,
Expand All @@ -124,6 +144,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.move:
return PointerMoveEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
kind: kind,
Expand All @@ -149,6 +170,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.up:
return PointerUpEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
kind: kind,
Expand All @@ -172,6 +194,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.cancel:
return PointerCancelEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
kind: kind,
Expand All @@ -194,6 +217,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.remove:
return PointerRemovedEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
kind: kind,
device: datum.device,
Expand All @@ -208,6 +232,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.panZoomStart:
return PointerPanZoomStartEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
device: datum.device,
Expand All @@ -221,6 +246,7 @@ abstract final class PointerEventConverter {
final Offset panDelta =
Offset(datum.panDeltaX, datum.panDeltaY) / devicePixelRatio;
return PointerPanZoomUpdateEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
device: datum.device,
Expand All @@ -234,6 +260,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerChange.panZoomEnd:
return PointerPanZoomEndEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
pointer: datum.pointerIdentifier,
device: datum.device,
Expand All @@ -249,6 +276,7 @@ abstract final class PointerEventConverter {
final Offset scrollDelta =
Offset(datum.scrollDeltaX, datum.scrollDeltaY) / devicePixelRatio;
return PointerScrollEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
kind: kind,
device: datum.device,
Expand All @@ -258,6 +286,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerSignalKind.scrollInertiaCancel:
return PointerScrollInertiaCancelEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
kind: kind,
device: datum.device,
Expand All @@ -266,6 +295,7 @@ abstract final class PointerEventConverter {
);
case ui.PointerSignalKind.scale:
return PointerScaleEvent(
viewId: datum.viewId,
timeStamp: timeStamp,
kind: kind,
device: datum.device,
Expand Down
Loading