Fixes#115525.
On [AbstractNode.detach] and its two progeny [RenderNode.detach]
and [Layer.detach], the docs said both to call the inherited method
before detaching children, and to end by doing so. The former
advice is what's enforced by an assertion in the base implementation,
so cut out the other.
The corresponding [attach] methods redundantly said twice to
call the inherited method first, so cut the redundancy.
Leave in place the version more recently added (in #76021), because
that PR shows the old version must have been easy to overlook.
These methods and/or their docs were recently copied (in #128467 and #128973) from their classes' former shared base class AbstractNode. Their wording was fittingly abstract there, but that abstraction is a bit puzzling for a reader finding them on these more concrete classes and not aware of the AbstractNode history. So make them more concrete, in similar terms to the other methods around them.
Also copy some useful points between corresponding methods on different classes (like that the parent of the root is null), and try to clean up the prose on [RenderObject.depth].
We focus on the more outward-facing parts of the API, letting methods like `redepthChildren` continue to talk generically about "nodes".
Deprecate `textScaleFactor` in favor of `textScaler`, in preparation for Android 14 [Non-linear font scaling to 200%](https://developer.android.com/about/versions/14/features#non-linear-font-scaling). The `TextScaler` class can be moved to `dart:ui` in the future, if we decide to use the Android platform API or AndroidX to get the scaling curve instead of hard coding the curve in the framework.
I haven't put the Flutter version in the deprecation message so the analyzer checks are failing. Will do so after I finish the migration guide.
**Why `TextScaler.textScaleFactor`**
The author of a `TextScaler` subclass should provide a fallback `textScaleFactor`. By making `TextScaler` also contain the `textScaleFactor` information it also makes it easier to migrate: if a widget overrides `MediaQueryData.textScaler` in the tree, for unmigrated widgets in the subtree it would also have to override `MediaQueryData.textScaleFactor`, and that makes it difficult to remove `MediaQueryData.textScaleFactor` in the future.
## A full list of affected APIs in this PR
Deprecated: The method/getter/setter/argument is annotated with a `@Deprecated()` annotation in this PR, and the caller should replace it with `textScaler` instead. Unless otherwise specified there will be a Flutter fix available to help with migration but it's still recommended to migrate case-by-case.
**Replaced**: The method this `textScaleFactor` argument belongs to is rarely called directly by user code and is not overridden by any of the registered custom tests, so the argument is directly replaced by `TextScaler`.
**To Be Deprecated**: The method/getter/setter/argument can't be deprecated in this PR because a registered customer test depends on it and a Flutter fix isn't available (or the test was run without applying flutter fixes first). This method/getter/setter/argument will be deprecated in a followup PR once the registered test is migrated.
### `Painting` Library
| Affected API | State of `textScaleFactor` | Comment |
| --- | --- | --- |
| `InlineSpan.build({ double textScaleFactor = 1.0 })` argument | **Replaced** | |
| `TextStyle.getParagraphStyle({ double TextScaleFactor = 1.0 })` argument | **Replaced** | |
| `TextStyle.getTextStyle({ double TextScaleFactor = 1.0 })` argument| Deprecated | Can't replace: c47fd38dca/super_editor/lib/src/infrastructure/super_textfield/desktop/desktop_textfield.dart (L1903-L1905)|
| `TextPainter({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | |
| `TextPainter.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet |
| `TextPainter.computeWidth({ double TextScaleFactor = 1.0 })` argument | Deprecated | |
| `TextPainter.computeMaxIntrinsicWidth({ double TextScaleFactor = 1.0 })` argument | Deprecated | |
### `Rendering` Library
| Affected API | State of `textScaleFactor` | Comment |
| --- | --- | --- |
| `RenderEditable({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | |
| `RenderEditable.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet |
| `RenderParagraph({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | |
| `RenderParagraph.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet |
### `Widgets` Library
| Affected API | State of `textScaleFactor` | Comment |
| --- | --- | --- |
| `MediaQueryData({ double TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | cd7b93532e/packages/flutter_markdown/test/text_scale_factor_test.dart (LL39C21-L39C35) |
| `MediaQueryData.textScaleFactor` getter | Deprecated | |
| `MediaQueryData.copyWith({ double? TextScaleFactor })` argument | Deprecated | |
| `MediaQuery.maybeTextScaleFactorOf(BuildContext context)` static method | Deprecated | No Flutter Fix, not expressible yet |
| `MediaQuery.textScaleFactorOf(BuildContext context)` static method | **To Be Deprecated** | cd7b93532e/packages/flutter_markdown/lib/src/_functions_io.dart (L68-L70), No Flutter Fix, not expressible yet |
| `RichText({ double TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | cd7b93532e/packages/flutter_markdown/lib/src/builder.dart (L829-L843) |
| `RichText.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away|
| `Text({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | 914d120da1/packages/rfw/lib/src/flutter/core_widgets.dart (L647) , No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
| `Text.rich({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | The default constructor has an argument that can't be deprecated right away. No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
| `Text.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away |
| `EditableText({ double? TextScaleFactor = 1.0 })` constructor argument | Deprecated | No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
| `EditableText.textScaleFactor` getter | Deprecated | |
### `Material` Library
| Affected API | State of `textScaleFactor` | Comment |
| --- | --- | --- |
| `SelectableText({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | cd7b93532e/packages/flutter_markdown/lib/src/builder.dart (L829-L843), No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
| `SelectableText.rich({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | The default constructor has an argument that can't be deprecated right away. No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 |
| `SelectableText.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away |
A lot of material widgets (`Slider`, `RangeSlider`, `TimePicker`, and different types of buttons) also change their layout based on `textScaleFactor`. These need to be handled in a case-by-case fashion and will be migrated in follow-up PRs.
This was showing up as a hot spot in some benchmarks and profiles. This
function is called frequently during frame builds and often has an empty
map. There may be significant overhead from obtaining the values
iterator and cloning it into a list.
See https://github.com/flutter/flutter/issues/130339
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")
issue:#126652
in Chinese text, word length is 1 and (position.offset == word.end) happens a lot.
Update if (position.offset >= word.end) to if (position.offset > word.end) to resolve the issue that Chinese characters are not selected.
## FlutterTimeline
Add a new class `FlutterTimeline` that's a drop-in replacement for `Timeline` from `dart:developer`. In addition to forwarding invocations of `startSync`, `finishSync`, `timeSync`, and `instantSync` to `dart:developer`, provides the following extra methods that make is easy to collect timings for code blocks on a frame-by-frame basis:
* `debugCollect()` - aggregates timings since the last reset, or since the app launched.
* `debugReset()` - forgets all data collected since the previous reset, or since the app launched. This allows clearing data from previous frames so timings can be attributed to the current frame.
* `now` - this was enhanced so that it works on the web by calling `window.performance.now` (in `Timeline` this is a noop in Dart web compilers).
* `collectionEnabled` - a field that controls whether `FlutterTimeline` stores timings in memory. By default this is disabled to avoid unexpected overhead (although the class is designed for minimal and predictable overhead). Specific benchmarks can enable collection to report to Skia Perf.
## Semantics benchmarks
Add `BenchMaterial3Semantics` that benchmarks the cost of semantics when constructing a screen full of Material 3 widgets from nothing. It is expected that semantics will have non-trivial cost in this case, but we should strive to keep it much lower than the rendering cost. This is the case already. This benchmark shows that the cost of semantics is <10%.
Add `BenchMaterial3ScrollSemantics` that benchmarks the cost of scrolling a previously constructed screen full of Material 3 widgets. The expectation should be that semantics will have trivial cost, since we're just shifting some widgets around. As of today, the numbers are not great, with semantics taking >50% of frame time, which is what prompted this PR in the first place. As we optimize this, we want to see this number improve.
This change updates `SelectableRegion`s right-click gesture to match native platform behavior.
Before: Right-click gesture selects word at position and opens context menu (All Platforms)
After:
- Linux, toggles context menu on/off, and collapses selection when click was not on an active selection (uncollapsed).
- Windows, Android, Fuchsia, shows context menu at right-clicked position (unless the click is at an active selection).
- macOS, toggles the context menu if right click was at the same position as the previous / or selects word at position and opens context menu.
- iOS, selects word at position and opens context menu.
This change also prevents the `copy` menu button from being shown when there is a collapsed selection (nothing to copy).
Fixes#117561
This is a second attempt to merge #107269. Currently I've fixed two of the issues:
1. Fixed horizontal scrollview by using a switch statement to consider vertical/horizontal case.
2. Fixed issue of `paintExtent` not being the right extent for painting. Rather using a `scrollExtent` for the main axis length of the decoration box and painting it offsetted by the `scrollOffset`.
3. If the sliver child has inifinite scrollExtent, then we only draw the decoration down to the bottom of the `cacheExtent`. The developer is expected to ensure that the border does not creep up above the cache area.
This PR includes a test that checks that the correct rectangle is drawn at a certain scrollOffset for both the horizontal and vertical case which should be sufficient for checking that `SliverDecoration` works properly now.
Fixes https://github.com/flutter/flutter/issues/107498.
This is a refactor to make `MouseTracker` use the same callback for both kinds of device update. Instead of using two different callbacks for the two device updating methods, `MouseTracker` now receives a hit testing callback at construction, which is the same hit testing method as the one used for other gestures.
This PR not only makes the code cleaner, but also removes the single view assumption from `MouseTracker`, whose code no longer refers to `RendererBinding.renderView`. In the future, we only need to modify `hitTest` (which we will have to do to support gestures for multi-view anyway) to make mouse tracker support multi-view.
Many parts of the floating cursor selection feature is pretty tricky. Some took me a while to figure out. So I added some comments to explain a bit for future readers.
*List which issues are fixed by this PR. You must list at least one issue.*
https://github.com/flutter/flutter/issues/30476
*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
Close https://github.com/flutter/flutter/issues/126303
When I encounter bugs in production environment saying null pointer error on `return _size!`, I wish I could know more information! However, currently the information is revealed by `assert(hasSize, 'RenderBox was not laid out: $this');`, thus *only* in debug mode can I know what is `this` (and/or more information that can be added), while in release mode I can only see a stack trace saying it is `RenderBox.size` that throws - nothing more :/
Therefore, it is intuitive to add this extra information in release mode. However, will it affect performance? We all know this is in critical path and should be quite careful. Thus I did some experiments: https://godbolt.org/z/zPPPf5969 From my naive understanding of assembly, the two versions of code (`size!` vs `size ?? throw`) has the same assembly, except that they throw different types of errors. In other words, when there is no error, both code should be equivalent; when there is an error, surely the new code will be slower since it calls `this.toString()`, but the error handling process is rare and already heavy, so this is not a problem.

Fixes#127076
Sometimes a `Selectable`s rect may contain another `Selectable`s rect within it. In the case of `handleSelectWord` when choosing which `Selectable` to dispatch the `SelectionEvent` to, the event would be dispatched to the wrong `Selectable` causing an assertion error to be thrown.
<img width="577" alt="Screenshot 2023-05-24 at 2 46 13 AM" src="https://github.com/flutter/flutter/assets/948037/bb246966-acad-4d81-bd87-758c3ea6ea39">
In the picture above the red outline shows the rect of a two-line piece of text. And the blue rect shows the rect of a piece of text that is on the second line of the two-line piece of text, but has been separated into its own rect for some case, for example when `TextSpan`s are separated by a `WidgetSpan`.
We should check if the text layout of the selectable that has been dispatched the SelectionEvent contains the word, if not then return `SelectionResult.next`, and continue to look through the list of selectables.
This workaround was created 6 years ago with no links to bug databases to track. As best we can determine, the issue is no longer present in SkPicture or DisplayList and is most likely obsolete. More importantly, though, non-rendering primitives are ignored by the DisplayList construction and so this workaround will just be ignored anyway. If a problem surfaces about this issue that we haven't discovered by a thorough code search of the current code base, then workarounds should be installed within the relevant implementation modules rather than in the framework (and documented with bugs filed in either or both of Flutter's github repos, and/or the Skia issue database).
Workaround originally created in this PR: https://github.com/flutter/flutter/pull/9654
In the multi view world, `RenderViews` are created by the `View` widget and no longer owned by the binding. Prior to this change, the `LiveTestWidgetsFlutterBinding` owned and managed a special subclass of `RenderView`, the `_LiveTestRenderView`. In the new world, where `RenderView`s can be created anywhere in the widget tree where a `View` widget is used, this setup is no longer feasible. This change removes this special `_LiveTestRenderView` and instead adds debug hocks to `RenderView` to allow the `LiveTestWidgetsFlutterBinding` to draw a debug overlay on top of the content of any `RenderView`.
Syncs our lints with https://github.com/dart-lang/linter/blob/master/example/all.yaml:
* removed the deprecated `iterable_contains_unrelated_type` and `list_remove_unrelated_type` lints (their replacement `collection_methods_unrelated_type` was already enabled for us)
* enabled the new `no_self_assignments` and fixed one issue triggered by the lint.
- Added `InlineWidgetContainerDefaults` for deduping inline widget code
- Added a helper function `WidgetSpan.extractFromInlineSpan` for extracting `WidgetSpan`s and automatically applying text scaling (at widget level)
- Removed `TextPainter.inlinePlaceholderScales`. I'm going to deprecate the `scale` argument in `TextPainter.addPlaceholder` next, as scaling is now done at the widget level.
- Added runtime check and comments to make sure nobody is extending `PlaceholderSpan` directly (unfortunately we can't remove `PlaceholderSpan` without moving RenderEditable and RenderParagraph to the widgets library).
Reverts flutter/flutter#127052, which seems to be breaking the build
because of a goldens failure.
```
The following TestFailure was thrown running a test:
Expected: one widget whose rasterized image matches golden image "shadow.PhysicalModel.enabled.png"
Actual: _WidgetTypeFinder:<exactly one widget with type "Container" (ignoring offstage widgets):
Container(bg: Color(0xfffff59d), margin: EdgeInsets.all(150.0))>
```
See
https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20web_tests_6/11051/overview
This workaround was created 6 years ago with no links to bug databases to track. As best we can determine, the issue is no longer present in SkPicture or DisplayList and is most likely obsolete. More importantly, though, non-rendering primitives are ignored by the DisplayList construction and so this workaround will just be ignored anyway. If a problem surfaces about this issue that we haven't discovered by a thorough code search of the current code base, then workarounds should be installed within the relevant implementation modules rather than in the framework (and documented with bugs filed in either or both of Flutter's github repos, and/or the Skia issue database).
Workaround originally created in this PR: https://github.com/flutter/flutter/pull/9654
This PR contains a series of minor changes to address issues that I happened to run into:
- Pretty-print errors triggered when handling events that are pending because of having locked event handling. Previously these were just dumped to the console.
- Add more documentation for `debugPaintPadding`.
- Add documentation to `Tween` saying how to implement it.
- Slight formatting changes in the scrollbar code to align some expressions.
- Since we convert ScrollMetricsNotifications to ScrollNotifications in various places, provide an explicit API to do this. This will make the behaviour consistent throughout, and makes the code easier to understand. Added a test for this.
- Clarifications to some of the BindingBase and SchedulerBinding documentation.
- Clarified some documentation in `flutter_test`'s `Finder` class.
I'd like to find out the `fontSize` of a `PlaceholderSpan`, and currently there doesn't seem to be a way to do `TextStyle` cascading in the framework:
`InlineSpan.visitChildren` traverses the entire `InlineSpan` tree using a preorder traversal, and nodes that don't have "content" will be skipped (https://master-api.flutter.dev/flutter/painting/InlineSpan/visitChildren.html):
> Walks this [InlineSpan](https://master-api.flutter.dev/flutter/painting/InlineSpan-class.html) and any descendants in pre-order and calls visitor for each span that has content.
which makes it impossible to do `TextStyle` cascading in the framework:
- `InlineSpan`s with a non-null `TextStyle` but has no content will be skipped
- `visitChildren` doesn't directly expose the hierarchy, it only gives information about the flattened tree.
This doesn't look like a breaking change, most internal customers are extending `WidgetSpan` which has a concrete implementation of the new method.
Alternatively I could create a fake `ui.ParagraphBuilder` and record the `ui.TextStyle` at the top of the stack when `addPlaceholder` is called. But `ui.TextStyle` properties are not exposed to the framework.
Engine PR: https://github.com/flutter/engine/pull/41593
This must land first
We should remove these, as they've been deprecated for a while. On the engine side of things, the physical model layer is the only one which requires the device pixel ratio, so deleting it will allow us to simplify the layer tree code in https://github.com/flutter/engine/pull/41559
during performLayout, active children's constraints were updated, but they weren't laid out again w.r.t their parent (ListWheelScrollView).
Fixes#123497