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