Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit fce6978

Browse files
authored
MultiView changes for dart:ui (#42493)
Fixes flutter/flutter#124991. Framework tests are failing because I need to do a pre-migration of `flutter_test` for the Object -> int change of viewId. That's in flutter/flutter#128092.
1 parent 8769e9c commit fce6978

File tree

11 files changed

+229
-29
lines changed

11 files changed

+229
-29
lines changed

lib/ui/fixtures/ui_test.dart

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,37 @@ void hooksTests() async {
538538
expectEquals(x.countryCode, y.countryCode);
539539
});
540540

541+
await test('PlatformDispatcher.view getter returns view with provided ID', () {
542+
const int viewId = 123456789;
543+
_callHook(
544+
'_updateWindowMetrics',
545+
21,
546+
viewId, // window Id
547+
1.0, // devicePixelRatio
548+
800.0, // width
549+
600.0, // height
550+
50.0, // paddingTop
551+
0.0, // paddingRight
552+
40.0, // paddingBottom
553+
0.0, // paddingLeft
554+
0.0, // insetTop
555+
0.0, // insetRight
556+
0.0, // insetBottom
557+
0.0, // insetLeft
558+
0.0, // systemGestureInsetTop
559+
0.0, // systemGestureInsetRight
560+
0.0, // systemGestureInsetBottom
561+
0.0, // systemGestureInsetLeft
562+
22.0, // physicalTouchSlop
563+
<double>[], // display features bounds
564+
<int>[], // display features types
565+
<int>[], // display features states
566+
0, // Display ID
567+
);
568+
569+
expectEquals(PlatformDispatcher.instance.view(id: viewId)?.viewId, viewId);
570+
});
571+
541572
await test('View padding/insets/viewPadding/systemGestureInsets', () {
542573
_callHook(
543574
'_updateWindowMetrics',
@@ -602,7 +633,7 @@ void hooksTests() async {
602633
expectEquals(window.systemGestureInsets.bottom, 44.0);
603634
});
604635

605-
await test('Window physical touch slop', () {
636+
await test('Window physical touch slop', () {
606637
_callHook(
607638
'_updateWindowMetrics',
608639
21,
@@ -816,6 +847,25 @@ void hooksTests() async {
816847
expectEquals(action, 4);
817848
});
818849

850+
await test('onSemanticsActionEvent preserves callback zone', () {
851+
late Zone innerZone;
852+
late Zone runZone;
853+
late SemanticsActionEvent action;
854+
855+
runZoned(() {
856+
innerZone = Zone.current;
857+
PlatformDispatcher.instance.onSemanticsActionEvent = (SemanticsActionEvent actionEvent) {
858+
runZone = Zone.current;
859+
action = actionEvent;
860+
};
861+
});
862+
863+
_callHook('_dispatchSemanticsAction', 3, 1234, 4, null);
864+
expectIdentical(runZone, innerZone);
865+
expectEquals(action.nodeId, 1234);
866+
expectEquals(action.type.index, 4);
867+
});
868+
819869
await test('onPlatformMessage preserves callback zone', () {
820870
late Zone innerZone;
821871
late Zone runZone;

lib/ui/hooks.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void _updateDisplays(
3232

3333
@pragma('vm:entry-point')
3434
void _updateWindowMetrics(
35-
Object id,
35+
int id,
3636
double devicePixelRatio,
3737
double width,
3838
double height,

lib/ui/platform_dispatcher.dart

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ typedef PointerDataPacketCallback = void Function(PointerDataPacket packet);
3333
typedef KeyDataCallback = bool Function(KeyData data);
3434

3535
/// Signature for [PlatformDispatcher.onSemanticsAction].
36+
// TODO(goderbauer): Deprecate/remove this when the framework has migrated to SemanticsActionEventCallback.
3637
typedef SemanticsActionCallback = void Function(int nodeId, SemanticsAction action, ByteData? args);
3738

39+
/// Signature for [PlatformDispatcher.onSemanticsActionEvent].
40+
typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action);
41+
3842
/// Signature for responses to platform messages.
3943
///
4044
/// Used as a parameter to [PlatformDispatcher.sendPlatformMessage] and
@@ -174,7 +178,11 @@ class PlatformDispatcher {
174178
///
175179
/// If any of their configurations change, [onMetricsChanged] will be called.
176180
Iterable<FlutterView> get views => _views.values;
177-
final Map<Object, FlutterView> _views = <Object, FlutterView>{};
181+
final Map<int, FlutterView> _views = <int, FlutterView>{};
182+
183+
/// Returns the [FlutterView] with the provided ID if one exists, or null
184+
/// otherwise.
185+
FlutterView? view({required int id}) => _views[id];
178186

179187
// A map of opaque platform view identifiers to view configurations.
180188
final Map<Object, _ViewConfiguration> _viewConfigurations = <Object, _ViewConfiguration>{};
@@ -250,7 +258,7 @@ class PlatformDispatcher {
250258
//
251259
// Updates the metrics of the window with the given id.
252260
void _updateWindowMetrics(
253-
Object id,
261+
int id,
254262
double devicePixelRatio,
255263
double width,
256264
double height,
@@ -436,6 +444,7 @@ class PlatformDispatcher {
436444
for (int i = 0; i < length; ++i) {
437445
int offset = i * _kPointerDataFieldCount;
438446
data.add(PointerData(
447+
// TODO(goderbauer): Wire up viewId.
439448
embedderId: packet.getInt64(kStride * offset++, _kFakeHostEndian),
440449
timeStamp: Duration(microseconds: packet.getInt64(kStride * offset++, _kFakeHostEndian)),
441450
change: PointerChange.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)],
@@ -1150,6 +1159,7 @@ class PlatformDispatcher {
11501159
///
11511160
/// The framework invokes this callback in the same zone in which the
11521161
/// callback was set.
1162+
// TODO(goderbauer): Deprecate/remove this when the framework has migrated to onSemanticsActionEvent.
11531163
SemanticsActionCallback? get onSemanticsAction => _onSemanticsAction;
11541164
SemanticsActionCallback? _onSemanticsAction;
11551165
Zone _onSemanticsActionZone = Zone.root;
@@ -1158,6 +1168,22 @@ class PlatformDispatcher {
11581168
_onSemanticsActionZone = Zone.current;
11591169
}
11601170

1171+
/// A callback that is invoked whenever the user requests an action to be
1172+
/// performed on a semantics node.
1173+
///
1174+
/// This callback is used when the user expresses the action they wish to
1175+
/// perform based on the semantics node supplied by updateSemantics.
1176+
///
1177+
/// The framework invokes this callback in the same zone in which the
1178+
/// callback was set.
1179+
SemanticsActionEventCallback? get onSemanticsActionEvent => _onSemanticsActionEvent;
1180+
SemanticsActionEventCallback? _onSemanticsActionEvent;
1181+
Zone _onSemanticsActionEventZone = Zone.root;
1182+
set onSemanticsActionEvent(SemanticsActionEventCallback? callback) {
1183+
_onSemanticsActionEvent = callback;
1184+
_onSemanticsActionEventZone = Zone.current;
1185+
}
1186+
11611187
// Called from the engine via hooks.dart.
11621188
void _updateFrameData(int frameNumber) {
11631189
final FrameData previous = _frameData;
@@ -1190,6 +1216,16 @@ class PlatformDispatcher {
11901216
SemanticsAction.fromIndex(action)!,
11911217
args,
11921218
);
1219+
_invoke1<SemanticsActionEvent>(
1220+
onSemanticsActionEvent,
1221+
_onSemanticsActionEventZone,
1222+
SemanticsActionEvent(
1223+
type: SemanticsAction.fromIndex(action)!,
1224+
nodeId: nodeId,
1225+
viewId: 0, // TODO(goderbauer): Wire up the real view ID.
1226+
arguments: args,
1227+
),
1228+
);
11931229
}
11941230

11951231
ErrorCallback? _onError;
@@ -2350,3 +2386,49 @@ enum DartPerformanceMode {
23502386
/// frequently performing work.
23512387
memory,
23522388
}
2389+
2390+
/// An event to request a [SemanticsAction] of [type] to be performed on the
2391+
/// [SemanticsNode] identified by [nodeId] owned by the [FlutterView] identified
2392+
/// by [viewId].
2393+
///
2394+
/// Used by [SemanticsBinding.performSemanticsAction].
2395+
class SemanticsActionEvent {
2396+
/// Creates a [SemanticsActionEvent].
2397+
const SemanticsActionEvent({
2398+
required this.type,
2399+
required this.viewId,
2400+
required this.nodeId,
2401+
this.arguments,
2402+
});
2403+
2404+
/// The type of action to be performed.
2405+
final SemanticsAction type;
2406+
2407+
/// The id of the [FlutterView] the [SemanticsNode] identified by [nodeId] is
2408+
/// associated with.
2409+
final int viewId;
2410+
2411+
/// The id of the [SemanticsNode] on which the action is to be performed.
2412+
final int nodeId;
2413+
2414+
/// Optional arguments for the action.
2415+
final Object? arguments;
2416+
2417+
static const Object _noArgumentPlaceholder = Object();
2418+
2419+
/// Create a clone of the [SemanticsActionEvent] but with provided parameters
2420+
/// replaced.
2421+
SemanticsActionEvent copyWith({
2422+
SemanticsAction? type,
2423+
int? viewId,
2424+
int? nodeId,
2425+
Object? arguments = _noArgumentPlaceholder,
2426+
}) {
2427+
return SemanticsActionEvent(
2428+
type: type ?? this.type,
2429+
viewId: viewId ?? this.viewId,
2430+
nodeId: nodeId ?? this.nodeId,
2431+
arguments: arguments == _noArgumentPlaceholder ? this.arguments : arguments,
2432+
);
2433+
}
2434+
}

lib/ui/pointer.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ enum PointerSignalKind {
141141
class PointerData {
142142
/// Creates an object that represents the state of a pointer.
143143
const PointerData({
144+
this.viewId = 0,
144145
this.embedderId = 0,
145146
this.timeStamp = Duration.zero,
146147
this.change = PointerChange.cancel,
@@ -178,11 +179,16 @@ class PointerData {
178179
this.rotation = 0.0,
179180
});
180181

181-
/// Unique identifier that ties the [PointerEvent] to embedder event created it.
182+
/// The ID of the [FlutterView] this [PointerEvent] originated from.
183+
final int viewId;
184+
185+
/// Unique identifier that ties the [PointerEvent] to the embedder
186+
/// event that created it.
187+
/// it.
182188
///
183-
/// No two pointer events can have the same [embedderId]. This is different from
184-
/// [pointerIdentifier] - used for hit-testing, whereas [embedderId] is used to
185-
/// identify the platform event.
189+
/// No two pointer events can have the same [embedderId]. This is different
190+
/// from [pointerIdentifier] - used for hit-testing, whereas [embedderId] is
191+
/// used to identify the platform event.
186192
final int embedderId;
187193

188194
/// Time of event dispatch, relative to an arbitrary timeline.

lib/ui/window.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class FlutterView {
8989
FlutterView._(this.viewId, this.platformDispatcher);
9090

9191
/// The opaque ID for this view.
92-
final Object viewId;
92+
final int viewId;
9393

9494
/// The platform dispatcher that this view is registered with, and gets its
9595
/// information from.

lib/web_ui/lib/platform_dispatcher.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ typedef TimingsCallback = void Function(List<FrameTiming> timings);
1010
typedef PointerDataPacketCallback = void Function(PointerDataPacket packet);
1111
typedef KeyDataCallback = bool Function(KeyData data);
1212
typedef SemanticsActionCallback = void Function(int nodeId, SemanticsAction action, ByteData? args);
13+
typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action);
1314
typedef PlatformMessageResponseCallback = void Function(ByteData? data);
1415
typedef PlatformMessageCallback = void Function(
1516
String name, ByteData? data, PlatformMessageResponseCallback? callback);
@@ -33,6 +34,8 @@ abstract class PlatformDispatcher {
3334

3435
Iterable<FlutterView> get views;
3536

37+
FlutterView? view({required int id});
38+
3639
FlutterView? get implicitView;
3740

3841
VoidCallback? get onMetricsChanged;
@@ -135,6 +138,9 @@ abstract class PlatformDispatcher {
135138
SemanticsActionCallback? get onSemanticsAction;
136139
set onSemanticsAction(SemanticsActionCallback? callback);
137140

141+
SemanticsActionEventCallback? get onSemanticsActionEvent;
142+
set onSemanticsActionEvent(SemanticsActionEventCallback? callback);
143+
138144
ErrorCallback? get onError;
139145
set onError(ErrorCallback? callback);
140146

@@ -493,3 +499,33 @@ enum DartPerformanceMode {
493499
throughput,
494500
memory,
495501
}
502+
503+
class SemanticsActionEvent {
504+
const SemanticsActionEvent({
505+
required this.type,
506+
required this.viewId,
507+
required this.nodeId,
508+
this.arguments,
509+
});
510+
511+
final SemanticsAction type;
512+
final int viewId;
513+
final int nodeId;
514+
final Object? arguments;
515+
516+
static const Object _noArgumentPlaceholder = Object();
517+
518+
SemanticsActionEvent copyWith({
519+
SemanticsAction? type,
520+
int? viewId,
521+
int? nodeId,
522+
Object? arguments = _noArgumentPlaceholder,
523+
}) {
524+
return SemanticsActionEvent(
525+
type: type ?? this.type,
526+
viewId: viewId ?? this.viewId,
527+
nodeId: nodeId ?? this.nodeId,
528+
arguments: arguments == _noArgumentPlaceholder ? this.arguments : arguments,
529+
);
530+
}
531+
}

lib/web_ui/lib/pointer.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum PointerSignalKind {
3636

3737
class PointerData {
3838
const PointerData({
39+
this.viewId = 0,
3940
this.embedderId = 0,
4041
this.timeStamp = Duration.zero,
4142
this.change = PointerChange.cancel,
@@ -72,6 +73,7 @@ class PointerData {
7273
this.scale = 0.0,
7374
this.rotation = 0.0,
7475
});
76+
final int viewId;
7577
final int embedderId;
7678
final Duration timeStamp;
7779
final PointerChange change;

lib/web_ui/lib/src/engine/platform_dispatcher.dart

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,12 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
165165
/// The current list of windows.
166166
@override
167167
Iterable<ui.FlutterView> get views => viewData.values;
168-
final Map<Object, ui.FlutterView> viewData = <Object, ui.FlutterView>{};
168+
final Map<int, ui.FlutterView> viewData = <int, ui.FlutterView>{};
169+
170+
/// Returns the [FlutterView] with the provided ID if one exists, or null
171+
/// otherwise.
172+
@override
173+
ui.FlutterView? view({required int id}) => viewData[id];
169174

170175
/// A map of opaque platform window identifiers to window configurations.
171176
///
@@ -1206,12 +1211,38 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
12061211
_onSemanticsActionZone = Zone.current;
12071212
}
12081213

1214+
/// A callback that is invoked whenever the user requests an action to be
1215+
/// performed on a semantics node.
1216+
///
1217+
/// This callback is used when the user expresses the action they wish to
1218+
/// perform based on the semantics node supplied by updateSemantics.
1219+
///
1220+
/// The framework invokes this callback in the same zone in which the
1221+
/// callback was set.
1222+
@override
1223+
ui.SemanticsActionEventCallback? get onSemanticsActionEvent => _onSemanticsActionEvent;
1224+
ui.SemanticsActionEventCallback? _onSemanticsActionEvent;
1225+
Zone _onSemanticsActionEventZone = Zone.root;
1226+
@override
1227+
set onSemanticsActionEvent(ui.SemanticsActionEventCallback? callback) {
1228+
_onSemanticsActionEvent = callback;
1229+
_onSemanticsActionEventZone = Zone.current;
1230+
}
1231+
12091232
/// Engine code should use this method instead of the callback directly.
12101233
/// Otherwise zones won't work properly.
12111234
void invokeOnSemanticsAction(
12121235
int nodeId, ui.SemanticsAction action, ByteData? args) {
12131236
invoke3<int, ui.SemanticsAction, ByteData?>(
12141237
_onSemanticsAction, _onSemanticsActionZone, nodeId, action, args);
1238+
invoke1<ui.SemanticsActionEvent>(
1239+
_onSemanticsActionEvent, _onSemanticsActionEventZone, ui.SemanticsActionEvent(
1240+
type: action,
1241+
nodeId: nodeId,
1242+
viewId: 0, // TODO(goderbauer): Wire up the real view ID.
1243+
arguments: args,
1244+
),
1245+
);
12151246
}
12161247

12171248
// TODO(dnfield): make this work on web.

lib/web_ui/lib/src/engine/window.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class EngineFlutterWindow extends ui.SingletonFlutterWindow {
5151
}
5252

5353
@override
54-
final Object viewId;
54+
final int viewId;
5555

5656
@override
5757
final ui.PlatformDispatcher platformDispatcher;

0 commit comments

Comments
 (0)