Commit 7dad780f authored by Ian Hickson's avatar Ian Hickson

Merge pull request #946 from Hixie/pointerExceptions

Catch exceptions in pointer handling
parents 7ea5879e 4e23ecd6
......@@ -19,5 +19,6 @@ export 'src/services/image_cache.dart';
export 'src/services/image_decoder.dart';
export 'src/services/image_resource.dart';
export 'src/services/keyboard.dart';
export 'src/services/print.dart';
export 'src/services/service_registry.dart';
export 'src/services/shell.dart';
......@@ -16,6 +16,8 @@ import 'events.dart';
import 'hit_test.dart';
import 'pointer_router.dart';
typedef void GesturerExceptionHandler(PointerEvent event, HitTestTarget target, dynamic exception, StackTrace stack);
abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestable {
void initInstances() {
......@@ -76,11 +78,34 @@ abstract class Gesturer extends BindingBase implements HitTestTarget, HitTestabl
result.add(new HitTestEntry(this));
}
/// This callback is invoked whenever an exception is caught by the Gesturer
/// binding. The 'event' argument is the pointer event that was being routed.
/// The 'target' argument is the class whose handleEvent function threw the
/// exception. The 'exception' argument contains the object that was thrown,
/// and the 'stack' argument contains the stack trace. The callback is invoked
/// after the information is printed to the console.
GesturerExceptionHandler debugGesturerExceptionHandler;
/// 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);
for (HitTestEntry entry in result.path) {
try {
entry.target.handleEvent(event, entry);
} catch (exception, stack) {
debugPrint('-- EXCEPTION --');
debugPrint('The following exception was raised while dispatching a pointer event:');
debugPrint('$exception');
debugPrint('Stack trace:');
debugPrint('$stack');
debugPrint('Event:');
debugPrint('$event');
debugPrint('Target:');
debugPrint('${entry.target}');
if (debugGesturerExceptionHandler != null)
debugGesturerExceptionHandler(event, entry.target, exception, stack);
}
}
}
void handleEvent(PointerEvent event, HitTestEntry entry) {
......
......@@ -2,11 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/services.dart';
import 'events.dart';
/// A callback that receives a [PointerEvent]
typedef void PointerRoute(PointerEvent event);
typedef void PointerExceptionHandler(PointerRouter source, PointerEvent event, PointerRoute route, dynamic exception, StackTrace stack);
/// A routing table for [PointerEvent] events.
class PointerRouter {
final Map<int, List<PointerRoute>> _routeMap = new Map<int, List<PointerRoute>>();
......@@ -34,14 +38,38 @@ class PointerRouter {
_routeMap.remove(pointer);
}
/// Calls the routes registed for this pointer event.
/// This callback is invoked whenever an exception is caught by the pointer
/// router. The 'source' argument is the [PointerRouter] object that caught
/// the exception. The 'event' argument is the pointer event that was being
/// routed. The 'route' argument is the callback that threw the exception. The
/// 'exception' argument contains the object that was thrown, and the 'stack'
/// argument contains the stack trace. The callback is invoked after the
/// information (exception, stack trace, and event; not the route callback
/// itself) is printed to the console.
PointerExceptionHandler debugPointerExceptionHandler;
/// Calls the routes registered for this pointer event.
///
/// Calls the routes in the order in which they were added to the route.
/// Routes are called in the order in which they were added to the
/// PointerRouter object.
void route(PointerEvent event) {
List<PointerRoute> routes = _routeMap[event.pointer];
if (routes == null)
return;
for (PointerRoute route in new List<PointerRoute>.from(routes))
route(event);
for (PointerRoute route in new List<PointerRoute>.from(routes)) {
try {
route(event);
} catch (exception, stack) {
debugPrint('-- EXCEPTION --');
debugPrint('The following exception was raised while routing a pointer event:');
debugPrint('$exception');
debugPrint('Stack trace:');
debugPrint('$stack');
debugPrint('Event:');
debugPrint('$event');
if (debugPointerExceptionHandler != null)
debugPointerExceptionHandler(this, event, route, exception, stack);
}
}
}
}
......@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:collection';
import 'dart:convert' show JSON;
import 'dart:developer' as developer;
import 'dart:ui' as ui;
......@@ -11,7 +10,8 @@ import 'dart:ui' as ui;
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:vector_math/vector_math_64.dart';
export 'package:flutter/services.dart' show debugPrint;
/// Causes each RenderBox to paint a box around its bounds.
bool debugPaintSizeEnabled = false;
......@@ -127,43 +127,3 @@ Future<developer.ServiceExtensionResponse> _timeDilation(String method, Map<Stri
}))
);
}
/// Prints a message to the console, which you can access using the "flutter"
/// tool's "logs" command ("flutter logs").
///
/// This function very crudely attempts to throttle the rate at which messages
/// are sent to avoid data loss on Android. This means that interleaving calls
/// to this function (directly or indirectly via [debugDumpRenderTree] or
/// [debugDumpApp]) and to the Dart [print] method can result in out-of-order
/// messages in the logs.
void debugPrint(String message) {
_debugPrintBuffer.addAll(message.split('\n'));
if (!_debugPrintScheduled)
_debugPrintTask();
}
int _debugPrintedCharacters = 0;
int _kDebugPrintCapacity = 16 * 1024;
Duration _kDebugPrintPauseTime = const Duration(seconds: 1);
Queue<String> _debugPrintBuffer = new Queue<String>();
Stopwatch _debugPrintStopwatch = new Stopwatch();
bool _debugPrintScheduled = false;
void _debugPrintTask() {
_debugPrintScheduled = false;
if (_debugPrintStopwatch.elapsed > _kDebugPrintPauseTime) {
_debugPrintStopwatch.stop();
_debugPrintStopwatch.reset();
_debugPrintedCharacters = 0;
}
while (_debugPrintedCharacters < _kDebugPrintCapacity && _debugPrintBuffer.length > 0) {
String line = _debugPrintBuffer.removeFirst();
_debugPrintedCharacters += line.length; // TODO(ianh): Use the UTF-8 byte length instead
print(line);
}
if (_debugPrintBuffer.length > 0) {
_debugPrintScheduled = true;
_debugPrintedCharacters = 0;
new Timer(_kDebugPrintPauseTime, _debugPrintTask);
} else {
_debugPrintStopwatch.start();
}
}
// 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:async';
import 'dart:collection';
/// Prints a message to the console, which you can access using the "flutter"
/// tool's "logs" command ("flutter logs").
///
/// This function very crudely attempts to throttle the rate at which messages
/// are sent to avoid data loss on Android. This means that interleaving calls
/// to this function (directly or indirectly via [debugDumpRenderTree] or
/// [debugDumpApp]) and to the Dart [print] method can result in out-of-order
/// messages in the logs.
void debugPrint(String message) {
_debugPrintBuffer.addAll(message.split('\n'));
if (!_debugPrintScheduled)
_debugPrintTask();
}
int _debugPrintedCharacters = 0;
int _kDebugPrintCapacity = 16 * 1024;
Duration _kDebugPrintPauseTime = const Duration(seconds: 1);
Queue<String> _debugPrintBuffer = new Queue<String>();
Stopwatch _debugPrintStopwatch = new Stopwatch();
bool _debugPrintScheduled = false;
void _debugPrintTask() {
_debugPrintScheduled = false;
if (_debugPrintStopwatch.elapsed > _kDebugPrintPauseTime) {
_debugPrintStopwatch.stop();
_debugPrintStopwatch.reset();
_debugPrintedCharacters = 0;
}
while (_debugPrintedCharacters < _kDebugPrintCapacity && _debugPrintBuffer.length > 0) {
String line = _debugPrintBuffer.removeFirst();
_debugPrintedCharacters += line.length; // TODO(ianh): Use the UTF-8 byte length instead
print(line);
}
if (_debugPrintBuffer.length > 0) {
_debugPrintScheduled = true;
_debugPrintedCharacters = 0;
new Timer(_kDebugPrintPauseTime, _debugPrintTask);
} else {
_debugPrintStopwatch.start();
}
}
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