Commit c9eda86b authored by Adam Barth's avatar Adam Barth Committed by GitHub

Switch to PointerData API (#6131)

Now dart:ui does the decoding of the pointer data itself, which means we don't
need to do it in the framework.
parent 2a530f78
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:mojo/bindings.dart' as bindings;
import 'package:mojo/core.dart' as core;
import 'package:flutter_services/pointer.dart';
ui.Color color; ui.Color color;
ui.Picture paint(ui.Rect paintBounds) { ui.Picture paint(ui.Rect paintBounds) {
...@@ -80,26 +76,18 @@ void beginFrame(Duration timeStamp) { ...@@ -80,26 +76,18 @@ void beginFrame(Duration timeStamp) {
ui.window.render(scene); ui.window.render(scene);
} }
// Pointer input arrives as an array of bytes. The format for the data is void handlePointerDataPacket(ui.PointerDataPacket packet) {
// defined by pointer.mojom, which generates serializes and parsers for a // The pointer packet contains a number of pointer movements, which we iterate
// number of languages, including Dart, C++, Java, and Go. // through and process.
void handlePointerPacket(ByteData serializedPacket) { for (ui.PointerData pointer in packet.pointers) {
// We wrap the byte data up into a Mojo Message object, which we then if (pointer.change == ui.PointerChange.down) {
// deserialize according to the mojom definition.
bindings.Message message = new bindings.Message(serializedPacket, <core.MojoHandle>[], serializedPacket.lengthInBytes, 0);
PointerPacket packet = PointerPacket.deserialize(message);
// The deserialized pointer packet contains a number of pointer movements,
// which we iterate through and process.
for (Pointer pointer in packet.pointers) {
if (pointer.type == PointerType.down) {
// If the pointer went down, we change the color of the circle to blue. // If the pointer went down, we change the color of the circle to blue.
color = const ui.Color(0xFF0000FF); color = const ui.Color(0xFF0000FF);
// Rather than calling paint() synchronously, we ask the engine to // Rather than calling paint() synchronously, we ask the engine to
// schedule a frame. The engine will call onBeginFrame when it is actually // schedule a frame. The engine will call onBeginFrame when it is actually
// time to produce the frame. // time to produce the frame.
ui.window.scheduleFrame(); ui.window.scheduleFrame();
} else if (pointer.type == PointerType.up) { } else if (pointer.change == ui.PointerChange.up) {
// Similarly, if the pointer went up, we change the color of the circle to // Similarly, if the pointer went up, we change the color of the circle to
// green and schedule a frame. It's harmless to call scheduleFrame many // green and schedule a frame. It's harmless to call scheduleFrame many
// times because the engine will ignore redundant requests up until the // times because the engine will ignore redundant requests up until the
...@@ -117,9 +105,9 @@ void main() { ...@@ -117,9 +105,9 @@ void main() {
color = const ui.Color(0xFF00FF00); color = const ui.Color(0xFF00FF00);
// The engine calls onBeginFrame whenever it wants us to produce a frame. // The engine calls onBeginFrame whenever it wants us to produce a frame.
ui.window.onBeginFrame = beginFrame; ui.window.onBeginFrame = beginFrame;
// The engine calls onPointerPacket whenever it had updated information about // The engine calls onPointerDataPacket whenever it had updated information
// the pointers directed at our app. // about the pointers directed at our app.
ui.window.onPointerPacket = handlePointerPacket; ui.window.onPointerDataPacket = handlePointerDataPacket;
// Here we kick off the whole process by asking the engine to schedule a new // Here we kick off the whole process by asking the engine to schedule a new
// frame. The engine will eventually call onBeginFrame when it is time for us // frame. The engine will eventually call onBeginFrame when it is time for us
// to actually produce the frame. // to actually produce the frame.
......
...@@ -4,13 +4,9 @@ ...@@ -4,13 +4,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'dart:typed_data'; import 'dart:ui' as ui show window, PointerDataPacket;
import 'dart:ui' as ui show window;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:mojo/bindings.dart' as mojo_bindings;
import 'package:mojo/core.dart' as mojo_core;
import 'package:flutter_services/pointer.dart';
import 'arena.dart'; import 'arena.dart';
import 'converter.dart'; import 'converter.dart';
...@@ -25,21 +21,14 @@ abstract class GestureBinding extends BindingBase implements HitTestable, HitTes ...@@ -25,21 +21,14 @@ abstract class GestureBinding extends BindingBase implements HitTestable, HitTes
void initInstances() { void initInstances() {
super.initInstances(); super.initInstances();
_instance = this; _instance = this;
ui.window.onPointerPacket = _handlePointerPacket; ui.window.onPointerDataPacket = _handlePointerDataPacket;
} }
/// The singleton instance of this object. /// The singleton instance of this object.
static GestureBinding get instance => _instance; static GestureBinding get instance => _instance;
static GestureBinding _instance; static GestureBinding _instance;
void _handlePointerPacket(ByteData serializedPacket) { void _handlePointerDataPacket(ui.PointerDataPacket packet) {
final mojo_bindings.Message message = new mojo_bindings.Message(
serializedPacket,
<mojo_core.MojoHandle>[],
serializedPacket.lengthInBytes,
0
);
final PointerPacket packet = PointerPacket.deserialize(message);
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.pointers, ui.window.devicePixelRatio)); _pendingPointerEvents.addAll(PointerEventConverter.expand(packet.pointers, ui.window.devicePixelRatio));
_flushPointerEventQueue(); _flushPointerEventQueue();
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter_services/pointer.dart' as mojom; import 'dart:ui' as ui show PointerData, PointerChange;
import 'events.dart'; import 'events.dart';
...@@ -37,14 +37,13 @@ class PointerEventConverter { ...@@ -37,14 +37,13 @@ class PointerEventConverter {
static Map<int, _PointerState> _pointers = <int, _PointerState>{}; static Map<int, _PointerState> _pointers = <int, _PointerState>{};
/// Expand the given packet of pointer data into a sequence of framework pointer events. /// Expand the given packet of pointer data into a sequence of framework pointer events.
static Iterable<PointerEvent> expand(Iterable<mojom.Pointer> packet, double devicePixelRatio) sync* { static Iterable<PointerEvent> expand(Iterable<ui.PointerData> data, double devicePixelRatio) sync* {
for (mojom.Pointer datum in packet) { for (ui.PointerData datum in data) {
Point position = new Point(datum.x, datum.y) / devicePixelRatio; final Point position = new Point(datum.physicalX, datum.physicalY) / devicePixelRatio;
Duration timeStamp = new Duration(microseconds: datum.timeStamp); final Duration timeStamp = datum.timeStamp;
assert(_pointerKindMap.containsKey(datum.kind)); final PointerDeviceKind kind = datum.kind;
PointerDeviceKind kind = _pointerKindMap[datum.kind]; switch (datum.change) {
switch (datum.type) { case ui.PointerChange.down:
case mojom.PointerType.down:
assert(!_pointers.containsKey(datum.pointer)); assert(!_pointers.containsKey(datum.pointer));
_PointerState state = _pointers.putIfAbsent( _PointerState state = _pointers.putIfAbsent(
datum.pointer, datum.pointer,
...@@ -87,7 +86,7 @@ class PointerEventConverter { ...@@ -87,7 +86,7 @@ class PointerEventConverter {
tilt: datum.tilt tilt: datum.tilt
); );
break; break;
case mojom.PointerType.move: case ui.PointerChange.move:
// If the service starts supporting hover pointers, then it must also // If the service starts supporting hover pointers, then it must also
// start sending us ADDED and REMOVED data points. // start sending us ADDED and REMOVED data points.
// See also: https://github.com/flutter/flutter/issues/720 // See also: https://github.com/flutter/flutter/issues/720
...@@ -118,8 +117,8 @@ class PointerEventConverter { ...@@ -118,8 +117,8 @@ class PointerEventConverter {
tilt: datum.tilt tilt: datum.tilt
); );
break; break;
case mojom.PointerType.up: case ui.PointerChange.up:
case mojom.PointerType.cancel: case ui.PointerChange.cancel:
assert(_pointers.containsKey(datum.pointer)); assert(_pointers.containsKey(datum.pointer));
_PointerState state = _pointers[datum.pointer]; _PointerState state = _pointers[datum.pointer];
assert(state.down); assert(state.down);
...@@ -156,7 +155,7 @@ class PointerEventConverter { ...@@ -156,7 +155,7 @@ class PointerEventConverter {
} }
assert(position == state.lastPosition); assert(position == state.lastPosition);
state.setUp(); state.setUp();
if (datum.type == mojom.PointerType.up) { if (datum.change == ui.PointerChange.up) {
yield new PointerUpEvent( yield new PointerUpEvent(
timeStamp: timeStamp, timeStamp: timeStamp,
pointer: state.pointer, pointer: state.pointer,
...@@ -210,11 +209,4 @@ class PointerEventConverter { ...@@ -210,11 +209,4 @@ class PointerEventConverter {
} }
} }
} }
static const Map<mojom.PointerKind, PointerDeviceKind> _pointerKindMap = const <mojom.PointerKind, PointerDeviceKind>{
mojom.PointerKind.touch: PointerDeviceKind.touch,
mojom.PointerKind.mouse: PointerDeviceKind.mouse,
mojom.PointerKind.stylus: PointerDeviceKind.stylus,
mojom.PointerKind.invertedStylus: PointerDeviceKind.invertedStylus,
};
} }
...@@ -2,26 +2,11 @@ ...@@ -2,26 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show Point, Offset; import 'dart:ui' show Point, Offset, PointerDeviceKind;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
export 'dart:ui' show Point, Offset; export 'dart:ui' show Point, Offset, PointerDeviceKind;
/// The kind of pointer device.
enum PointerDeviceKind {
/// A touch-based pointer device.
touch,
/// A pointer device with a stylus.
stylus,
/// A pointer device with a stylus that has been inverted.
invertedStylus,
/// A mouse-based pointer device.
mouse
}
/// The bit of [PointerEvent.buttons] that corresponds to the primary mouse button. /// The bit of [PointerEvent.buttons] that corresponds to the primary mouse button.
/// ///
......
...@@ -6,8 +6,6 @@ import 'dart:ui' as ui; ...@@ -6,8 +6,6 @@ import 'dart:ui' as ui;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:mojo/bindings.dart' as mojo_bindings;
import 'package:flutter_services/pointer.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
typedef void HandleEventCallback(PointerEvent event); typedef void HandleEventCallback(PointerEvent event);
...@@ -35,42 +33,35 @@ void main() { ...@@ -35,42 +33,35 @@ void main() {
setUp(ensureTestGestureBinding); setUp(ensureTestGestureBinding);
test('Pointer tap events', () { test('Pointer tap events', () {
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder(); ui.PointerDataPacket packet = new ui.PointerDataPacket(
pointers: <ui.PointerData>[
PointerPacket packet = new PointerPacket(); new ui.PointerData(change: ui.PointerChange.down),
packet.pointers = <Pointer>[new Pointer(), new Pointer()]; new ui.PointerData(change: ui.PointerChange.up),
packet.pointers[0].type = PointerType.down; ]
packet.pointers[0].kind = PointerKind.touch; );
packet.pointers[1].type = PointerType.up;
packet.pointers[1].kind = PointerKind.touch;
packet.encode(encoder);
List<PointerEvent> events = <PointerEvent>[]; List<PointerEvent> events = <PointerEvent>[];
_binding.callback = (PointerEvent event) => events.add(event); _binding.callback = (PointerEvent event) => events.add(event);
ui.window.onPointerPacket(encoder.message.buffer); ui.window.onPointerDataPacket(packet);
expect(events.length, 2); expect(events.length, 2);
expect(events[0].runtimeType, equals(PointerDownEvent)); expect(events[0].runtimeType, equals(PointerDownEvent));
expect(events[1].runtimeType, equals(PointerUpEvent)); expect(events[1].runtimeType, equals(PointerUpEvent));
}); });
test('Pointer move events', () { test('Pointer move events', () {
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder(); ui.PointerDataPacket packet = new ui.PointerDataPacket(
pointers: <ui.PointerData>[
PointerPacket packet = new PointerPacket(); new ui.PointerData(change: ui.PointerChange.down),
packet.pointers = <Pointer>[new Pointer(), new Pointer(), new Pointer()]; new ui.PointerData(change: ui.PointerChange.move),
packet.pointers[0].type = PointerType.down; new ui.PointerData(change: ui.PointerChange.up),
packet.pointers[0].kind = PointerKind.touch; ]
packet.pointers[1].type = PointerType.move; );
packet.pointers[1].kind = PointerKind.touch;
packet.pointers[2].type = PointerType.up;
packet.pointers[2].kind = PointerKind.touch;
packet.encode(encoder);
List<PointerEvent> events = <PointerEvent>[]; List<PointerEvent> events = <PointerEvent>[];
_binding.callback = (PointerEvent event) => events.add(event); _binding.callback = (PointerEvent event) => events.add(event);
ui.window.onPointerPacket(encoder.message.buffer); ui.window.onPointerDataPacket(packet);
expect(events.length, 3); expect(events.length, 3);
expect(events[0].runtimeType, equals(PointerDownEvent)); expect(events[0].runtimeType, equals(PointerDownEvent));
expect(events[1].runtimeType, equals(PointerMoveEvent)); expect(events[1].runtimeType, equals(PointerMoveEvent));
...@@ -78,26 +69,25 @@ void main() { ...@@ -78,26 +69,25 @@ void main() {
}); });
test('Synthetic move events', () { test('Synthetic move events', () {
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder(); ui.PointerDataPacket packet = new ui.PointerDataPacket(
pointers: <ui.PointerData>[
PointerPacket packet = new PointerPacket(); new ui.PointerData(
packet.pointers = <Pointer>[new Pointer(), new Pointer()]; change: ui.PointerChange.down,
packet.pointers[0] physicalX: 1.0,
..type = PointerType.down physicalY: 3.0,
..kind = PointerKind.touch ),
..x = 1.0 new ui.PointerData(
..y = 3.0; change: ui.PointerChange.up,
packet.pointers[1] physicalX: 10.0,
..type = PointerType.up physicalY: 15.0,
..kind = PointerKind.touch ),
..x = 10.0 ]
..y = 15.0; );
packet.encode(encoder);
List<PointerEvent> events = <PointerEvent>[]; List<PointerEvent> events = <PointerEvent>[];
_binding.callback = (PointerEvent event) => events.add(event); _binding.callback = (PointerEvent event) => events.add(event);
ui.window.onPointerPacket(encoder.message.buffer); ui.window.onPointerDataPacket(packet);
expect(events.length, 3); expect(events.length, 3);
expect(events[0].runtimeType, equals(PointerDownEvent)); expect(events[0].runtimeType, equals(PointerDownEvent));
expect(events[1].runtimeType, equals(PointerMoveEvent)); expect(events[1].runtimeType, equals(PointerMoveEvent));
...@@ -106,35 +96,29 @@ void main() { ...@@ -106,35 +96,29 @@ void main() {
}); });
test('Pointer cancel events', () { test('Pointer cancel events', () {
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder(); ui.PointerDataPacket packet = new ui.PointerDataPacket(
pointers: <ui.PointerData>[
PointerPacket packet = new PointerPacket(); new ui.PointerData(change: ui.PointerChange.down),
packet.pointers = <Pointer>[new Pointer(), new Pointer()]; new ui.PointerData(change: ui.PointerChange.cancel),
packet.pointers[0].type = PointerType.down; ]
packet.pointers[0].kind = PointerKind.touch; );
packet.pointers[1].type = PointerType.cancel;
packet.pointers[1].kind = PointerKind.touch;
packet.encode(encoder);
List<PointerEvent> events = <PointerEvent>[]; List<PointerEvent> events = <PointerEvent>[];
_binding.callback = (PointerEvent event) => events.add(event); _binding.callback = (PointerEvent event) => events.add(event);
ui.window.onPointerPacket(encoder.message.buffer); ui.window.onPointerDataPacket(packet);
expect(events.length, 2); expect(events.length, 2);
expect(events[0].runtimeType, equals(PointerDownEvent)); expect(events[0].runtimeType, equals(PointerDownEvent));
expect(events[1].runtimeType, equals(PointerCancelEvent)); expect(events[1].runtimeType, equals(PointerCancelEvent));
}); });
test('Can cancel pointers', () { test('Can cancel pointers', () {
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder(); ui.PointerDataPacket packet = new ui.PointerDataPacket(
pointers: <ui.PointerData>[
PointerPacket packet = new PointerPacket(); new ui.PointerData(change: ui.PointerChange.down),
packet.pointers = <Pointer>[new Pointer(), new Pointer()]; new ui.PointerData(change: ui.PointerChange.up),
packet.pointers[0].type = PointerType.down; ]
packet.pointers[0].kind = PointerKind.touch; );
packet.pointers[1].type = PointerType.up;
packet.pointers[1].kind = PointerKind.touch;
packet.encode(encoder);
List<PointerEvent> events = <PointerEvent>[]; List<PointerEvent> events = <PointerEvent>[];
_binding.callback = (PointerEvent event) { _binding.callback = (PointerEvent event) {
...@@ -143,7 +127,7 @@ void main() { ...@@ -143,7 +127,7 @@ void main() {
_binding.cancelPointer(event.pointer); _binding.cancelPointer(event.pointer);
}; };
ui.window.onPointerPacket(encoder.message.buffer); ui.window.onPointerDataPacket(packet);
expect(events.length, 2); expect(events.length, 2);
expect(events[0].runtimeType, equals(PointerDownEvent)); expect(events[0].runtimeType, equals(PointerDownEvent));
expect(events[1].runtimeType, equals(PointerCancelEvent)); expect(events[1].runtimeType, equals(PointerCancelEvent));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment