diff --git a/packages/flutter/lib/src/gestures/converter.dart b/packages/flutter/lib/src/gestures/converter.dart index 6b992db7e3c..ac8ecb22877 100644 --- a/packages/flutter/lib/src/gestures/converter.dart +++ b/packages/flutter/lib/src/gestures/converter.dart @@ -52,7 +52,7 @@ class PointerEventConverter { static Iterable expand(Iterable data, double devicePixelRatio) { return data .where((ui.PointerData datum) => datum.signalKind != ui.PointerSignalKind.unknown) - .map((ui.PointerData datum) { + .map((ui.PointerData datum) { 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); @@ -247,6 +247,9 @@ class PointerEventConverter { ); } case ui.PointerSignalKind.scroll: + if (!datum.scrollDeltaX.isFinite || !datum.scrollDeltaY.isFinite || devicePixelRatio <= 0) { + return null; + } final Offset scrollDelta = Offset(datum.scrollDeltaX, datum.scrollDeltaY) / devicePixelRatio; return PointerScrollEvent( @@ -280,7 +283,7 @@ class PointerEventConverter { // enumeration to PointerSignalKind. throw StateError('Unreachable'); } - }); + }).whereType(); } static double _toLogicalPixels(double physicalPixels, double devicePixelRatio) => physicalPixels / devicePixelRatio; diff --git a/packages/flutter/test/gestures/gesture_binding_test.dart b/packages/flutter/test/gestures/gesture_binding_test.dart index 05f6da7d4ae..223d0d1fad4 100644 --- a/packages/flutter/test/gestures/gesture_binding_test.dart +++ b/packages/flutter/test/gestures/gesture_binding_test.dart @@ -177,6 +177,47 @@ void main() { expect(events[4], isA()); }); + test('Can handle malformed scrolling event.', () { + ui.PointerDataPacket packet = const ui.PointerDataPacket( + data: [ + ui.PointerData(change: ui.PointerChange.add, device: 24), + ], + ); + List events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); + + expect(events.length, 1); + expect(events[0], isA()); + + // Send packet contains malformed scroll events. + packet = const ui.PointerDataPacket( + data: [ + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaX: double.infinity, scrollDeltaY: 10), + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaX: double.nan, scrollDeltaY: 10), + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaX: double.negativeInfinity, scrollDeltaY: 10), + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaY: double.infinity, scrollDeltaX: 10), + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaY: double.nan, scrollDeltaX: 10), + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaY: double.negativeInfinity, scrollDeltaX: 10), + ], + ); + events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); + expect(events.length, 0); + + // Send packet with a valid scroll event. + packet = const ui.PointerDataPacket( + data: [ + ui.PointerData(signalKind: ui.PointerSignalKind.scroll, device: 24, scrollDeltaX: 10, scrollDeltaY: 10), + ], + ); + // Make sure PointerEventConverter can expand when device pixel ratio is valid. + events = PointerEventConverter.expand(packet.data, GestureBinding.instance.window.devicePixelRatio).toList(); + expect(events.length, 1); + expect(events[0], isA()); + + // Make sure PointerEventConverter returns none when device pixel ratio is invalid. + events = PointerEventConverter.expand(packet.data, 0).toList(); + expect(events.length, 0); + }); + test('Can expand pointer scroll events', () { const ui.PointerDataPacket packet = ui.PointerDataPacket( data: [