Commit 8cc9a53e authored by Alexey Ivanov's avatar Alexey Ivanov Committed by Michael Goderbauer

Improve routers performance (#42526)

parent 877c6a62
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// 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:collection';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
...@@ -14,8 +12,8 @@ typedef PointerRoute = void Function(PointerEvent event); ...@@ -14,8 +12,8 @@ typedef PointerRoute = void Function(PointerEvent event);
/// A routing table for [PointerEvent] events. /// A routing table for [PointerEvent] events.
class PointerRouter { class PointerRouter {
final Map<int, LinkedHashSet<_RouteEntry>> _routeMap = <int, LinkedHashSet<_RouteEntry>>{}; final Map<int, Map<PointerRoute, Matrix4>> _routeMap = <int, Map<PointerRoute, Matrix4>>{};
final LinkedHashSet<_RouteEntry> _globalRoutes = LinkedHashSet<_RouteEntry>(); final Map<PointerRoute, Matrix4> _globalRoutes = <PointerRoute, Matrix4>{};
/// Adds a route to the routing table. /// Adds a route to the routing table.
/// ///
...@@ -25,9 +23,12 @@ class PointerRouter { ...@@ -25,9 +23,12 @@ class PointerRouter {
/// Routes added reentrantly within [PointerRouter.route] will take effect when /// Routes added reentrantly within [PointerRouter.route] will take effect when
/// routing the next event. /// routing the next event.
void addRoute(int pointer, PointerRoute route, [Matrix4 transform]) { void addRoute(int pointer, PointerRoute route, [Matrix4 transform]) {
final LinkedHashSet<_RouteEntry> routes = _routeMap.putIfAbsent(pointer, () => LinkedHashSet<_RouteEntry>()); final Map<PointerRoute, Matrix4> routes = _routeMap.putIfAbsent(
assert(!routes.any(_RouteEntry.isRoutePredicate(route))); pointer,
routes.add(_RouteEntry(route: route, transform: transform)); () => <PointerRoute, Matrix4>{},
);
assert(!routes.containsKey(route));
routes[route] = transform;
} }
/// Removes a route from the routing table. /// Removes a route from the routing table.
...@@ -39,9 +40,9 @@ class PointerRouter { ...@@ -39,9 +40,9 @@ class PointerRouter {
/// immediately. /// immediately.
void removeRoute(int pointer, PointerRoute route) { void removeRoute(int pointer, PointerRoute route) {
assert(_routeMap.containsKey(pointer)); assert(_routeMap.containsKey(pointer));
final LinkedHashSet<_RouteEntry> routes = _routeMap[pointer]; final Map<PointerRoute, Matrix4> routes = _routeMap[pointer];
assert(routes.any(_RouteEntry.isRoutePredicate(route))); assert(routes.containsKey(route));
routes.removeWhere(_RouteEntry.isRoutePredicate(route)); routes.remove(route);
if (routes.isEmpty) if (routes.isEmpty)
_routeMap.remove(pointer); _routeMap.remove(pointer);
} }
...@@ -53,8 +54,8 @@ class PointerRouter { ...@@ -53,8 +54,8 @@ class PointerRouter {
/// Routes added reentrantly within [PointerRouter.route] will take effect when /// Routes added reentrantly within [PointerRouter.route] will take effect when
/// routing the next event. /// routing the next event.
void addGlobalRoute(PointerRoute route, [Matrix4 transform]) { void addGlobalRoute(PointerRoute route, [Matrix4 transform]) {
assert(!_globalRoutes.any(_RouteEntry.isRoutePredicate(route))); assert(!_globalRoutes.containsKey(route));
_globalRoutes.add(_RouteEntry(route: route, transform: transform)); _globalRoutes[route] = transform;
} }
/// Removes a route from the global entry in the routing table. /// Removes a route from the global entry in the routing table.
...@@ -65,14 +66,14 @@ class PointerRouter { ...@@ -65,14 +66,14 @@ class PointerRouter {
/// Routes removed reentrantly within [PointerRouter.route] will take effect /// Routes removed reentrantly within [PointerRouter.route] will take effect
/// immediately. /// immediately.
void removeGlobalRoute(PointerRoute route) { void removeGlobalRoute(PointerRoute route) {
assert(_globalRoutes.any(_RouteEntry.isRoutePredicate(route))); assert(_globalRoutes.containsKey(route));
_globalRoutes.removeWhere(_RouteEntry.isRoutePredicate(route)); _globalRoutes.remove(route);
} }
void _dispatch(PointerEvent event, _RouteEntry entry) { void _dispatch(PointerEvent event, PointerRoute route, Matrix4 transform) {
try { try {
event = event.transformed(entry.transform); event = event.transformed(transform);
entry.route(event); route(event);
} catch (exception, stack) { } catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetailsForPointerRouter( FlutterError.reportError(FlutterErrorDetailsForPointerRouter(
exception: exception, exception: exception,
...@@ -80,7 +81,7 @@ class PointerRouter { ...@@ -80,7 +81,7 @@ class PointerRouter {
library: 'gesture library', library: 'gesture library',
context: ErrorDescription('while routing a pointer event'), context: ErrorDescription('while routing a pointer event'),
router: this, router: this,
route: entry.route, route: route,
event: event, event: event,
informationCollector: () sync* { informationCollector: () sync* {
yield DiagnosticsProperty<PointerEvent>('Event', event, style: DiagnosticsTreeStyle.errorProperty); yield DiagnosticsProperty<PointerEvent>('Event', event, style: DiagnosticsTreeStyle.errorProperty);
...@@ -94,18 +95,28 @@ class PointerRouter { ...@@ -94,18 +95,28 @@ class PointerRouter {
/// Routes are called in the order in which they were added to the /// Routes are called in the order in which they were added to the
/// PointerRouter object. /// PointerRouter object.
void route(PointerEvent event) { void route(PointerEvent event) {
final LinkedHashSet<_RouteEntry> routes = _routeMap[event.pointer]; final Map<PointerRoute, Matrix4> routes = _routeMap[event.pointer];
final List<_RouteEntry> globalRoutes = List<_RouteEntry>.from(_globalRoutes); final Map<PointerRoute, Matrix4> copiedGlobalRoutes = Map<PointerRoute, Matrix4>.from(_globalRoutes);
if (routes != null) { if (routes != null) {
for (_RouteEntry entry in List<_RouteEntry>.from(routes)) { _dispatchEventToRoutes(
if (routes.any(_RouteEntry.isRoutePredicate(entry.route))) event,
_dispatch(event, entry); routes,
} Map<PointerRoute, Matrix4>.from(routes),
} );
for (_RouteEntry entry in globalRoutes) {
if (_globalRoutes.any(_RouteEntry.isRoutePredicate(entry.route)))
_dispatch(event, entry);
} }
_dispatchEventToRoutes(event, _globalRoutes, copiedGlobalRoutes);
}
void _dispatchEventToRoutes(
PointerEvent event,
Map<PointerRoute, Matrix4> referenceRoutes,
Map<PointerRoute, Matrix4> copiedRoutes,
) {
copiedRoutes.forEach((PointerRoute route, Matrix4 transform) {
if (referenceRoutes.containsKey(route)) {
_dispatch(event, route, transform);
}
});
} }
} }
...@@ -151,19 +162,3 @@ class FlutterErrorDetailsForPointerRouter extends FlutterErrorDetails { ...@@ -151,19 +162,3 @@ class FlutterErrorDetailsForPointerRouter extends FlutterErrorDetails {
/// The pointer event that was being routed when the exception was raised. /// The pointer event that was being routed when the exception was raised.
final PointerEvent event; final PointerEvent event;
} }
typedef _RouteEntryPredicate = bool Function(_RouteEntry entry);
class _RouteEntry {
const _RouteEntry({
@required this.route,
@required this.transform,
});
final PointerRoute route;
final Matrix4 transform;
static _RouteEntryPredicate isRoutePredicate(PointerRoute route) {
return (_RouteEntry entry) => entry.route == route;
}
}
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