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

Commit 5019d6d

Browse files
authored
Basic view management for engine classes (#42991)
_This PR is part of the multiview engine project. For a complete roadmap, see [this doc](https://docs.google.com/document/d/10APhzRDR7XqjWdbYWpFfKur7DPiz_HvSKNcLvcyA9vg/edit?resourcekey=0-DfGcg4-XWRMMZF__C1nmcA)._ ------ This PR adds view management to all engine classes that need it. View management here basically means `AddView` and `RemoveView` methods, and most importantly, how to handle the implicit view. The implicit view is a special view that's handled differently than all the other "regular views", since it keeps the behavior of the current single view of Flutter. Detailed introduction can be found in `Settings.implicit_view_enabled`. The following two graphs show the difference between initializing with/without the implicit view and creating regular views. <img width="879" alt="image" src="https://github.com/flutter/engine/assets/1596656/31244685-d9d3-4c9a-9a9e-6e8540a5711e"> <img width="864" alt="image" src="https://github.com/flutter/engine/assets/1596656/e2dd4b8c-57e3-428d-8547-834fb270052b"> <img width="860" alt="image" src="https://github.com/flutter/engine/assets/1596656/58dae687-8c17-434e-ae24-a48c2d8fa5fa"> [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 61a7bea commit 5019d6d

34 files changed

+872
-336
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,8 +1904,6 @@ ORIGIN: ../../../flutter/lib/ui/window/pointer_data_packet_converter.cc + ../../
19041904
ORIGIN: ../../../flutter/lib/ui/window/pointer_data_packet_converter.h + ../../../flutter/LICENSE
19051905
ORIGIN: ../../../flutter/lib/ui/window/viewport_metrics.cc + ../../../flutter/LICENSE
19061906
ORIGIN: ../../../flutter/lib/ui/window/viewport_metrics.h + ../../../flutter/LICENSE
1907-
ORIGIN: ../../../flutter/lib/ui/window/window.cc + ../../../flutter/LICENSE
1908-
ORIGIN: ../../../flutter/lib/ui/window/window.h + ../../../flutter/LICENSE
19091907
ORIGIN: ../../../flutter/lib/web_ui/lib/annotations.dart + ../../../flutter/LICENSE
19101908
ORIGIN: ../../../flutter/lib/web_ui/lib/canvas.dart + ../../../flutter/LICENSE
19111909
ORIGIN: ../../../flutter/lib/web_ui/lib/channel_buffers.dart + ../../../flutter/LICENSE
@@ -4634,8 +4632,6 @@ FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter.cc
46344632
FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter.h
46354633
FILE: ../../../flutter/lib/ui/window/viewport_metrics.cc
46364634
FILE: ../../../flutter/lib/ui/window/viewport_metrics.h
4637-
FILE: ../../../flutter/lib/ui/window/window.cc
4638-
FILE: ../../../flutter/lib/ui/window/window.h
46394635
FILE: ../../../flutter/lib/web_ui/lib/annotations.dart
46404636
FILE: ../../../flutter/lib/web_ui/lib/canvas.dart
46414637
FILE: ../../../flutter/lib/web_ui/lib/channel_buffers.dart

common/constants.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,32 @@
77

88
namespace flutter {
99
constexpr double kMegaByteSizeInBytes = (1 << 20);
10+
11+
// The ID for the implicit view if the implicit view is enabled.
12+
//
13+
// The implicit view is a compatibility mechanism to help the transition from
14+
// the older single-view APIs to the newer multi-view APIs. The two sets of APIs
15+
// use different models for view management. The implicit view mechanism allows
16+
// single-view APIs to operate a special view as if other views don't exist.
17+
//
18+
// In the regular multi-view model, all views should be created by
19+
// `Shell::AddView` before being used, and removed by `Shell::RemoveView` to
20+
// signify that they are gone. If a view is added or removed, the framework
21+
// (`PlatformDispatcher`) will be notified. New view IDs are always unique,
22+
// never reused. Operating a non-existing view is an error.
23+
//
24+
// The implicit view is another special view in addition to the "regular views"
25+
// as above. The shell starts up having the implicit view, which has a fixed
26+
// view ID of `kFlutterImplicitViewId` and is available throughout the lifetime
27+
// of the shell. `Shell::AddView` or `RemoveView` must not be called for this
28+
// view. Even when the window that shows the view is closed, the framework is
29+
// unaware and might continue rendering into or operating this view.
30+
//
31+
// The single-view APIs, which are APIs that do not specify view IDs, operate
32+
// the implicit view. The multi-view APIs can operate all views, including the
33+
// implicit view if the target ID is `kFlutterImplicitViewId`, unless specified
34+
// otherwise.
35+
constexpr int64_t kFlutterImplicitViewId = 0;
1036
} // namespace flutter
1137

1238
#endif // FLUTTER_COMMON_CONSTANTS_H_

lib/ui/BUILD.gn

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,6 @@ source_set("ui") {
155155
"window/pointer_data_packet_converter.h",
156156
"window/viewport_metrics.cc",
157157
"window/viewport_metrics.h",
158-
"window/window.cc",
159-
"window/window.h",
160158
]
161159

162160
public_configs = [ "//flutter:config" ]

lib/ui/compositing/scene.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "flutter/lib/ui/painting/picture.h"
1111
#include "flutter/lib/ui/ui_dart_state.h"
1212
#include "flutter/lib/ui/window/platform_configuration.h"
13-
#include "flutter/lib/ui/window/window.h"
1413
#if IMPELLER_SUPPORTS_RENDERING
1514
#include "flutter/lib/ui/painting/display_list_deferred_image_gpu_impeller.h"
1615
#endif // IMPELLER_SUPPORTS_RENDERING

lib/ui/dart_ui.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <mutex>
88
#include <string_view>
99

10+
#include "flutter/common/constants.h"
1011
#include "flutter/common/settings.h"
1112
#include "flutter/fml/build_config.h"
1213
#include "flutter/lib/ui/compositing/scene.h"
@@ -95,7 +96,6 @@ typedef CanvasPath Path;
9596
V(IsolateNameServerNatives::RemovePortNameMapping, 1) \
9697
V(NativeStringAttribute::initLocaleStringAttribute, 4) \
9798
V(NativeStringAttribute::initSpellOutStringAttribute, 3) \
98-
V(PlatformConfigurationNativeApi::ImplicitViewEnabled, 0) \
9999
V(PlatformConfigurationNativeApi::DefaultRouteName, 0) \
100100
V(PlatformConfigurationNativeApi::ScheduleFrame, 0) \
101101
V(PlatformConfigurationNativeApi::Render, 1) \
@@ -373,6 +373,12 @@ void DartUI::InitForIsolate(const Settings& settings) {
373373
Dart_PropagateError(result);
374374
}
375375
}
376+
377+
result = Dart_SetField(dart_ui, ToDart("_implicitViewId"),
378+
Dart_NewInteger(kFlutterImplicitViewId));
379+
if (Dart_IsError(result)) {
380+
Dart_PropagateError(result);
381+
}
376382
}
377383

378384
} // namespace flutter

lib/ui/hooks.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,60 @@
44

55
part of dart.ui;
66

7+
@pragma('vm:entry-point')
8+
void _addView(
9+
int viewId,
10+
double devicePixelRatio,
11+
double width,
12+
double height,
13+
double viewPaddingTop,
14+
double viewPaddingRight,
15+
double viewPaddingBottom,
16+
double viewPaddingLeft,
17+
double viewInsetTop,
18+
double viewInsetRight,
19+
double viewInsetBottom,
20+
double viewInsetLeft,
21+
double systemGestureInsetTop,
22+
double systemGestureInsetRight,
23+
double systemGestureInsetBottom,
24+
double systemGestureInsetLeft,
25+
double physicalTouchSlop,
26+
List<double> displayFeaturesBounds,
27+
List<int> displayFeaturesType,
28+
List<int> displayFeaturesState,
29+
int displayId,
30+
) {
31+
final _ViewConfiguration viewConfiguration = _buildViewConfiguration(
32+
devicePixelRatio,
33+
width,
34+
height,
35+
viewPaddingTop,
36+
viewPaddingRight,
37+
viewPaddingBottom,
38+
viewPaddingLeft,
39+
viewInsetTop,
40+
viewInsetRight,
41+
viewInsetBottom,
42+
viewInsetLeft,
43+
systemGestureInsetTop,
44+
systemGestureInsetRight,
45+
systemGestureInsetBottom,
46+
systemGestureInsetLeft,
47+
physicalTouchSlop,
48+
displayFeaturesBounds,
49+
displayFeaturesType,
50+
displayFeaturesState,
51+
displayId,
52+
);
53+
PlatformDispatcher.instance._addView(viewId, viewConfiguration);
54+
}
55+
56+
@pragma('vm:entry-point')
57+
void _removeView(int viewId) {
58+
PlatformDispatcher.instance._removeView(viewId);
59+
}
60+
761
@pragma('vm:entry-point')
862
void _updateDisplays(
963
List<int> ids,

lib/ui/natives.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,12 @@ _ScheduleImmediateClosure _getScheduleMicrotaskClosure() => _scheduleMicrotask;
112112
// rendering.
113113
@pragma('vm:entry-point')
114114
bool _impellerEnabled = false;
115+
116+
// Used internally to indicate whether the embedder enables the implicit view,
117+
// and the implicit view's ID if so.
118+
//
119+
// The exact value of this variable is an implementation detail that may change
120+
// at any time. Apps should always use PlatformDispatcher.implicitView to
121+
// determine the current implicit view, if any.
122+
@pragma('vm:entry-point')
123+
int? _implicitViewId;

lib/ui/painting/canvas.cc

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "flutter/lib/ui/painting/paint.h"
1414
#include "flutter/lib/ui/ui_dart_state.h"
1515
#include "flutter/lib/ui/window/platform_configuration.h"
16-
#include "flutter/lib/ui/window/window.h"
1716

1817
using tonic::ToDart;
1918

@@ -621,11 +620,16 @@ void Canvas::drawShadow(const CanvasPath* path,
621620
}
622621

623622
// Not using SafeNarrow because DPR will always be a relatively small number.
624-
SkScalar dpr = static_cast<float>(UIDartState::Current()
625-
->platform_configuration()
626-
->get_window(0)
627-
->viewport_metrics()
628-
.device_pixel_ratio);
623+
const ViewportMetrics* metrics =
624+
UIDartState::Current()->platform_configuration()->GetMetrics(0);
625+
SkScalar dpr;
626+
// TODO(dkwingsmt): We should support rendering shadows on non-implicit views.
627+
// However, currently this method has no way to get the target view ID.
628+
if (metrics == nullptr) {
629+
dpr = 1.0f;
630+
} else {
631+
dpr = static_cast<float>(metrics->device_pixel_ratio);
632+
}
629633
if (display_list_builder_) {
630634
// The DrawShadow mechanism results in non-public operations to be
631635
// performed on the canvas involving an SkDrawShadowRec. Since we

lib/ui/platform_dispatcher.dart

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,6 @@ typedef ErrorCallback = bool Function(Object exception, StackTrace stackTrace);
6666
// A gesture setting value that indicates it has not been set by the engine.
6767
const double _kUnsetGestureSetting = -1.0;
6868

69-
// The view ID of PlatformDispatcher.implicitView. This is an
70-
// implementation detail that may change at any time. Apps
71-
// should always use PlatformDispatcher.implicitView to determine
72-
// the current implicit view, if any.
73-
//
74-
// Keep this in sync with kImplicitViewId in window/platform_configuration.cc.
75-
const int _kImplicitViewId = 0;
76-
7769
// A message channel to receive KeyData from the platform.
7870
//
7971
// See embedder.cc::kFlutterKeyDataChannel for more information.
@@ -218,10 +210,29 @@ class PlatformDispatcher {
218210
/// * [View.of], for accessing the current view.
219211
/// * [PlatformDispatcher.views] for a list of all [FlutterView]s provided
220212
/// by the platform.
221-
FlutterView? get implicitView => _implicitViewEnabled() ? _views[_kImplicitViewId] : null;
222-
223-
@Native<Handle Function()>(symbol: 'PlatformConfigurationNativeApi::ImplicitViewEnabled')
224-
external static bool _implicitViewEnabled();
213+
FlutterView? get implicitView {
214+
final FlutterView? result = _views[_implicitViewId];
215+
// Make sure [implicitView] agrees with `_implicitViewId`.
216+
assert((result != null) == (_implicitViewId != null),
217+
(_implicitViewId != null) ?
218+
'The implicit view ID is $_implicitViewId, but the implicit view does not exist.' :
219+
'The implicit view ID is null, but the implicit view exists.');
220+
// Make sure [implicitView] never chages.
221+
assert(() {
222+
if (_debugRecordedLastImplicitView) {
223+
assert(identical(_debugLastImplicitView, result),
224+
'The implicitView has changed:\n'
225+
'Last: $_debugLastImplicitView\nCurrent: $result');
226+
} else {
227+
_debugLastImplicitView = result;
228+
_debugRecordedLastImplicitView = true;
229+
}
230+
return true;
231+
}());
232+
return result;
233+
}
234+
FlutterView? _debugLastImplicitView;
235+
bool _debugRecordedLastImplicitView = false;
225236

226237
/// A callback that is invoked whenever the [ViewConfiguration] of any of the
227238
/// [views] changes.
@@ -249,6 +260,34 @@ class PlatformDispatcher {
249260
_onMetricsChangedZone = Zone.current;
250261
}
251262

263+
// Called from the engine, via hooks.dart
264+
//
265+
// Adds a new view with the specific view configuration.
266+
//
267+
// The implicit view must be added before [implicitView] is first called,
268+
// which is typically the main function.
269+
void _addView(int id, _ViewConfiguration viewConfiguration) {
270+
assert(!_views.containsKey(id), 'View ID $id already exists.');
271+
_views[id] = FlutterView._(id, this, viewConfiguration);
272+
_invoke(onMetricsChanged, _onMetricsChangedZone);
273+
}
274+
275+
// Called from the engine, via hooks.dart
276+
//
277+
// Removes the specific view.
278+
//
279+
// The target view must must exist. The implicit view must not be removed,
280+
// or an assertion will be triggered.
281+
void _removeView(int id) {
282+
assert(id != _implicitViewId, 'The implicit view #$id can not be removed.');
283+
if (id == _implicitViewId) {
284+
return;
285+
}
286+
assert(_views.containsKey(id), 'View ID $id does not exist.');
287+
_views.remove(id);
288+
_invoke(onMetricsChanged, _onMetricsChangedZone);
289+
}
290+
252291
// Called from the engine, via hooks.dart.
253292
//
254293
// Updates the available displays.
@@ -264,15 +303,8 @@ class PlatformDispatcher {
264303
//
265304
// Updates the metrics of the window with the given id.
266305
void _updateWindowMetrics(int viewId, _ViewConfiguration viewConfiguration) {
267-
final FlutterView? view = _views[viewId];
268-
if (viewId == _kImplicitViewId && view == null) {
269-
// TODO(goderbauer): Remove the implicit creation of the implicit view
270-
// when we have an addView API and the implicit view is added via that.
271-
_views[viewId] = FlutterView._(viewId, this, viewConfiguration);
272-
} else {
273-
assert(view != null);
274-
view!._viewConfiguration = viewConfiguration;
275-
}
306+
assert(_views.containsKey(viewId), 'View $viewId does not exist.');
307+
_views[viewId]!._viewConfiguration = viewConfiguration;
276308
_invoke(onMetricsChanged, _onMetricsChangedZone);
277309
}
278310

lib/ui/ui_dart_state.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "flutter/fml/message_loop.h"
1111
#include "flutter/lib/ui/window/platform_configuration.h"
12+
#include "flutter/lib/ui/window/platform_message.h"
1213
#include "third_party/tonic/converter/dart_converter.h"
1314
#include "third_party/tonic/dart_message_handler.h"
1415

0 commit comments

Comments
 (0)