Skip to content

Conversation

@goderbauer
Copy link
Member

@goderbauer goderbauer commented Apr 17, 2023

Part of #121573.

This change enables Flutter to generate multiple Scenes to be rendered into separate FlutterViews from a single widget tree. Each Scene is described by a separate render tree, which are all associated with the single widget tree.

This PR implements the framework-side mechanisms to describe the content to be rendered into multiple views. Separate engine-side changes are necessary to provide these views to the framework and to draw the framework-generated Scene into them.

Summary of changes

The details of this change are described in flutter.dev/go/multiple-views. Below is a high-level summary organized by layers.

Rendering layer changes

  • The RendererBinding no longer owns a single renderView. In fact, it doesn't OWN any RenderViews at all anymore. Instead, it offers an API (addRenderView/removeRenderView) to add and remove RenderViews that then will be MANAGED by the binding. The RenderView itself is now owned by a higher-level abstraction (e.g. the RawView Element of the widgets layer, see below), who is also in charge of adding it to the binding. When added, the binding will interact with the RenderView to produce a frame (e.g. by calling compositeFrame on it) and to perform hit tests for incoming pointer events. Multiple RenderViews can be added to the binding (typically one per FlutterView) to produce multiple Scenes.
  • Instead of owning a single pipelineOwner, the RendererBinding now owns the root of the PipelineOwner tree (exposed as rootPipelineOwner on the binding). Each PipelineOwner in that tree (except for the root) typically manages its own render tree typically rooted in one of the RenderViews mentioned in the previous bullet. During frame production, the binding will instruct each PipelineOwner of that tree to flush layout, paint, semantics etc. A higher-level abstraction (e.g. the widgets layer, see below) is in charge of adding PipelineOwners to this tree.
  • Backwards compatibility: The old renderView and pipelineOwner properties of the RendererBinding are retained, but marked as deprecated. Care has been taken to keep their original behavior for the deprecation period, i.e. if you just call runApp, the render tree bootstrapped by this call is rooted in the deprecated RendererBinding.renderView and managed by the deprecated RendererBinding.pipelineOwner.

Widgets layer changes

  • The WidgetsBinding no longer attaches the widget tree to an existing render tree. Instead, it bootstraps a stand-alone widget tree that is not backed by a render tree. For this, RenderObjectToWidgetAdapter has been replaced by RootWidget.
  • Multiple render trees can be bootstrapped and attached to the widget tree with the help of the View widget, which internally is backed by a RawView widget. Configured with a FlutterView to render into, the RawView creates a new PipelineOwner and a new RenderView for the new render tree. It adds the new RenderView to the RendererBinding and its PipelineOwner to the pipeline owner tree.
  • The View widget can only appear in certain well-defined locations in the widget tree since it bootstraps a new render tree and does not insert a RenderObject into an ancestor. However, almost all Elements expect that their children insert RenderObjects, otherwise they will not function properly. To produce a good error message when the View widget is used in an illegal location, the debugMustInsertRenderObjectIntoSlot method has been added to Element, where a child can ask whether a given slot must insert a RenderObject into its ancestor or not. In practice, the View widget can be used as a child of the RootWidget, inside the view slot of the ViewAnchor (see below) and inside a ViewCollection (see below). In those locations, the View widget may be wrapped in other non-RenderObjectWidgets (e.g. InheritedWidgets).
  • The new ViewAnchor can be used to create a side-view inside a parent View. The child of the ViewAnchor widget renders into the parent View as usual, but the view slot can take on another View widget, which has access to all inherited widgets above the ViewAnchor. Metaphorically speaking, the view is anchored to the location of the ViewAnchor in the widget tree.
  • The new ViewCollection widget allows for multiple sibling views as it takes a list of Views as children. It can be used in all the places that accept a View widget.

Google3

As of July 5, 2023 this change passed a TAP global presubmit (TGP) in google3: tap/OCL:544707016:BASE:545809771:1688597935864:e43dd651

Note to reviewers

This change is big (sorry). I suggest focusing the initial review on the changes inside of packages/flutter first. The majority of the changes describe above are implemented in (listed in suggested review order):

  • rendering/binding.dart
  • widgets/binding.dart
  • widgets/view.dart
  • widgets/framework.dart

All other changes included in the PR are basically the fallout of what's implemented in those files. Also note that a lot of the lines added in this PR are documentation and tests.

I am also very happy to walk reviewers through the code in person or via video call, if that is helpful.

I appreciate any feedback.

Feedback to address before submitting ("TODO")

  • PipelineOwner tree should implement DiagnosticableTree
  • ViewHooksScope should be private
  • Disallow setting root node on default root pipeline owner

@flutter-dashboard flutter-dashboard bot added a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) a: animation Animation APIs a: tests "flutter test", flutter_test, or one of our tests a: text input Entering text in a text field or keyboard related problems d: examples Sample code and demos f: focus Focus traversal, gaining or losing focus f: gestures flutter/packages/flutter/gestures repository. f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels. f: integration_test The flutter/packages/integration_test plugin c: contributor-productivity Team-specific productivity, code health, technical debt. labels Apr 17, 2023
@goderbauer goderbauer force-pushed the rawview branch 2 times, most recently from b53331d to b4f9996 Compare April 25, 2023 13:01
@goderbauer goderbauer force-pushed the rawview branch 4 times, most recently from 8993887 to c6dd65f Compare May 10, 2023 11:59
@goderbauer goderbauer force-pushed the rawview branch 3 times, most recently from 478a36b to 43a9a19 Compare May 18, 2023 18:22
@github-actions github-actions bot removed the a: animation Animation APIs label Jun 7, 2023
@github-actions github-actions bot removed f: material design flutter/packages/flutter/material repository. a: text input Entering text in a text field or keyboard related problems f: routes Navigator, Router, and related APIs. labels Jun 7, 2023
@goderbauer goderbauer force-pushed the rawview branch 3 times, most recently from 9b1458e to 7c92446 Compare June 10, 2023 01:01
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 18, 2023
stuartmorgan-g added a commit to stuartmorgan-g/packages that referenced this pull request Jul 18, 2023
As of flutter/flutter#125003 the current method
these tests use to get the screen width throws an exception, since it
assumes that the first widget in the tree has certain properties. To
make the test more robust, this get the width of the outmost Column,
which is part of the test setup, rather than whatever the first widget
is.

Unblocks the flutter->packgaes roller.
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jul 19, 2023
As of flutter/flutter#125003 the current method these tests use to get the screen width throws an exception, since it assumes that the first widget in the tree has certain properties. To make the test more robust, this get the width of the outmost Column, which is part of the test setup, rather than whatever the first widget is.

Unblocks the flutter->packgaes roller.
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 19, 2023
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jul 19, 2023
Manual roll requested by [email protected]

flutter/flutter@f842ed9...6f09064

2023-07-17 [email protected] Stand-alone widget tree with multiple render trees to enable multi-view rendering (flutter/flutter#125003)
2023-07-17 [email protected] Update to valid build tools variant and update lockfiles (flutter/flutter#125825)
2023-07-17 [email protected] Roll Packages from 369ee7e to 6889cca (5 revisions) (flutter/flutter#130721)
2023-07-17 [email protected] [Reland] - Update `DialogTheme` tests for M2/M3 (flutter/flutter#130711)
2023-07-17 [email protected] Roll Flutter Engine from 683087731feb to e4cae43c9c7a (9 revisions) (flutter/flutter#130716)
2023-07-17 [email protected] [flutter_tools] Support coverage collection for dependencies (flutter/flutter#129513)
2023-07-17 [email protected] Fix `DatePicker` uses incorrect overlay color from `DatePickerTheme` and add missing tests (flutter/flutter#130584)
2023-07-17 [email protected] Update `DropdownMenu`, `SnackBarTheme` and `Stepper` tests for M2/M3 (flutter/flutter#130464)
2023-07-17 [email protected] Clarify the whole "CustomPainters default to Size.zero" thing. (flutter/flutter#130624)
2023-07-16 [email protected] Update list of CoC contacts. (flutter/flutter#130630)
2023-07-15 [email protected] Manual roll Flutter Engine from 403866d16137 to 683087731feb (16 revisions) (flutter/flutter#130666)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
LouiseHsu pushed a commit to LouiseHsu/flutter that referenced this pull request Jul 31, 2023
…ew rendering (flutter#125003)

This change enables Flutter to generate multiple Scenes to be rendered into separate FlutterViews from a single widget tree. Each Scene is described by a separate render tree, which are all associated with the single widget tree.

This PR implements the framework-side mechanisms to describe the content to be rendered into multiple views. Separate engine-side changes are necessary to provide these views to the framework and to draw the framework-generated Scene into them.

## Summary of changes

The details of this change are described in [flutter.dev/go/multiple-views](https://flutter.dev/go/multiple-views). Below is a high-level summary organized by layers.

### Rendering layer changes

* The `RendererBinding` no longer owns a single `renderView`. In fact, it doesn't OWN any `RenderView`s at all anymore. Instead, it offers an API (`addRenderView`/`removeRenderView`) to add and remove `RenderView`s that then will be MANAGED by the binding. The `RenderView` itself is now owned by a higher-level abstraction (e.g. the `RawView` Element of the widgets layer, see below), who is also in charge of adding it to the binding. When added, the binding will interact with the `RenderView` to produce a frame (e.g. by calling `compositeFrame` on it) and to perform hit tests for incoming pointer events. Multiple `RenderView`s can be added to the binding (typically one per `FlutterView`) to produce multiple Scenes.
* Instead of owning a single `pipelineOwner`, the `RendererBinding` now owns the root of the `PipelineOwner` tree (exposed as `rootPipelineOwner` on the binding). Each `PipelineOwner` in that tree (except for the root) typically manages its own render tree typically rooted in one of the `RenderView`s mentioned in the previous bullet. During frame production, the binding will instruct each `PipelineOwner` of that tree to flush layout, paint, semantics etc. A higher-level abstraction (e.g. the widgets layer, see below) is in charge of adding `PipelineOwner`s to this tree.
* Backwards compatibility: The old `renderView` and `pipelineOwner` properties of the `RendererBinding` are retained, but marked as deprecated. Care has been taken to keep their original behavior for the deprecation period, i.e. if you just call `runApp`, the render tree bootstrapped by this call is rooted in the deprecated `RendererBinding.renderView` and managed by the deprecated `RendererBinding.pipelineOwner`.

### Widgets layer changes

* The `WidgetsBinding` no longer attaches the widget tree to an existing render tree. Instead, it bootstraps a stand-alone widget tree that is not backed by a render tree. For this, `RenderObjectToWidgetAdapter` has been replaced by `RootWidget`.
* Multiple render trees can be bootstrapped and attached to the widget tree with the help of the `View` widget, which internally is backed by a `RawView` widget. Configured with a `FlutterView` to render into, the `RawView` creates a new `PipelineOwner` and a new `RenderView` for the new render tree. It adds the new `RenderView` to the `RendererBinding` and its `PipelineOwner` to the pipeline owner tree.
* The `View` widget can only appear in certain well-defined locations in the widget tree since it bootstraps a new render tree and does not insert a `RenderObject` into an ancestor. However, almost all Elements expect that their children insert `RenderObject`s, otherwise they will not function properly. To produce a good error message when the `View` widget is used in an illegal location, the `debugMustInsertRenderObjectIntoSlot` method has been added to Element, where a child can ask whether a given slot must insert a RenderObject into its ancestor or not. In practice, the `View` widget can be used as a child of the `RootWidget`, inside the `view` slot of the `ViewAnchor` (see below) and inside a `ViewCollection` (see below). In those locations, the `View` widget may be wrapped in other non-RenderObjectWidgets (e.g. InheritedWidgets).
* The new `ViewAnchor` can be used to create a side-view inside a parent `View`. The `child` of the `ViewAnchor` widget renders into the parent `View` as usual, but the `view` slot can take on another `View` widget, which has access to all inherited widgets above the `ViewAnchor`. Metaphorically speaking, the view is anchored to the location of the `ViewAnchor` in the widget tree.
* The new `ViewCollection` widget allows for multiple sibling views as it takes a list of `View`s as children. It can be used in all the places that accept a `View` widget.

## Google3

As of July 5, 2023 this change passed a TAP global presubmit (TGP) in google3: tap/OCL:544707016:BASE:545809771:1688597935864:e43dd651

## Note to reviewers

This change is big (sorry). I suggest focusing the initial review on the changes inside of `packages/flutter` first. The majority of the changes describe above are implemented in (listed in suggested review order):

* `rendering/binding.dart`
* `widgets/binding.dart`
* `widgets/view.dart`
* `widgets/framework.dart`

All other changes included in the PR are basically the fallout of what's implemented in those files. Also note that a lot of the lines added in this PR are documentation and tests.

I am also very happy to walk reviewers through the code in person or via video call, if that is helpful.

I appreciate any feedback.

## Feedback to address before submitting ("TODO")
@goderbauer goderbauer deleted the rawview branch November 22, 2023 17:52
auto-submit bot pushed a commit that referenced this pull request Aug 29, 2024
So, uhm, 2 years ago in #116429 we introduced this concept of a lookup boundary to hide certain InheritedWidgets in widget subtrees who belong to a different render tree than the InheritedWidget itself. This is for example needed for the Material widget: Buttons reach out to their Material ancestor to draw ink splashes on its associated render object. This only produces the desired effect if the button render object is a descendant of the Material render object (the two need to be in the same render tree). Overlay widgets have a similar problem. 

Lookup boundaries were specifically designed for multi view support, where a sub view would be powered by a separate and independent render tree. Ergo, widgets in the sub view shouldn't see these InheritedWidgets if they are part of the parent view. After all, it would be strange if clicking on a button in a subview draws the ink splash effect into the parent view. Unfortunately, we (and by that I really mean I) forgot to put a LayoutBoundary into the relevant multi view widgets when those were introduced in #125003. This PR addresses that by wrapping the `ViewAnchor.view` child in a LookupBoundary so that its subtree (which bootstraps a separate render tree) cannot see these InheritedWidgets in the parent view.
Buchimi pushed a commit to Buchimi/flutter that referenced this pull request Sep 2, 2024
So, uhm, 2 years ago in flutter#116429 we introduced this concept of a lookup boundary to hide certain InheritedWidgets in widget subtrees who belong to a different render tree than the InheritedWidget itself. This is for example needed for the Material widget: Buttons reach out to their Material ancestor to draw ink splashes on its associated render object. This only produces the desired effect if the button render object is a descendant of the Material render object (the two need to be in the same render tree). Overlay widgets have a similar problem. 

Lookup boundaries were specifically designed for multi view support, where a sub view would be powered by a separate and independent render tree. Ergo, widgets in the sub view shouldn't see these InheritedWidgets if they are part of the parent view. After all, it would be strange if clicking on a button in a subview draws the ink splash effect into the parent view. Unfortunately, we (and by that I really mean I) forgot to put a LayoutBoundary into the relevant multi view widgets when those were introduced in flutter#125003. This PR addresses that by wrapping the `ViewAnchor.view` child in a LookupBoundary so that its subtree (which bootstraps a separate render tree) cannot see these InheritedWidgets in the parent view.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) a: tests "flutter test", flutter_test, or one of our tests autosubmit Merge PR when tree becomes green via auto submit App c: contributor-productivity Team-specific productivity, code health, technical debt. d: examples Sample code and demos f: focus Focus traversal, gaining or losing focus f: integration_test The flutter/packages/integration_test plugin framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants