Commit ade93651 authored by Ian Hickson's avatar Ian Hickson

Refactor bindings.

parent 94871975
...@@ -42,5 +42,5 @@ void main() { ...@@ -42,5 +42,5 @@ void main() {
child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0)) child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0))
); );
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root);
} }
...@@ -87,5 +87,5 @@ void main() { ...@@ -87,5 +87,5 @@ void main() {
direction: FlexDirection.vertical, direction: FlexDirection.vertical,
alignItems: FlexAlignItems.stretch alignItems: FlexAlignItems.stretch
); );
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root);
} }
...@@ -73,5 +73,5 @@ void main() { ...@@ -73,5 +73,5 @@ void main() {
], ],
direction: FlexDirection.vertical direction: FlexDirection.vertical
); );
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root);
} }
...@@ -53,5 +53,5 @@ RenderBox buildFlexExample() { ...@@ -53,5 +53,5 @@ RenderBox buildFlexExample() {
} }
void main() { void main() {
new FlutterBinding(root: buildFlexExample()); new RenderingFlutterBinding(root: buildFlexExample());
} }
...@@ -6,6 +6,7 @@ import 'dart:ui' as ui; ...@@ -6,6 +6,7 @@ import 'dart:ui' as ui;
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:mojo/bindings.dart' as bindings; import 'package:mojo/bindings.dart' as bindings;
...@@ -37,25 +38,32 @@ class RenderImageGrow extends RenderImage { ...@@ -37,25 +38,32 @@ class RenderImageGrow extends RenderImage {
RenderImageGrow image; RenderImageGrow image;
void handlePopRoute() { class DemoBinding extends BindingBase with Scheduler, Renderer {
activity.finishCurrentActivity(); DemoBinding({ RenderBox root }) {
} renderView.child = root;
ui.window.onPopRoute = handlePopRoute;
final Map<int, Touch> touches = <int, Touch>{}; ui.window.onPointerPacket = handlePointerPacket;
}
void handlePointerPacket(ByteData serializedPacket) { void handlePopRoute() {
bindings.Message message = new bindings.Message( activity.finishCurrentActivity();
serializedPacket, }
<core.MojoHandle>[],
serializedPacket.lengthInBytes,
0
);
PointerPacket packet = PointerPacket.deserialize(message);
for (Pointer pointer in packet.pointers) { final Map<int, Touch> touches = <int, Touch>{};
if (pointer.type == PointerType.MOVE)
image.growth = math.max(0.0, image.growth + pointer.x - touches[pointer.pointer].x); void handlePointerPacket(ByteData serializedPacket) {
touches[pointer.pointer] = new Touch(pointer.x, pointer.y); bindings.Message message = new bindings.Message(
serializedPacket,
<core.MojoHandle>[],
serializedPacket.lengthInBytes,
0
);
PointerPacket packet = PointerPacket.deserialize(message);
for (Pointer pointer in packet.pointers) {
if (pointer.type == PointerType.MOVE)
image.growth = math.max(0.0, image.growth + pointer.x - touches[pointer.pointer].x);
touches[pointer.pointer] = new Touch(pointer.x, pointer.y);
}
} }
} }
...@@ -74,7 +82,7 @@ void main() { ...@@ -74,7 +82,7 @@ void main() {
// Resizeable image // Resizeable image
image = new RenderImageGrow(null, new Size(100.0, null)); image = new RenderImageGrow(null, new Size(100.0, null));
imageCache.load("https://www.dartlang.org/logos/dart-logo.png").first.then((ui.Image dartLogo) { imageCache.load("http://flutter.io/favicon.ico").first.then((ui.Image dartLogo) {
image.image = dartLogo; image.image = dartLogo;
}); });
...@@ -114,7 +122,5 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin."""; ...@@ -114,7 +122,5 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
); );
updateTaskDescription('Interactive Flex', topColor); updateTaskDescription('Interactive Flex', topColor);
new FlutterBinding(root: root); new DemoBinding(root: root);
ui.window.onPopRoute = handlePopRoute;
ui.window.onPointerPacket = handlePointerPacket;
} }
...@@ -37,5 +37,5 @@ void main() { ...@@ -37,5 +37,5 @@ void main() {
child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0)) child: new RenderPadding(child: table, padding: new EdgeDims.symmetric(vertical: 50.0))
); );
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root);
} }
...@@ -23,4 +23,4 @@ RenderBox buildGridExample() { ...@@ -23,4 +23,4 @@ RenderBox buildGridExample() {
return new RenderGrid(children: children, maxChildExtent: 100.0); return new RenderGrid(children: children, maxChildExtent: 100.0);
} }
main() => new FlutterBinding(root: buildGridExample()); main() => new RenderingFlutterBinding(root: buildGridExample());
...@@ -40,5 +40,5 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin."""; ...@@ -40,5 +40,5 @@ Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
childParentData = child.parentData; childParentData = child.parentData;
childParentData.flex = 1; childParentData.flex = 1;
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root);
} }
...@@ -18,5 +18,5 @@ RenderBox buildSectorExample() { ...@@ -18,5 +18,5 @@ RenderBox buildSectorExample() {
} }
void main() { void main() {
new FlutterBinding(root: buildSectorExample()); new RenderingFlutterBinding(root: buildSectorExample());
} }
...@@ -18,7 +18,7 @@ void main() { ...@@ -18,7 +18,7 @@ void main() {
var paddedBox = new RenderPadding( var paddedBox = new RenderPadding(
padding: const EdgeDims.all(50.0), padding: const EdgeDims.all(50.0),
child: coloredBox); child: coloredBox);
new FlutterBinding(root: new RenderDecoratedBox( new RenderingFlutterBinding(root: new RenderDecoratedBox(
decoration: const BoxDecoration( decoration: const BoxDecoration(
backgroundColor: const Color(0xFFFFFFFF) backgroundColor: const Color(0xFFFFFFFF)
), ),
......
...@@ -59,5 +59,5 @@ void main() { ...@@ -59,5 +59,5 @@ void main() {
(p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint, (p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
]); ]);
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root);
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'lib/solid_color_box.dart'; import 'lib/solid_color_box.dart';
...@@ -30,9 +29,8 @@ void main() { ...@@ -30,9 +29,8 @@ void main() {
RenderPadding root = new RenderPadding(padding: new EdgeDims.all(20.0), child: transformBox); RenderPadding root = new RenderPadding(padding: new EdgeDims.all(20.0), child: transformBox);
new FlutterBinding(root: root); new RenderingFlutterBinding(root: root)
..addPersistentFrameCallback(rotate);
scheduler.addPersistentFrameCallback(rotate);
} }
void rotate(Duration timeStamp) { void rotate(Duration timeStamp) {
......
...@@ -77,5 +77,5 @@ void main() { ...@@ -77,5 +77,5 @@ void main() {
final StackParentData paragraphParentData = paragraph.parentData; final StackParentData paragraphParentData = paragraph.parentData;
paragraphParentData..top = 40.0 paragraphParentData..top = 40.0
..left = 20.0; ..left = 20.0;
new FlutterBinding(root: stack); new RenderingFlutterBinding(root: stack);
} }
...@@ -24,5 +24,5 @@ void main() { ...@@ -24,5 +24,5 @@ void main() {
RenderFlex flex = new RenderFlex(); RenderFlex flex = new RenderFlex();
flex.add(spin); flex.add(spin);
new FlutterBinding(root: flex); new RenderingFlutterBinding(root: flex);
} }
...@@ -6,7 +6,6 @@ import 'dart:ui' as ui; ...@@ -6,7 +6,6 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_rendering_examples/solid_color_box.dart'; import 'package:flutter_rendering_examples/solid_color_box.dart';
...@@ -84,11 +83,6 @@ void rotate(Duration timeStamp) { ...@@ -84,11 +83,6 @@ void rotate(Duration timeStamp) {
} }
void main() { void main() {
// Because we're going to use Widgets, we want to ensure we're using a
// WidgetFlutterBinding rather than some other kind of binding (e.g. a
// straight rendering library FlutterBinding).
WidgetFlutterBinding.ensureInitialized();
RenderProxyBox proxy = new RenderProxyBox(); RenderProxyBox proxy = new RenderProxyBox();
attachWidgetTreeToRenderTree(proxy); attachWidgetTreeToRenderTree(proxy);
...@@ -100,6 +94,7 @@ void main() { ...@@ -100,6 +94,7 @@ void main() {
transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity()); transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity());
RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox); RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox);
FlutterBinding.instance.renderView.child = root; WidgetFlutterBinding.ensureInitialized()
scheduler.addPersistentFrameCallback(rotate); ..renderView.child = root
..addPersistentFrameCallback(rotate);
} }
...@@ -6,9 +6,12 @@ ...@@ -6,9 +6,12 @@
library gestures; library gestures;
export 'src/gestures/arena.dart'; export 'src/gestures/arena.dart';
export 'src/gestures/binding.dart';
export 'src/gestures/constants.dart'; export 'src/gestures/constants.dart';
export 'src/gestures/converter.dart';
export 'src/gestures/drag.dart'; export 'src/gestures/drag.dart';
export 'src/gestures/events.dart'; export 'src/gestures/events.dart';
export 'src/gestures/hit_test.dart';
export 'src/gestures/long_press.dart'; export 'src/gestures/long_press.dart';
export 'src/gestures/lsq_solver.dart'; export 'src/gestures/lsq_solver.dart';
export 'src/gestures/multitap.dart'; export 'src/gestures/multitap.dart';
......
...@@ -16,7 +16,6 @@ export 'src/rendering/editable_paragraph.dart'; ...@@ -16,7 +16,6 @@ export 'src/rendering/editable_paragraph.dart';
export 'src/rendering/error.dart'; export 'src/rendering/error.dart';
export 'src/rendering/flex.dart'; export 'src/rendering/flex.dart';
export 'src/rendering/grid.dart'; export 'src/rendering/grid.dart';
export 'src/rendering/hit_test.dart';
export 'src/rendering/image.dart'; export 'src/rendering/image.dart';
export 'src/rendering/layer.dart'; export 'src/rendering/layer.dart';
export 'src/rendering/node.dart'; export 'src/rendering/node.dart';
......
...@@ -13,6 +13,7 @@ library services; ...@@ -13,6 +13,7 @@ library services;
export 'src/services/activity.dart'; export 'src/services/activity.dart';
export 'src/services/asset_bundle.dart'; export 'src/services/asset_bundle.dart';
export 'src/services/binding.dart';
export 'src/services/fetch.dart'; export 'src/services/fetch.dart';
export 'src/services/image_cache.dart'; export 'src/services/image_cache.dart';
export 'src/services/image_decoder.dart'; export 'src/services/image_decoder.dart';
......
...@@ -40,7 +40,7 @@ class Ticker { ...@@ -40,7 +40,7 @@ class Ticker {
_startTime = null; _startTime = null;
if (_animationId != null) { if (_animationId != null) {
scheduler.cancelFrameCallbackWithId(_animationId); Scheduler.instance.cancelFrameCallbackWithId(_animationId);
_animationId = null; _animationId = null;
} }
...@@ -74,6 +74,6 @@ class Ticker { ...@@ -74,6 +74,6 @@ class Ticker {
void _scheduleTick() { void _scheduleTick() {
assert(isTicking); assert(isTicking);
assert(_animationId == null); assert(_animationId == null);
_animationId = scheduler.scheduleFrameCallback(_tick); _animationId = Scheduler.instance.scheduleFrameCallback(_tick);
} }
} }
...@@ -64,8 +64,6 @@ class _GestureArenaState { ...@@ -64,8 +64,6 @@ class _GestureArenaState {
class GestureArena { class GestureArena {
final Map<Object, _GestureArenaState> _arenas = new Map<Object, _GestureArenaState>(); final Map<Object, _GestureArenaState> _arenas = new Map<Object, _GestureArenaState>();
static final GestureArena instance = new GestureArena();
GestureArenaEntry add(Object key, GestureArenaMember member) { GestureArenaEntry add(Object key, GestureArenaMember member) {
_GestureArenaState state = _arenas.putIfAbsent(key, () => new _GestureArenaState()); _GestureArenaState state = _arenas.putIfAbsent(key, () => new _GestureArenaState());
state.add(member); state.add(member);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/services.dart';
import 'package:mojo/bindings.dart' as mojo_bindings;
import 'package:mojo/core.dart' as mojo_core;
import 'package:sky_services/pointer/pointer.mojom.dart';
import 'arena.dart';
import 'converter.dart';
import 'events.dart';
import 'hit_test.dart';
import 'pointer_router.dart';
abstract class Pointerer extends BindingBase implements HitTestTarget, HitTestable {
void initInstances() {
super.initInstances();
_instance = this;
ui.window.onPointerPacket = _handlePointerPacket;
}
static Pointerer _instance;
static Pointerer get instance => _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);
for (PointerEvent event in PointerEventConverter.expand(packet.pointers))
_handlePointerEvent(event);
}
/// A router that routes all pointer events received from the engine.
final PointerRouter pointerRouter = new PointerRouter();
/// The gesture arenas used for disambiguating the meaning of sequences of
/// pointer events.
final GestureArena gestureArena = new GestureArena();
/// State for all pointers which are currently down.
///
/// The state of hovering pointers is not tracked because that would require
/// hit-testing on every frame.
Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};
void _handlePointerEvent(PointerEvent event) {
if (event is PointerDownEvent) {
assert(!_hitTests.containsKey(event.pointer));
HitTestResult result = new HitTestResult();
hitTest(result, event.position);
_hitTests[event.pointer] = result;
} else if (event is! PointerUpEvent) {
assert(event.down == _hitTests.containsKey(event.pointer));
if (!event.down)
return; // we currently ignore add, remove, and hover move events
}
assert(_hitTests[event.pointer] != null);
dispatchEvent(event, _hitTests[event.pointer]);
if (event is PointerUpEvent) {
assert(_hitTests.containsKey(event.pointer));
_hitTests.remove(event.pointer);
}
}
/// Determine which [HitTestTarget] objects are located at a given position.
void hitTest(HitTestResult result, Point position) {
result.add(new HitTestEntry(this));
}
/// Dispatch the given event to the path of the given hit test result
void dispatchEvent(PointerEvent event, HitTestResult result) {
assert(result != null);
for (HitTestEntry entry in result.path)
entry.target.handleEvent(event, entry);
}
void handleEvent(PointerEvent event, HitTestEntry entry) {
pointerRouter.route(event);
if (event is PointerDownEvent) {
gestureArena.close(event.pointer);
} else if (event is PointerUpEvent) {
gestureArena.sweep(event.pointer);
}
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky_services/pointer/pointer.mojom.dart';
import 'events.dart';
class _PointerState {
_PointerState(this.lastPosition);
int get pointer => _pointer; // The identifier used in PointerEvent objects.
int _pointer;
static int _pointerCount = 0;
void startNewPointer() {
_pointerCount += 1;
_pointer = _pointerCount;
}
bool get down => _down;
bool _down = false;
void setDown() {
assert(!_down);
_down = true;
}
void setUp() {
assert(_down);
_down = false;
}
Point lastPosition;
}
class PointerEventConverter {
// Map from platform pointer identifiers to PointerEvent pointer identifiers.
static Map<int, _PointerState> _pointers = <int, _PointerState>{};
static Iterable<PointerEvent> expand(Iterable<Pointer> packet) sync* {
for (Pointer datum in packet) {
Point position = new Point(datum.x, datum.y);
Duration timeStamp = new Duration(microseconds: datum.timeStamp);
assert(_pointerKindMap.containsKey(datum.kind));
PointerDeviceKind kind = _pointerKindMap[datum.kind];
switch (datum.type) {
case PointerType.DOWN:
assert(!_pointers.containsKey(datum.pointer));
_PointerState state = _pointers.putIfAbsent(
datum.pointer,
() => new _PointerState(position)
);
assert(state.lastPosition == position);
state.startNewPointer();
state.setDown();
yield new PointerAddedEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
position: position,
obscured: datum.obscured,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distance: datum.distance,
distanceMax: datum.distanceMax,
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
);
yield new PointerDownEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
position: position,
obscured: datum.obscured,
pressure: datum.pressure,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distanceMax: datum.distanceMax,
radiusMajor: datum.radiusMajor,
radiusMinor: datum.radiusMajor,
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
);
break;
case PointerType.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
assert(_pointers.containsKey(datum.pointer));
_PointerState state = _pointers[datum.pointer];
assert(state.down);
Offset offset = position - state.lastPosition;
state.lastPosition = position;
yield new PointerMoveEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
position: position,
delta: offset,
down: state.down,
obscured: datum.obscured,
pressure: datum.pressure,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distance: datum.distance,
distanceMax: datum.distanceMax,
radiusMajor: datum.radiusMajor,
radiusMinor: datum.radiusMajor,
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
);
break;
case PointerType.UP:
case PointerType.CANCEL:
assert(_pointers.containsKey(datum.pointer));
_PointerState state = _pointers[datum.pointer];
assert(state.down);
assert(position == state.lastPosition);
state.setUp();
if (datum.type == PointerType.UP) {
yield new PointerUpEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
position: position,
obscured: datum.obscured,
pressureMax: datum.pressureMax,
distance: datum.distance,
distanceMax: datum.distanceMax,
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
);
} else {
yield new PointerCancelEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
position: position,
obscured: datum.obscured,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distance: datum.distance,
distanceMax: datum.distanceMax,
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
);
}
yield new PointerRemovedEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
obscured: datum.obscured,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distanceMax: datum.distanceMax,
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax
);
_pointers.remove(datum.pointer);
break;
default:
// TODO(ianh): once https://github.com/flutter/flutter/issues/720 is
// done, add real support for PointerAddedEvent and PointerRemovedEvent
assert(false);
}
}
}
static const Map<PointerKind, PointerDeviceKind> _pointerKindMap = const <PointerKind, PointerDeviceKind>{
PointerKind.TOUCH: PointerDeviceKind.touch,
PointerKind.MOUSE: PointerDeviceKind.mouse,
PointerKind.STYLUS: PointerDeviceKind.stylus,
PointerKind.INVERTED_STYLUS: PointerDeviceKind.invertedStylus,
};
}
...@@ -32,8 +32,16 @@ bool _isFlingGesture(Offset velocity) { ...@@ -32,8 +32,16 @@ bool _isFlingGesture(Offset velocity) {
} }
abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGestureRecognizer { abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGestureRecognizer {
_DragGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd }) _DragGestureRecognizer({
: super(router: router); PointerRouter router,
GestureArena gestureArena,
this.onStart,
this.onUpdate,
this.onEnd
}) : super(
router: router,
gestureArena: gestureArena
);
GestureDragStartCallback onStart; GestureDragStartCallback onStart;
_GesturePolymorphicUpdateCallback<T> onUpdate; _GesturePolymorphicUpdateCallback<T> onUpdate;
...@@ -120,10 +128,17 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest ...@@ -120,10 +128,17 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> { class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
VerticalDragGestureRecognizer({ VerticalDragGestureRecognizer({
PointerRouter router, PointerRouter router,
GestureArena gestureArena,
GestureDragStartCallback onStart, GestureDragStartCallback onStart,
GestureDragUpdateCallback onUpdate, GestureDragUpdateCallback onUpdate,
GestureDragEndCallback onEnd GestureDragEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd); }) : super(
router: router,
gestureArena: gestureArena,
onStart: onStart,
onUpdate: onUpdate,
onEnd: onEnd
);
double get _initialPendingDragDelta => 0.0; double get _initialPendingDragDelta => 0.0;
double _getDragDelta(PointerEvent event) => event.delta.dy; double _getDragDelta(PointerEvent event) => event.delta.dy;
...@@ -133,10 +148,17 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> { ...@@ -133,10 +148,17 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> { class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
HorizontalDragGestureRecognizer({ HorizontalDragGestureRecognizer({
PointerRouter router, PointerRouter router,
GestureArena gestureArena,
GestureDragStartCallback onStart, GestureDragStartCallback onStart,
GestureDragUpdateCallback onUpdate, GestureDragUpdateCallback onUpdate,
GestureDragEndCallback onEnd GestureDragEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd); }) : super(
router: router,
gestureArena: gestureArena,
onStart: onStart,
onUpdate: onUpdate,
onEnd: onEnd
);
double get _initialPendingDragDelta => 0.0; double get _initialPendingDragDelta => 0.0;
double _getDragDelta(PointerEvent event) => event.delta.dx; double _getDragDelta(PointerEvent event) => event.delta.dx;
...@@ -146,10 +168,17 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> { ...@@ -146,10 +168,17 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
class PanGestureRecognizer extends _DragGestureRecognizer<Offset> { class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
PanGestureRecognizer({ PanGestureRecognizer({
PointerRouter router, PointerRouter router,
GestureArena gestureArena,
GesturePanStartCallback onStart, GesturePanStartCallback onStart,
GesturePanUpdateCallback onUpdate, GesturePanUpdateCallback onUpdate,
GesturePanEndCallback onEnd GesturePanEndCallback onEnd
}) : super(router: router, onStart: onStart, onUpdate: onUpdate, onEnd: onEnd); }) : super(
router: router,
gestureArena: gestureArena,
onStart: onStart,
onUpdate: onUpdate,
onEnd: onEnd
);
Offset get _initialPendingDragDelta => Offset.zero; Offset get _initialPendingDragDelta => Offset.zero;
Offset _getDragDelta(PointerEvent event) => event.delta; Offset _getDragDelta(PointerEvent event) => event.delta;
......
...@@ -2,7 +2,12 @@ ...@@ -2,7 +2,12 @@
// 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/gestures.dart'; import 'events.dart';
/// An object that can hit-test pointers.
abstract class HitTestable {
void hitTest(HitTestResult result, Point position);
}
/// An object that can handle events. /// An object that can handle events.
abstract class HitTestTarget { abstract class HitTestTarget {
......
...@@ -11,8 +11,15 @@ import 'recognizer.dart'; ...@@ -11,8 +11,15 @@ import 'recognizer.dart';
typedef void GestureLongPressCallback(); typedef void GestureLongPressCallback();
class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer { class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
LongPressGestureRecognizer({ PointerRouter router, this.onLongPress }) LongPressGestureRecognizer({
: super(router: router, deadline: kLongPressTimeout); PointerRouter router,
GestureArena gestureArena,
this.onLongPress
}) : super(
router: router,
gestureArena: gestureArena,
deadline: kLongPressTimeout
);
GestureLongPressCallback onLongPress; GestureLongPressCallback onLongPress;
......
...@@ -58,9 +58,12 @@ class DoubleTapGestureRecognizer extends GestureRecognizer { ...@@ -58,9 +58,12 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
DoubleTapGestureRecognizer({ DoubleTapGestureRecognizer({
PointerRouter router, PointerRouter router,
GestureArena gestureArena,
this.onDoubleTap this.onDoubleTap
}) : _router = router { }) : _router = router,
_gestureArena = gestureArena {
assert(router != null); assert(router != null);
assert(gestureArena != null);
} }
// Implementation notes: // Implementation notes:
...@@ -84,6 +87,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer { ...@@ -84,6 +87,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
// - The gesture arena decides we have been rejected wholesale // - The gesture arena decides we have been rejected wholesale
PointerRouter _router; PointerRouter _router;
GestureArena _gestureArena;
GestureDoubleTapCallback onDoubleTap; GestureDoubleTapCallback onDoubleTap;
Timer _doubleTapTimer; Timer _doubleTapTimer;
...@@ -98,7 +102,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer { ...@@ -98,7 +102,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
_stopDoubleTapTimer(); _stopDoubleTapTimer();
_TapTracker tracker = new _TapTracker( _TapTracker tracker = new _TapTracker(
event: event, event: event,
entry: GestureArena.instance.add(event.pointer, this) entry: _gestureArena.add(event.pointer, this)
); );
_trackers[event.pointer] = tracker; _trackers[event.pointer] = tracker;
tracker.startTrackingPointer(_router, handleEvent); tracker.startTrackingPointer(_router, handleEvent);
...@@ -149,6 +153,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer { ...@@ -149,6 +153,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
void dispose() { void dispose() {
_reset(); _reset();
_router = null; _router = null;
_gestureArena = null;
} }
void _reset() { void _reset() {
...@@ -159,14 +164,14 @@ class DoubleTapGestureRecognizer extends GestureRecognizer { ...@@ -159,14 +164,14 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
_TapTracker tracker = _firstTap; _TapTracker tracker = _firstTap;
_firstTap = null; _firstTap = null;
_reject(tracker); _reject(tracker);
GestureArena.instance.release(tracker.pointer); _gestureArena.release(tracker.pointer);
} }
_clearTrackers(); _clearTrackers();
} }
void _registerFirstTap(_TapTracker tracker) { void _registerFirstTap(_TapTracker tracker) {
_startDoubleTapTimer(); _startDoubleTapTimer();
GestureArena.instance.hold(tracker.pointer); _gestureArena.hold(tracker.pointer);
// Note, order is important below in order for the clear -> reject logic to // Note, order is important below in order for the clear -> reject logic to
// work properly. // work properly.
_freezeTracker(tracker); _freezeTracker(tracker);
...@@ -226,7 +231,10 @@ class _TapGesture extends _TapTracker { ...@@ -226,7 +231,10 @@ class _TapGesture extends _TapTracker {
Duration longTapDelay Duration longTapDelay
}) : gestureRecognizer = gestureRecognizer, }) : gestureRecognizer = gestureRecognizer,
_lastPosition = event.position, _lastPosition = event.position,
super(event: event, entry: GestureArena.instance.add(event.pointer, gestureRecognizer)) { super(
event: event,
entry: gestureRecognizer._gestureArena.add(event.pointer, gestureRecognizer)
) {
startTrackingPointer(gestureRecognizer.router, handleEvent); startTrackingPointer(gestureRecognizer.router, handleEvent);
if (longTapDelay > Duration.ZERO) { if (longTapDelay > Duration.ZERO) {
_timer = new Timer(longTapDelay, () { _timer = new Timer(longTapDelay, () {
...@@ -299,18 +307,23 @@ class _TapGesture extends _TapTracker { ...@@ -299,18 +307,23 @@ class _TapGesture extends _TapTracker {
class MultiTapGestureRecognizer extends GestureRecognizer { class MultiTapGestureRecognizer extends GestureRecognizer {
MultiTapGestureRecognizer({ MultiTapGestureRecognizer({
PointerRouter router, PointerRouter router,
GestureArena gestureArena,
this.onTapDown, this.onTapDown,
this.onTapUp, this.onTapUp,
this.onTap, this.onTap,
this.onTapCancel, this.onTapCancel,
this.longTapDelay: Duration.ZERO, this.longTapDelay: Duration.ZERO,
this.onLongTapDown this.onLongTapDown
}) : _router = router { }) : _router = router,
_gestureArena = gestureArena {
assert(router != null); assert(router != null);
assert(gestureArena != null);
} }
PointerRouter get router => _router; PointerRouter get router => _router;
PointerRouter _router; PointerRouter _router;
GestureArena get gestureArena => _gestureArena;
GestureArena _gestureArena;
GestureMultiTapDownCallback onTapDown; GestureMultiTapDownCallback onTapDown;
GestureMultiTapUpCallback onTapUp; GestureMultiTapUpCallback onTapUp;
GestureMultiTapCallback onTap; GestureMultiTapCallback onTap;
...@@ -369,6 +382,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer { ...@@ -369,6 +382,7 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
// Rejection of each gesture should cause it to be removed from our map // Rejection of each gesture should cause it to be removed from our map
assert(_gestureMap.isEmpty); assert(_gestureMap.isEmpty);
_router = null; _router = null;
_gestureArena = null;
} }
} }
...@@ -30,11 +30,17 @@ abstract class GestureRecognizer extends GestureArenaMember { ...@@ -30,11 +30,17 @@ abstract class GestureRecognizer extends GestureArenaMember {
} }
abstract class OneSequenceGestureRecognizer extends GestureRecognizer { abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
OneSequenceGestureRecognizer({ PointerRouter router }) : _router = router { OneSequenceGestureRecognizer({
PointerRouter router,
GestureArena gestureArena
}) : _router = router,
_gestureArena = gestureArena {
assert(_router != null); assert(_router != null);
assert(_gestureArena != null);
} }
PointerRouter _router; PointerRouter _router;
GestureArena _gestureArena;
final List<GestureArenaEntry> _entries = <GestureArenaEntry>[]; final List<GestureArenaEntry> _entries = <GestureArenaEntry>[];
final Set<int> _trackedPointers = new Set<int>(); final Set<int> _trackedPointers = new Set<int>();
...@@ -58,12 +64,13 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer { ...@@ -58,12 +64,13 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
_trackedPointers.clear(); _trackedPointers.clear();
assert(_entries.isEmpty); assert(_entries.isEmpty);
_router = null; _router = null;
_gestureArena = null;
} }
void startTrackingPointer(int pointer) { void startTrackingPointer(int pointer) {
_router.addRoute(pointer, handleEvent); _router.addRoute(pointer, handleEvent);
_trackedPointers.add(pointer); _trackedPointers.add(pointer);
_entries.add(GestureArena.instance.add(pointer, this)); _entries.add(_gestureArena.add(pointer, this));
} }
void stopTrackingPointer(int pointer) { void stopTrackingPointer(int pointer) {
...@@ -87,8 +94,14 @@ enum GestureRecognizerState { ...@@ -87,8 +94,14 @@ enum GestureRecognizerState {
} }
abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecognizer { abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecognizer {
PrimaryPointerGestureRecognizer({ PointerRouter router, this.deadline }) PrimaryPointerGestureRecognizer({
: super(router: router); PointerRouter router,
GestureArena gestureArena,
this.deadline
}) : super(
router: router,
gestureArena: gestureArena
);
final Duration deadline; final Duration deadline;
......
...@@ -19,8 +19,16 @@ typedef void GestureScaleUpdateCallback(double scale, Point focalPoint); ...@@ -19,8 +19,16 @@ typedef void GestureScaleUpdateCallback(double scale, Point focalPoint);
typedef void GestureScaleEndCallback(); typedef void GestureScaleEndCallback();
class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
ScaleGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd }) ScaleGestureRecognizer({
: super(router: router); PointerRouter router,
GestureArena gestureArena,
this.onStart,
this.onUpdate,
this.onEnd
}) : super(
router: router,
gestureArena: gestureArena
);
GestureScaleStartCallback onStart; GestureScaleStartCallback onStart;
GestureScaleUpdateCallback onUpdate; GestureScaleUpdateCallback onUpdate;
......
...@@ -19,11 +19,16 @@ typedef void GestureTapCancelCallback(); ...@@ -19,11 +19,16 @@ typedef void GestureTapCancelCallback();
class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
TapGestureRecognizer({ TapGestureRecognizer({
PointerRouter router, PointerRouter router,
GestureArena gestureArena,
this.onTapDown, this.onTapDown,
this.onTapUp, this.onTapUp,
this.onTap, this.onTap,
this.onTapCancel this.onTapCancel
}) : super(router: router, deadline: kPressTimeout); }) : super(
router: router,
gestureArena: gestureArena,
deadline: kPressTimeout
);
GestureTapDownCallback onTapDown; GestureTapDownCallback onTapDown;
GestureTapDownCallback onTapUp; GestureTapDownCallback onTapUp;
......
...@@ -74,11 +74,11 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver { ...@@ -74,11 +74,11 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
_navigator = new GlobalObjectKey(this); _navigator = new GlobalObjectKey(this);
_size = ui.window.size; _size = ui.window.size;
didChangeLocale(ui.window.locale); didChangeLocale(ui.window.locale);
FlutterBinding.instance.addObserver(this); WidgetFlutterBinding.instance.addObserver(this);
} }
void dispose() { void dispose() {
FlutterBinding.instance.removeObserver(this); WidgetFlutterBinding.instance.removeObserver(this);
super.dispose(); super.dispose();
} }
......
...@@ -86,7 +86,7 @@ class _RenderSlider extends RenderConstrainedBox { ...@@ -86,7 +86,7 @@ class _RenderSlider extends RenderConstrainedBox {
_activeColor = activeColor, _activeColor = activeColor,
super(additionalConstraints: const BoxConstraints.tightFor(width: _kTrackWidth + 2 * _kReactionRadius, height: 2 * _kReactionRadius)) { super(additionalConstraints: const BoxConstraints.tightFor(width: _kTrackWidth + 2 * _kReactionRadius, height: 2 * _kReactionRadius)) {
assert(value != null && value >= 0.0 && value <= 1.0); assert(value != null && value >= 0.0 && value <= 1.0);
_drag = new HorizontalDragGestureRecognizer(router: FlutterBinding.instance.pointerRouter) _drag = new HorizontalDragGestureRecognizer(router: Pointerer.instance.pointerRouter, gestureArena: Pointerer.instance.gestureArena)
..onStart = _handleDragStart ..onStart = _handleDragStart
..onUpdate = _handleDragUpdate ..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd; ..onEnd = _handleDragEnd;
......
...@@ -115,7 +115,7 @@ class _RenderSwitch extends RenderToggleable { ...@@ -115,7 +115,7 @@ class _RenderSwitch extends RenderToggleable {
) { ) {
_activeTrackColor = activeTrackColor; _activeTrackColor = activeTrackColor;
_inactiveTrackColor = inactiveTrackColor; _inactiveTrackColor = inactiveTrackColor;
_drag = new HorizontalDragGestureRecognizer(router: FlutterBinding.instance.pointerRouter) _drag = new HorizontalDragGestureRecognizer(router: Pointerer.instance.pointerRouter, gestureArena: Pointerer.instance.gestureArena)
..onStart = _handleDragStart ..onStart = _handleDragStart
..onUpdate = _handleDragUpdate ..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd; ..onEnd = _handleDragEnd;
......
...@@ -29,7 +29,7 @@ abstract class RenderToggleable extends RenderConstrainedBox { ...@@ -29,7 +29,7 @@ abstract class RenderToggleable extends RenderConstrainedBox {
assert(value != null); assert(value != null);
assert(activeColor != null); assert(activeColor != null);
assert(inactiveColor != null); assert(inactiveColor != null);
_tap = new TapGestureRecognizer(router: FlutterBinding.instance.pointerRouter) _tap = new TapGestureRecognizer(router: Pointerer.instance.pointerRouter, gestureArena: Pointerer.instance.gestureArena)
..onTapDown = _handleTapDown ..onTapDown = _handleTapDown
..onTap = _handleTap ..onTap = _handleTap
..onTapUp = _handleTapUp ..onTapUp = _handleTapUp
......
...@@ -420,6 +420,8 @@ void paintImage({ ...@@ -420,6 +420,8 @@ void paintImage({
double alignX, double alignX,
double alignY double alignY
}) { }) {
assert(canvas != null);
assert(image != null);
Size outputSize = rect.size; Size outputSize = rect.size;
Size inputSize = new Size(image.width.toDouble(), image.height.toDouble()); Size inputSize = new Size(image.width.toDouble(), image.height.toDouble());
Offset sliceBorder; Offset sliceBorder;
......
...@@ -220,7 +220,7 @@ class RenderAutoLayout extends RenderBox ...@@ -220,7 +220,7 @@ class RenderAutoLayout extends RenderBox
// only indicates that the value has been flushed to the variable. // only indicates that the value has been flushed to the variable.
} }
bool hitTestChildren(HitTestResult result, {Point position}) { bool hitTestChildren(HitTestResult result, { Point position }) {
return defaultHitTestChildren(result, position: position); return defaultHitTestChildren(result, position: position);
} }
......
...@@ -11,12 +11,11 @@ import 'package:flutter/scheduler.dart'; ...@@ -11,12 +11,11 @@ import 'package:flutter/scheduler.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
import 'debug.dart'; import 'debug.dart';
import 'hit_test.dart';
import 'layer.dart'; import 'layer.dart';
import 'node.dart'; import 'node.dart';
export 'layer.dart'; export 'layer.dart';
export 'hit_test.dart'; export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
typedef ui.Shader ShaderCallback(Rect bounds); typedef ui.Shader ShaderCallback(Rect bounds);
...@@ -551,7 +550,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -551,7 +550,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert(parent == this.parent); assert(parent == this.parent);
} else { } else {
_nodesNeedingLayout.add(this); _nodesNeedingLayout.add(this);
scheduler.ensureVisualUpdate(); Scheduler.instance.ensureVisualUpdate();
} }
} }
...@@ -916,7 +915,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -916,7 +915,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// ourselves without involving any other nodes. // ourselves without involving any other nodes.
assert(_layer != null); assert(_layer != null);
_nodesNeedingPaint.add(this); _nodesNeedingPaint.add(this);
scheduler.ensureVisualUpdate(); Scheduler.instance.ensureVisualUpdate();
} else if (parent is RenderObject) { } else if (parent is RenderObject) {
// We don't have our own layer; one of our ancestors will take // We don't have our own layer; one of our ancestors will take
// care of updating the layer we're in and when they do that // care of updating the layer we're in and when they do that
...@@ -930,7 +929,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -930,7 +929,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// then we have to paint ourselves, since nobody else can paint // then we have to paint ourselves, since nobody else can paint
// us. We don't add ourselves to _nodesNeedingPaint in this // us. We don't add ourselves to _nodesNeedingPaint in this
// case, because the root is always told to paint regardless. // case, because the root is always told to paint regardless.
scheduler.ensureVisualUpdate(); Scheduler.instance.ensureVisualUpdate();
} }
} }
......
...@@ -73,7 +73,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -73,7 +73,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
void scheduleInitialFrame() { void scheduleInitialFrame() {
scheduleInitialLayout(); scheduleInitialLayout();
scheduleInitialPaint(new TransformLayer(transform: _logicalToDeviceTransform)); scheduleInitialPaint(new TransformLayer(transform: _logicalToDeviceTransform));
scheduler.ensureVisualUpdate(); Scheduler.instance.ensureVisualUpdate();
} }
// We never call layout() on this class, so this should never get // We never call layout() on this class, so this should never get
......
...@@ -7,6 +7,7 @@ import 'dart:developer'; ...@@ -7,6 +7,7 @@ import 'dart:developer';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:collection/priority_queue.dart'; import 'package:collection/priority_queue.dart';
import 'package:flutter/services.dart';
/// Slows down animations by this factor to help in development. /// Slows down animations by this factor to help in development.
double timeDilation = 1.0; double timeDilation = 1.0;
...@@ -80,12 +81,18 @@ class Priority { ...@@ -80,12 +81,18 @@ class Priority {
/// the task should be run. /// the task should be run.
/// ///
/// Tasks always run in the idle time after a frame has been committed. /// Tasks always run in the idle time after a frame has been committed.
class Scheduler { abstract class Scheduler extends BindingBase {
/// Requires clients to use the [scheduler] singleton /// Requires clients to use the [scheduler] singleton
Scheduler._() {
void initInstances() {
super.initInstances();
_instance = this;
ui.window.onBeginFrame = handleBeginFrame; ui.window.onBeginFrame = handleBeginFrame;
} }
static Scheduler _instance;
static Scheduler get instance => _instance;
SchedulingStrategy schedulingStrategy = new DefaultSchedulingStrategy(); SchedulingStrategy schedulingStrategy = new DefaultSchedulingStrategy();
final PriorityQueue _taskQueue = new HeapPriorityQueue<_TaskEntry>( final PriorityQueue _taskQueue = new HeapPriorityQueue<_TaskEntry>(
...@@ -120,7 +127,7 @@ class Scheduler { ...@@ -120,7 +127,7 @@ class Scheduler {
if (_taskQueue.isEmpty) if (_taskQueue.isEmpty)
return; return;
_TaskEntry entry = _taskQueue.first; _TaskEntry entry = _taskQueue.first;
if (schedulingStrategy.shouldRunTaskWithPriority(entry.priority)) { if (schedulingStrategy.shouldRunTaskWithPriority(priority: entry.priority, scheduler: this)) {
try { try {
(_taskQueue.removeFirst().task)(); (_taskQueue.removeFirst().task)();
} finally { } finally {
...@@ -295,17 +302,15 @@ class Scheduler { ...@@ -295,17 +302,15 @@ class Scheduler {
} }
} }
final Scheduler scheduler = new Scheduler._();
abstract class SchedulingStrategy { abstract class SchedulingStrategy {
bool shouldRunTaskWithPriority(int priority); bool shouldRunTaskWithPriority({ int priority, Scheduler scheduler });
} }
class DefaultSchedulingStrategy implements SchedulingStrategy { class DefaultSchedulingStrategy implements SchedulingStrategy {
// TODO(floitsch): for now we only expose the priority. It might be // TODO(floitsch): for now we only expose the priority. It might be
// interesting to provide more info (like, how long the task ran the last // interesting to provide more info (like, how long the task ran the last
// time). // time).
bool shouldRunTaskWithPriority(int priority) { bool shouldRunTaskWithPriority({ int priority, Scheduler scheduler }) {
if (scheduler.transientCallbackCount > 0) if (scheduler.transientCallbackCount > 0)
return priority >= Priority.animation._value; return priority >= Priority.animation._value;
return true; return true;
......
...@@ -100,7 +100,8 @@ class MojoAssetBundle extends AssetBundle { ...@@ -100,7 +100,8 @@ class MojoAssetBundle extends AssetBundle {
AssetBundle _initRootBundle() { AssetBundle _initRootBundle() {
try { try {
AssetBundleProxy bundle = new AssetBundleProxy.fromHandle( AssetBundleProxy bundle = new AssetBundleProxy.fromHandle(
new core.MojoHandle(internals.takeRootBundleHandle())); new core.MojoHandle(internals.takeRootBundleHandle())
);
return new MojoAssetBundle(bundle); return new MojoAssetBundle(bundle);
} catch (e) { } catch (e) {
return null; return null;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Base class for mixins that provide singleton services (also known as
/// "bindings").
///
/// To use this class in a mixin, inherit from it and implement
/// [initInstances()]. The mixin is guaranteed to only be constructed once in
/// the lifetime of the app (more precisely, it will assert if constructed twice
/// in checked mode).
abstract class BindingBase {
BindingBase() {
assert(!_debugInitialized);
initInstances();
assert(_debugInitialized);
}
static bool _debugInitialized = false;
/// The initialization method. Subclasses override this method to hook into
/// the platform and otherwise configure their services. Subclasses must call
/// "super.initInstances()".
///
/// By convention, if the service is to be provided as a singleton, it should
/// be exposed as `MixinClassName.instance`, a static getter that returns
/// `MixinClassName._instance`, a static field that is set by
/// `initInstances()`.
void initInstances() {
assert(() { _debugInitialized = true; return true; });
}
}
...@@ -2,35 +2,82 @@ ...@@ -2,35 +2,82 @@
// 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' as ui;
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'framework.dart'; import 'framework.dart';
/// The glue that binds the widget framework to the Flutter engine. class BindingObserver {
class WidgetFlutterBinding extends FlutterBinding { bool didPopRoute() => false;
void didChangeSize(Size size) { }
void didChangeLocale(ui.Locale locale) { }
}
WidgetFlutterBinding() { /// A concrete binding for applications based on the Widgets framework.
BuildableElement.scheduleBuildFor = scheduleBuildFor; /// This is the glue that binds the framework to the Flutter engine.
class WidgetFlutterBinding extends BindingBase with Scheduler, Pointerer, Renderer {
WidgetFlutterBinding._();
/// Creates and initializes the WidgetFlutterBinding. This constructor is
/// idempotent; calling it a second time will just return the
/// previously-created instance.
static WidgetFlutterBinding ensureInitialized() {
if (_instance == null)
new WidgetFlutterBinding._();
return _instance;
} }
/// Ensures that there is a FlutterBinding object instantiated. initInstances() {
static void ensureInitialized() { super.initInstances();
if (FlutterBinding.instance == null) _instance = this;
new WidgetFlutterBinding(); BuildableElement.scheduleBuildFor = scheduleBuildFor;
assert(FlutterBinding.instance is WidgetFlutterBinding); ui.window.onLocaleChanged = handleLocaleChanged;
ui.window.onPopRoute = handlePopRoute;
} }
/// The one static instance of this class. /// The one static instance of this class.
/// ///
/// Only valid after ensureInitialized() (or the WidgetFlutterBinding /// Only valid after the WidgetFlutterBinding constructor) has been called.
/// constructor) has been called. If another FlutterBinding subclass is /// Only one binding class can be instantiated per process. If another
/// instantiated before this one (e.g. bindings from other frameworks based on /// BindingBase implementation has been instantiated before this one (e.g.
/// the Flutter "rendering" library), then WidgetFlutterBinding.instance will /// bindings from other frameworks based on the Flutter "rendering" library),
/// not be valid (and will throw in checked mode). /// then WidgetFlutterBinding.instance will not be valid (and will throw in
static WidgetFlutterBinding get instance => FlutterBinding.instance; /// checked mode).
static WidgetFlutterBinding _instance;
static WidgetFlutterBinding get instance => _instance;
final List<BindingObserver> _observers = new List<BindingObserver>();
void addObserver(BindingObserver observer) => _observers.add(observer);
bool removeObserver(BindingObserver observer) => _observers.remove(observer);
void handleMetricsChanged() {
super.handleMetricsChanged();
for (BindingObserver observer in _observers)
observer.didChangeSize(ui.window.size);
}
void handleLocaleChanged() {
dispatchLocaleChanged(ui.window.locale);
}
void dispatchLocaleChanged(ui.Locale locale) {
for (BindingObserver observer in _observers)
observer.didChangeLocale(locale);
}
void handlePopRoute() {
for (BindingObserver observer in _observers) {
if (observer.didPopRoute())
break;
}
}
void beginFrame() { void beginFrame() {
buildDirtyElements(); buildDirtyElements();
...@@ -46,7 +93,7 @@ class WidgetFlutterBinding extends FlutterBinding { ...@@ -46,7 +93,7 @@ class WidgetFlutterBinding extends FlutterBinding {
assert(!_dirtyElements.contains(element)); assert(!_dirtyElements.contains(element));
assert(element.dirty); assert(element.dirty);
if (_dirtyElements.isEmpty) if (_dirtyElements.isEmpty)
scheduler.ensureVisualUpdate(); ensureVisualUpdate();
_dirtyElements.add(element); _dirtyElements.add(element);
} }
...@@ -93,8 +140,7 @@ class WidgetFlutterBinding extends FlutterBinding { ...@@ -93,8 +140,7 @@ class WidgetFlutterBinding extends FlutterBinding {
/// Inflate the given widget and attach it to the screen. /// Inflate the given widget and attach it to the screen.
void runApp(Widget app) { void runApp(Widget app) {
WidgetFlutterBinding.ensureInitialized(); WidgetFlutterBinding.ensureInitialized()._runApp(app);
WidgetFlutterBinding.instance._runApp(app);
} }
/// Print a string representation of the currently running app. /// Print a string representation of the currently running app.
...@@ -157,7 +203,7 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectEl ...@@ -157,7 +203,7 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectEl
Element _child; Element _child;
static const _rootChild = const Object(); static const _rootChildSlot = const Object();
void visitChildren(ElementVisitor visitor) { void visitChildren(ElementVisitor visitor) {
if (_child != null) if (_child != null)
...@@ -167,19 +213,19 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectEl ...@@ -167,19 +213,19 @@ class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectEl
void mount(Element parent, dynamic newSlot) { void mount(Element parent, dynamic newSlot) {
assert(parent == null); assert(parent == null);
super.mount(parent, newSlot); super.mount(parent, newSlot);
_child = updateChild(_child, widget.child, _rootChild); _child = updateChild(_child, widget.child, _rootChildSlot);
} }
void update(RenderObjectToWidgetAdapter<T> newWidget) { void update(RenderObjectToWidgetAdapter<T> newWidget) {
super.update(newWidget); super.update(newWidget);
assert(widget == newWidget); assert(widget == newWidget);
_child = updateChild(_child, widget.child, _rootChild); _child = updateChild(_child, widget.child, _rootChildSlot);
} }
RenderObjectWithChildMixin<T> get renderObject => super.renderObject; RenderObjectWithChildMixin<T> get renderObject => super.renderObject;
void insertChildRenderObject(RenderObject child, dynamic slot) { void insertChildRenderObject(RenderObject child, dynamic slot) {
assert(slot == _rootChild); assert(slot == _rootChildSlot);
renderObject.child = child; renderObject.child = child;
} }
......
...@@ -96,6 +96,7 @@ class Draggable<T> extends DraggableBase<T> { ...@@ -96,6 +96,7 @@ class Draggable<T> extends DraggableBase<T> {
GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) { GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) {
return new MultiTapGestureRecognizer( return new MultiTapGestureRecognizer(
router: router, router: router,
gestureArena: Pointerer.instance.gestureArena,
onTapDown: starter onTapDown: starter
); );
} }
...@@ -122,6 +123,7 @@ class LongPressDraggable<T> extends DraggableBase<T> { ...@@ -122,6 +123,7 @@ class LongPressDraggable<T> extends DraggableBase<T> {
GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) { GestureRecognizer createRecognizer(PointerRouter router, DragStartCallback starter) {
return new MultiTapGestureRecognizer( return new MultiTapGestureRecognizer(
router: router, router: router,
gestureArena: Pointerer.instance.gestureArena,
longTapDelay: kLongPressTimeout, longTapDelay: kLongPressTimeout,
onLongTapDown: (Point position, int pointer) { onLongTapDown: (Point position, int pointer) {
userFeedback.performHapticFeedback(HapticFeedbackType.VIRTUAL_KEY); userFeedback.performHapticFeedback(HapticFeedbackType.VIRTUAL_KEY);
...@@ -133,7 +135,7 @@ class LongPressDraggable<T> extends DraggableBase<T> { ...@@ -133,7 +135,7 @@ class LongPressDraggable<T> extends DraggableBase<T> {
class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArenaMember { class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArenaMember {
PointerRouter get router => FlutterBinding.instance.pointerRouter; PointerRouter get router => Pointerer.instance.pointerRouter;
void initState() { void initState() {
super.initState(); super.initState();
...@@ -144,7 +146,7 @@ class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArena ...@@ -144,7 +146,7 @@ class _DraggableState<T> extends State<DraggableBase<T>> implements GestureArena
Map<int, GestureArenaEntry> _activePointers = <int, GestureArenaEntry>{}; Map<int, GestureArenaEntry> _activePointers = <int, GestureArenaEntry>{};
void _routePointer(PointerEvent event) { void _routePointer(PointerEvent event) {
_activePointers[event.pointer] = GestureArena.instance.add(event.pointer, this); _activePointers[event.pointer] = Pointerer.instance.gestureArena.add(event.pointer, this);
_recognizer.addPointer(event); _recognizer.addPointer(event);
} }
...@@ -315,7 +317,8 @@ class _DragAvatar<T> { ...@@ -315,7 +317,8 @@ class _DragAvatar<T> {
void update(Point globalPosition) { void update(Point globalPosition) {
_lastOffset = globalPosition - dragStartPoint; _lastOffset = globalPosition - dragStartPoint;
_entry.markNeedsBuild(); _entry.markNeedsBuild();
HitTestResult result = WidgetFlutterBinding.instance.hitTest(globalPosition + feedbackOffset); HitTestResult result = new HitTestResult();
WidgetFlutterBinding.instance.hitTest(result, globalPosition + feedbackOffset);
_DragTargetState target = _getDragTarget(result.path); _DragTargetState target = _getDragTarget(result.path);
if (target == _activeTarget) if (target == _activeTarget)
return; return;
......
...@@ -121,7 +121,7 @@ class GestureDetector extends StatefulComponent { ...@@ -121,7 +121,7 @@ class GestureDetector extends StatefulComponent {
} }
class _GestureDetectorState extends State<GestureDetector> { class _GestureDetectorState extends State<GestureDetector> {
PointerRouter get _router => FlutterBinding.instance.pointerRouter; PointerRouter get _router => Pointerer.instance.pointerRouter;
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
DoubleTapGestureRecognizer _doubleTap; DoubleTapGestureRecognizer _doubleTap;
...@@ -165,7 +165,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -165,7 +165,7 @@ class _GestureDetectorState extends State<GestureDetector> {
if (config.onTapDown == null && config.onTapUp == null && config.onTap == null && config.onTapCancel == null) { if (config.onTapDown == null && config.onTapUp == null && config.onTap == null && config.onTapCancel == null) {
_tap = _ensureDisposed(_tap); _tap = _ensureDisposed(_tap);
} else { } else {
_tap ??= new TapGestureRecognizer(router: _router); _tap ??= new TapGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_tap _tap
..onTapDown = config.onTapDown ..onTapDown = config.onTapDown
..onTapUp = config.onTapUp ..onTapUp = config.onTapUp
...@@ -178,7 +178,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -178,7 +178,7 @@ class _GestureDetectorState extends State<GestureDetector> {
if (config.onDoubleTap == null) { if (config.onDoubleTap == null) {
_doubleTap = _ensureDisposed(_doubleTap); _doubleTap = _ensureDisposed(_doubleTap);
} else { } else {
_doubleTap ??= new DoubleTapGestureRecognizer(router: _router); _doubleTap ??= new DoubleTapGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_doubleTap.onDoubleTap = config.onDoubleTap; _doubleTap.onDoubleTap = config.onDoubleTap;
} }
} }
...@@ -187,7 +187,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -187,7 +187,7 @@ class _GestureDetectorState extends State<GestureDetector> {
if (config.onLongPress == null) { if (config.onLongPress == null) {
_longPress = _ensureDisposed(_longPress); _longPress = _ensureDisposed(_longPress);
} else { } else {
_longPress ??= new LongPressGestureRecognizer(router: _router); _longPress ??= new LongPressGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_longPress.onLongPress = config.onLongPress; _longPress.onLongPress = config.onLongPress;
} }
} }
...@@ -196,7 +196,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -196,7 +196,7 @@ class _GestureDetectorState extends State<GestureDetector> {
if (config.onVerticalDragStart == null && config.onVerticalDragUpdate == null && config.onVerticalDragEnd == null) { if (config.onVerticalDragStart == null && config.onVerticalDragUpdate == null && config.onVerticalDragEnd == null) {
_verticalDrag = _ensureDisposed(_verticalDrag); _verticalDrag = _ensureDisposed(_verticalDrag);
} else { } else {
_verticalDrag ??= new VerticalDragGestureRecognizer(router: _router); _verticalDrag ??= new VerticalDragGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_verticalDrag _verticalDrag
..onStart = config.onVerticalDragStart ..onStart = config.onVerticalDragStart
..onUpdate = config.onVerticalDragUpdate ..onUpdate = config.onVerticalDragUpdate
...@@ -208,7 +208,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -208,7 +208,7 @@ class _GestureDetectorState extends State<GestureDetector> {
if (config.onHorizontalDragStart == null && config.onHorizontalDragUpdate == null && config.onHorizontalDragEnd == null) { if (config.onHorizontalDragStart == null && config.onHorizontalDragUpdate == null && config.onHorizontalDragEnd == null) {
_horizontalDrag = _ensureDisposed(_horizontalDrag); _horizontalDrag = _ensureDisposed(_horizontalDrag);
} else { } else {
_horizontalDrag ??= new HorizontalDragGestureRecognizer(router: _router); _horizontalDrag ??= new HorizontalDragGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_horizontalDrag _horizontalDrag
..onStart = config.onHorizontalDragStart ..onStart = config.onHorizontalDragStart
..onUpdate = config.onHorizontalDragUpdate ..onUpdate = config.onHorizontalDragUpdate
...@@ -221,7 +221,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -221,7 +221,7 @@ class _GestureDetectorState extends State<GestureDetector> {
_pan = _ensureDisposed(_pan); _pan = _ensureDisposed(_pan);
} else { } else {
assert(_scale == null); // Scale is a superset of pan; just use scale assert(_scale == null); // Scale is a superset of pan; just use scale
_pan ??= new PanGestureRecognizer(router: _router); _pan ??= new PanGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_pan _pan
..onStart = config.onPanStart ..onStart = config.onPanStart
..onUpdate = config.onPanUpdate ..onUpdate = config.onPanUpdate
...@@ -234,7 +234,7 @@ class _GestureDetectorState extends State<GestureDetector> { ...@@ -234,7 +234,7 @@ class _GestureDetectorState extends State<GestureDetector> {
_scale = _ensureDisposed(_scale); _scale = _ensureDisposed(_scale);
} else { } else {
assert(_pan == null); // Scale is a superset of pan; just use scale assert(_pan == null); // Scale is a superset of pan; just use scale
_scale ??= new ScaleGestureRecognizer(router: _router); _scale ??= new ScaleGestureRecognizer(router: _router, gestureArena: Pointerer.instance.gestureArena);
_scale _scale
..onStart = config.onScaleStart ..onStart = config.onScaleStart
..onUpdate = config.onScaleUpdate ..onUpdate = config.onScaleUpdate
......
...@@ -455,7 +455,7 @@ class HeroController extends NavigatorObserver { ...@@ -455,7 +455,7 @@ class HeroController extends NavigatorObserver {
void _checkForHeroQuest() { void _checkForHeroQuest() {
if (_from != null && _to != null && _from != _to) { if (_from != null && _to != null && _from != _to) {
_to.offstage = _to.performance.status != PerformanceStatus.completed; _to.offstage = _to.performance.status != PerformanceStatus.completed;
scheduler.addPostFrameCallback(_updateQuest); Scheduler.instance.addPostFrameCallback(_updateQuest);
} }
} }
......
...@@ -17,13 +17,15 @@ typedef Point SizeToPointFunction(Size size); ...@@ -17,13 +17,15 @@ typedef Point SizeToPointFunction(Size size);
class WidgetTester { class WidgetTester {
WidgetTester._(FakeAsync async) WidgetTester._(FakeAsync async)
: async = async, : binding = WidgetFlutterBinding.ensureInitialized(),
async = async,
clock = async.getClock(new DateTime.utc(2015, 1, 1)) { clock = async.getClock(new DateTime.utc(2015, 1, 1)) {
timeDilation = 1.0; timeDilation = 1.0;
ui.window.onBeginFrame = null; ui.window.onBeginFrame = null;
runApp(new ErrorWidget()); // flush out the last build entirely runApp(new ErrorWidget()); // flush out the last build entirely
} }
final WidgetFlutterBinding binding;
final FakeAsync async; final FakeAsync async;
final Clock clock; final Clock clock;
...@@ -34,15 +36,16 @@ class WidgetTester { ...@@ -34,15 +36,16 @@ class WidgetTester {
void setLocale(String languageCode, String countryCode) { void setLocale(String languageCode, String countryCode) {
ui.Locale locale = new ui.Locale(languageCode, countryCode); ui.Locale locale = new ui.Locale(languageCode, countryCode);
FlutterBinding.instance.dispatchLocaleChanged(locale); binding.dispatchLocaleChanged(locale);
async.flushMicrotasks(); async.flushMicrotasks();
} }
void pump([ Duration duration ]) { void pump([ Duration duration ]) {
if (duration != null) if (duration != null)
async.elapse(duration); async.elapse(duration);
scheduler.handleBeginFrame(new Duration( binding.handleBeginFrame(new Duration(
milliseconds: clock.now().millisecondsSinceEpoch)); milliseconds: clock.now().millisecondsSinceEpoch)
);
async.flushMicrotasks(); async.flushMicrotasks();
} }
...@@ -58,7 +61,7 @@ class WidgetTester { ...@@ -58,7 +61,7 @@ class WidgetTester {
} }
return result; return result;
} }
List<Layer> get layers => _layers(FlutterBinding.instance.renderView.layer); List<Layer> get layers => _layers(binding.renderView.layer);
void walkElements(ElementVisitor visitor) { void walkElements(ElementVisitor visitor) {
...@@ -66,7 +69,7 @@ class WidgetTester { ...@@ -66,7 +69,7 @@ class WidgetTester {
visitor(element); visitor(element);
element.visitChildren(walk); element.visitChildren(walk);
} }
WidgetFlutterBinding.instance.renderViewElement.visitChildren(walk); binding.renderViewElement.visitChildren(walk);
} }
Element findElement(bool predicate(Element element)) { Element findElement(bool predicate(Element element)) {
...@@ -184,10 +187,14 @@ class WidgetTester { ...@@ -184,10 +187,14 @@ class WidgetTester {
_dispatchEvent(event, _hitTest(location)); _dispatchEvent(event, _hitTest(location));
} }
HitTestResult _hitTest(Point location) => WidgetFlutterBinding.instance.hitTest(location); HitTestResult _hitTest(Point location) {
HitTestResult result = new HitTestResult();
binding.hitTest(result, location);
return result;
}
void _dispatchEvent(PointerEvent event, HitTestResult result) { void _dispatchEvent(PointerEvent event, HitTestResult result) {
WidgetFlutterBinding.instance.dispatchEvent(event, result); binding.dispatchEvent(event, result);
} }
} }
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:ui' show Rect, Color, Paint; import 'dart:ui' show Rect, Color, Paint;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui'; import 'dart:ui';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui'; import 'dart:ui';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui'; import 'dart:ui';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:test/test.dart'; import 'package:test/test.dart';
import '../rendering/rendering_tester.dart'; import '../rendering/rendering_tester.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:quiver/testing/async.dart'; import 'package:quiver/testing/async.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -15,7 +19,11 @@ const PointerUpEvent up = const PointerUpEvent( ...@@ -15,7 +19,11 @@ const PointerUpEvent up = const PointerUpEvent(
void main() { void main() {
test('Should recognize long press', () { test('Should recognize long press', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool longPressRecognized = false; bool longPressRecognized = false;
longPress.onLongPress = () { longPress.onLongPress = () {
...@@ -24,7 +32,7 @@ void main() { ...@@ -24,7 +32,7 @@ void main() {
new FakeAsync().run((FakeAsync async) { new FakeAsync().run((FakeAsync async) {
longPress.addPointer(down); longPress.addPointer(down);
GestureArena.instance.close(5); gestureArena.close(5);
expect(longPressRecognized, isFalse); expect(longPressRecognized, isFalse);
router.route(down); router.route(down);
expect(longPressRecognized, isFalse); expect(longPressRecognized, isFalse);
...@@ -39,7 +47,11 @@ void main() { ...@@ -39,7 +47,11 @@ void main() {
test('Up cancels long press', () { test('Up cancels long press', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool longPressRecognized = false; bool longPressRecognized = false;
longPress.onLongPress = () { longPress.onLongPress = () {
...@@ -48,7 +60,7 @@ void main() { ...@@ -48,7 +60,7 @@ void main() {
new FakeAsync().run((FakeAsync async) { new FakeAsync().run((FakeAsync async) {
longPress.addPointer(down); longPress.addPointer(down);
GestureArena.instance.close(5); gestureArena.close(5);
expect(longPressRecognized, isFalse); expect(longPressRecognized, isFalse);
router.route(down); router.route(down);
expect(longPressRecognized, isFalse); expect(longPressRecognized, isFalse);
...@@ -65,8 +77,15 @@ void main() { ...@@ -65,8 +77,15 @@ void main() {
test('Should recognize both tap down and long press', () { test('Should recognize both tap down and long press', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(router: router); LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(
router: router,
gestureArena: gestureArena
);
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool tapDownRecognized = false; bool tapDownRecognized = false;
tap.onTapDown = (_) { tap.onTapDown = (_) {
...@@ -81,7 +100,7 @@ void main() { ...@@ -81,7 +100,7 @@ void main() {
new FakeAsync().run((FakeAsync async) { new FakeAsync().run((FakeAsync async) {
tap.addPointer(down); tap.addPointer(down);
longPress.addPointer(down); longPress.addPointer(down);
GestureArena.instance.close(5); gestureArena.close(5);
expect(tapDownRecognized, isFalse); expect(tapDownRecognized, isFalse);
expect(longPressRecognized, isFalse); expect(longPressRecognized, isFalse);
router.route(down); router.route(down);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -5,8 +9,15 @@ import 'package:test/test.dart'; ...@@ -5,8 +9,15 @@ import 'package:test/test.dart';
void main() { void main() {
test('Should recognize scale gestures', () { test('Should recognize scale gestures', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
ScaleGestureRecognizer scale = new ScaleGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); ScaleGestureRecognizer scale = new ScaleGestureRecognizer(
router: router,
gestureArena: gestureArena
);
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool didStartScale = false; bool didStartScale = false;
Point updatedFocalPoint; Point updatedFocalPoint;
...@@ -37,7 +48,7 @@ void main() { ...@@ -37,7 +48,7 @@ void main() {
scale.addPointer(down); scale.addPointer(down);
tap.addPointer(down); tap.addPointer(down);
GestureArena.instance.close(1); gestureArena.close(1);
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedScale, isNull); expect(updatedScale, isNull);
expect(updatedFocalPoint, isNull); expect(updatedFocalPoint, isNull);
...@@ -67,7 +78,7 @@ void main() { ...@@ -67,7 +78,7 @@ void main() {
PointerDownEvent down2 = pointer2.down(const Point(10.0, 20.0)); PointerDownEvent down2 = pointer2.down(const Point(10.0, 20.0));
scale.addPointer(down2); scale.addPointer(down2);
tap.addPointer(down2); tap.addPointer(down2);
GestureArena.instance.close(2); gestureArena.close(2);
router.route(down2); router.route(down2);
expect(didEndScale, isTrue); expect(didEndScale, isTrue);
...@@ -100,7 +111,7 @@ void main() { ...@@ -100,7 +111,7 @@ void main() {
PointerDownEvent down3 = pointer3.down(const Point(25.0, 35.0)); PointerDownEvent down3 = pointer3.down(const Point(25.0, 35.0));
scale.addPointer(down3); scale.addPointer(down3);
tap.addPointer(down3); tap.addPointer(down3);
GestureArena.instance.close(3); gestureArena.close(3);
router.route(down3); router.route(down3);
expect(didEndScale, isTrue); expect(didEndScale, isTrue);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -5,8 +9,15 @@ import 'package:test/test.dart'; ...@@ -5,8 +9,15 @@ import 'package:test/test.dart';
void main() { void main() {
test('Should recognize pan', () { test('Should recognize pan', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
PanGestureRecognizer pan = new PanGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); PanGestureRecognizer pan = new PanGestureRecognizer(
router: router,
gestureArena: gestureArena
);
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool didStartPan = false; bool didStartPan = false;
pan.onStart = (_) { pan.onStart = (_) {
...@@ -32,7 +43,7 @@ void main() { ...@@ -32,7 +43,7 @@ void main() {
PointerDownEvent down = pointer.down(const Point(10.0, 10.0)); PointerDownEvent down = pointer.down(const Point(10.0, 10.0));
pan.addPointer(down); pan.addPointer(down);
tap.addPointer(down); tap.addPointer(down);
GestureArena.instance.close(5); gestureArena.close(5);
expect(didStartPan, isFalse); expect(didStartPan, isFalse);
expect(updatedScrollDelta, isNull); expect(updatedScrollDelta, isNull);
expect(didEndPan, isFalse); expect(didEndPan, isFalse);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:quiver/testing/async.dart'; import 'package:quiver/testing/async.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -49,7 +53,11 @@ void main() { ...@@ -49,7 +53,11 @@ void main() {
test('Should recognize tap', () { test('Should recognize tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool tapRecognized = false; bool tapRecognized = false;
tap.onTap = () { tap.onTap = () {
...@@ -57,14 +65,14 @@ void main() { ...@@ -57,14 +65,14 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(down1); router.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(up1); router.route(up1);
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
tap.dispose(); tap.dispose();
...@@ -72,7 +80,11 @@ void main() { ...@@ -72,7 +80,11 @@ void main() {
test('No duplicate tap events', () { test('No duplicate tap events', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
int tapsRecognized = 0; int tapsRecognized = 0;
tap.onTap = () { tap.onTap = () {
...@@ -80,25 +92,25 @@ void main() { ...@@ -80,25 +92,25 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
router.route(down1); router.route(down1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
router.route(up1); router.route(up1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
tap.addPointer(down1); tap.addPointer(down1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
router.route(down1); router.route(down1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
router.route(up1); router.route(up1);
expect(tapsRecognized, 2); expect(tapsRecognized, 2);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapsRecognized, 2); expect(tapsRecognized, 2);
tap.dispose(); tap.dispose();
...@@ -106,7 +118,11 @@ void main() { ...@@ -106,7 +118,11 @@ void main() {
test('Should not recognize two overlapping taps', () { test('Should not recognize two overlapping taps', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
int tapsRecognized = 0; int tapsRecognized = 0;
tap.onTap = () { tap.onTap = () {
...@@ -114,13 +130,13 @@ void main() { ...@@ -114,13 +130,13 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
router.route(down1); router.route(down1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
tap.addPointer(down2); tap.addPointer(down2);
GestureArena.instance.close(2); gestureArena.close(2);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
router.route(down1); router.route(down1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
...@@ -128,12 +144,12 @@ void main() { ...@@ -128,12 +144,12 @@ void main() {
router.route(up1); router.route(up1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
router.route(up2); router.route(up2);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureArena.instance.sweep(2); gestureArena.sweep(2);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
tap.dispose(); tap.dispose();
...@@ -141,7 +157,11 @@ void main() { ...@@ -141,7 +157,11 @@ void main() {
test('Distance cancels tap', () { test('Distance cancels tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool tapRecognized = false; bool tapRecognized = false;
tap.onTap = () { tap.onTap = () {
...@@ -153,7 +173,7 @@ void main() { ...@@ -153,7 +173,7 @@ void main() {
}; };
tap.addPointer(down3); tap.addPointer(down3);
GestureArena.instance.close(3); gestureArena.close(3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isFalse); expect(tapCanceled, isFalse);
router.route(down3); router.route(down3);
...@@ -166,7 +186,7 @@ void main() { ...@@ -166,7 +186,7 @@ void main() {
router.route(up3); router.route(up3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isTrue); expect(tapCanceled, isTrue);
GestureArena.instance.sweep(3); gestureArena.sweep(3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isTrue); expect(tapCanceled, isTrue);
...@@ -175,7 +195,11 @@ void main() { ...@@ -175,7 +195,11 @@ void main() {
test('Timeout does not cancel tap', () { test('Timeout does not cancel tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool tapRecognized = false; bool tapRecognized = false;
tap.onTap = () { tap.onTap = () {
...@@ -184,7 +208,7 @@ void main() { ...@@ -184,7 +208,7 @@ void main() {
new FakeAsync().run((FakeAsync async) { new FakeAsync().run((FakeAsync async) {
tap.addPointer(down1); tap.addPointer(down1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(down1); router.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
...@@ -193,7 +217,7 @@ void main() { ...@@ -193,7 +217,7 @@ void main() {
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(up1); router.route(up1);
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
}); });
...@@ -202,7 +226,11 @@ void main() { ...@@ -202,7 +226,11 @@ void main() {
test('Should yield to other arena members', () { test('Should yield to other arena members', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool tapRecognized = false; bool tapRecognized = false;
tap.onTap = () { tap.onTap = () {
...@@ -211,16 +239,16 @@ void main() { ...@@ -211,16 +239,16 @@ void main() {
tap.addPointer(down1); tap.addPointer(down1);
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureArena.instance.add(1, member); GestureArenaEntry entry = gestureArena.add(1, member);
GestureArena.instance.hold(1); gestureArena.hold(1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(down1); router.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(up1); router.route(up1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
entry.resolve(GestureDisposition.accepted); entry.resolve(GestureDisposition.accepted);
...@@ -231,7 +259,11 @@ void main() { ...@@ -231,7 +259,11 @@ void main() {
test('Should trigger on release of held arena', () { test('Should trigger on release of held arena', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); GestureArena gestureArena = new GestureArena();
TapGestureRecognizer tap = new TapGestureRecognizer(
router: router,
gestureArena: gestureArena
);
bool tapRecognized = false; bool tapRecognized = false;
tap.onTap = () { tap.onTap = () {
...@@ -240,16 +272,16 @@ void main() { ...@@ -240,16 +272,16 @@ void main() {
tap.addPointer(down1); tap.addPointer(down1);
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureArena.instance.add(1, member); GestureArenaEntry entry = gestureArena.add(1, member);
GestureArena.instance.hold(1); gestureArena.hold(1);
GestureArena.instance.close(1); gestureArena.close(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(down1); router.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(up1); router.route(up1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureArena.instance.sweep(1); gestureArena.sweep(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
entry.resolve(GestureDisposition.rejected); entry.resolve(GestureDisposition.rejected);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
const List<PointerEvent> velocityEventData = const <PointerEvent>[ const List<PointerEvent> velocityEventData = const <PointerEvent>[
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'velocity_tracker_data.dart'; import 'velocity_tracker_data.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
const Size _kTestViewSize = const Size(800.0, 600.0); const Size _kTestViewSize = const Size(800.0, 600.0);
class TestRenderView extends RenderView { class TestRenderView extends RenderView {
TestRenderView() { TestRenderView() {
attach();
rootConstraints = new ViewConstraints(size: _kTestViewSize); rootConstraints = new ViewConstraints(size: _kTestViewSize);
}
void scheduleInitialFrame() {
scheduleInitialLayout(); scheduleInitialLayout();
scheduleInitialPaint(new TransformLayer(transform: new Matrix4.identity())); scheduleInitialPaint(new TransformLayer(transform: new Matrix4.identity()));
} }
...@@ -17,18 +25,37 @@ enum EnginePhase { ...@@ -17,18 +25,37 @@ enum EnginePhase {
composite composite
} }
RenderView _renderView; class TestRenderingFlutterBinding extends BindingBase with Scheduler, Renderer, Pointerer {
RenderView get renderView => _renderView; void initRenderView() {
if (renderView == null) {
renderView = new TestRenderView();
renderView.scheduleInitialFrame();
}
}
EnginePhase phase = EnginePhase.composite;
void beginFrame() {
RenderObject.flushLayout();
if (phase == EnginePhase.layout)
return;
renderer.renderView.updateCompositingBits();
RenderObject.flushPaint();
if (phase == EnginePhase.paint)
return;
renderer.renderView.compositeFrame();
}
}
TestRenderingFlutterBinding _renderer;
TestRenderingFlutterBinding get renderer => _renderer;
void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: EnginePhase.layout }) { void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: EnginePhase.layout }) {
assert(box != null); // if you want to just repump the last box, call pumpFrame(). assert(box != null); // if you want to just repump the last box, call pumpFrame().
if (renderView == null) _renderer ??= new TestRenderingFlutterBinding();
_renderView = new TestRenderView();
if (renderView.child != null)
renderView.child = null;
renderer.renderView.child = null;
if (constraints != null) { if (constraints != null) {
box = new RenderPositionedBox( box = new RenderPositionedBox(
child: new RenderConstrainedBox( child: new RenderConstrainedBox(
...@@ -37,21 +64,15 @@ void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: Engi ...@@ -37,21 +64,15 @@ void layout(RenderBox box, { BoxConstraints constraints, EnginePhase phase: Engi
) )
); );
} }
renderer.renderView.child = box;
renderView.child = box;
pumpFrame(phase: phase); pumpFrame(phase: phase);
} }
void pumpFrame({ EnginePhase phase: EnginePhase.layout }) { void pumpFrame({ EnginePhase phase: EnginePhase.layout }) {
RenderObject.flushLayout(); assert(renderer != null);
if (phase == EnginePhase.layout) renderer.phase = phase;
return; renderer.beginFrame();
renderView.updateCompositingBits();
RenderObject.flushPaint();
if (phase == EnginePhase.paint)
return;
renderView.compositeFrame();
} }
class TestCallbackPainter extends CustomPainter { class TestCallbackPainter extends CustomPainter {
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -26,11 +30,11 @@ void main() { ...@@ -26,11 +30,11 @@ void main() {
HitTestResult result; HitTestResult result;
result = new HitTestResult(); result = new HitTestResult();
renderView.hitTest(result, position: new Point(15.0, 0.0)); renderer.renderView.hitTest(result, position: new Point(15.0, 0.0));
expect(result.path.first.target.runtimeType, equals(TestRenderView)); expect(result.path.first.target.runtimeType, equals(TestRenderView));
result = new HitTestResult(); result = new HitTestResult();
renderView.hitTest(result, position: new Point(15.0, 15.0)); renderer.renderView.hitTest(result, position: new Point(15.0, 15.0));
expect(result.path.first.target, equals(green)); expect(result.path.first.target, equals(green));
}); });
} }
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
class TestSchedulerBinding extends BindingBase with Scheduler { }
void main() { void main() {
Scheduler scheduler = new TestSchedulerBinding();
test("Check for a time dilation being in effect", () { test("Check for a time dilation being in effect", () {
expect(timeDilation, equals(1.0)); expect(timeDilation, equals(1.0));
}); });
......
...@@ -2,43 +2,52 @@ ...@@ -2,43 +2,52 @@
// 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.
// This test is disabled because it triggers https://github.com/dart-lang/sdk/issues/25246
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
class TestSchedulerBinding extends BindingBase with Scheduler { }
class TestStrategy implements SchedulingStrategy { class TestStrategy implements SchedulingStrategy {
int allowedPriority = 10000; int allowedPriority = 10000;
bool shouldRunTaskWithPriority(int priority) { bool shouldRunTaskWithPriority({ int priority, Scheduler scheduler }) {
return priority >= allowedPriority; return priority >= allowedPriority;
} }
} }
void main() { void main() {
test("Tasks are executed in the right order", () { test("Tasks are executed in the right order", () {
var strategy = new TestStrategy(); Scheduler scheduler = new TestSchedulerBinding();
TestStrategy strategy = new TestStrategy();
scheduler.schedulingStrategy = strategy; scheduler.schedulingStrategy = strategy;
List input = [2, 23, 23, 11, 0, 80, 3]; List<int> input = <int>[2, 23, 23, 11, 0, 80, 3];
List executedTasks = []; List<int> executedTasks = <int>[];
void scheduleAddingTask(int x) { void scheduleAddingTask(int x) {
scheduler.scheduleTask(() { executedTasks.add(x); }, Priority.idle + x); scheduler.scheduleTask(() { executedTasks.add(x); }, Priority.idle + x);
} }
for (int x in input) { for (int x in input)
scheduleAddingTask(x); scheduleAddingTask(x);
}
strategy.allowedPriority = 100; strategy.allowedPriority = 100;
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback(); for (int i = 0; i < 3; i += 1)
scheduler.handleEventLoopCallback();
expect(executedTasks.isEmpty, isTrue); expect(executedTasks.isEmpty, isTrue);
strategy.allowedPriority = 50; strategy.allowedPriority = 50;
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback(); for (int i = 0; i < 3; i += 1)
scheduler.handleEventLoopCallback();
expect(executedTasks.length, equals(1)); expect(executedTasks.length, equals(1));
expect(executedTasks.single, equals(80)); expect(executedTasks.single, equals(80));
executedTasks.clear(); executedTasks.clear();
strategy.allowedPriority = 20; strategy.allowedPriority = 20;
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback(); for (int i = 0; i < 3; i += 1)
scheduler.handleEventLoopCallback();
expect(executedTasks.length, equals(2)); expect(executedTasks.length, equals(2));
expect(executedTasks[0], equals(23)); expect(executedTasks[0], equals(23));
expect(executedTasks[1], equals(23)); expect(executedTasks[1], equals(23));
...@@ -48,21 +57,24 @@ void main() { ...@@ -48,21 +57,24 @@ void main() {
scheduleAddingTask(19); scheduleAddingTask(19);
scheduleAddingTask(5); scheduleAddingTask(5);
scheduleAddingTask(97); scheduleAddingTask(97);
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback(); for (int i = 0; i < 3; i += 1)
scheduler.handleEventLoopCallback();
expect(executedTasks.length, equals(2)); expect(executedTasks.length, equals(2));
expect(executedTasks[0], equals(99)); expect(executedTasks[0], equals(99));
expect(executedTasks[1], equals(97)); expect(executedTasks[1], equals(97));
executedTasks.clear(); executedTasks.clear();
strategy.allowedPriority = 10; strategy.allowedPriority = 10;
for (int i = 0; i < 3; i++) scheduler.handleEventLoopCallback(); for (int i = 0; i < 3; i += 1)
scheduler.handleEventLoopCallback();
expect(executedTasks.length, equals(2)); expect(executedTasks.length, equals(2));
expect(executedTasks[0], equals(19)); expect(executedTasks[0], equals(19));
expect(executedTasks[1], equals(11)); expect(executedTasks[1], equals(11));
executedTasks.clear(); executedTasks.clear();
strategy.allowedPriority = 1; strategy.allowedPriority = 1;
for (int i = 0; i < 4; i++) scheduler.handleEventLoopCallback(); for (int i = 0; i < 4; i += 1)
scheduler.handleEventLoopCallback();
expect(executedTasks.length, equals(3)); expect(executedTasks.length, equals(3));
expect(executedTasks[0], equals(5)); expect(executedTasks[0], equals(5));
expect(executedTasks[1], equals(3)); expect(executedTasks[1], equals(3));
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -65,9 +64,9 @@ void main() { ...@@ -65,9 +64,9 @@ void main() {
) )
) )
); );
expect(scheduler.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
tester.pump(new Duration(seconds: 1)); tester.pump(new Duration(seconds: 1));
expect(scheduler.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget( tester.pumpWidget(
new AnimatedContainer( new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
...@@ -76,9 +75,9 @@ void main() { ...@@ -76,9 +75,9 @@ void main() {
) )
) )
); );
expect(scheduler.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
tester.pump(new Duration(seconds: 1)); tester.pump(new Duration(seconds: 1));
expect(scheduler.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget( tester.pumpWidget(
new AnimatedContainer( new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
...@@ -87,9 +86,9 @@ void main() { ...@@ -87,9 +86,9 @@ void main() {
) )
) )
); );
expect(scheduler.transientCallbackCount, 1); // this is the only time an animation should have started! expect(tester.binding.transientCallbackCount, 1); // this is the only time an animation should have started!
tester.pump(new Duration(seconds: 1)); tester.pump(new Duration(seconds: 1));
expect(scheduler.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
tester.pumpWidget( tester.pumpWidget(
new AnimatedContainer( new AnimatedContainer(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
...@@ -98,7 +97,7 @@ void main() { ...@@ -98,7 +97,7 @@ void main() {
) )
) )
); );
expect(scheduler.transientCallbackCount, 0); expect(tester.binding.transientCallbackCount, 0);
}); });
}); });
} }
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