This enhances the overlay optimization by delaying combining pictures to get tighter bounds for the pictures that make up the scene, enabling more sophisticated optimization since we can determine if they intersect with platform views on a per-picture basis.
Fixes https://github.com/flutter/flutter/issues/149863
On a Macbook in Chrome in an example app with an infinite scrolling grid of platform views, this brings the ratio of dropped frames from 93% to 55% (roughly 4 fps to 30 fps).
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
In certain situations, semantics elements get assigned `pointer-events: none` when they aren't supposed to.
One such situation is when a text field has a [decoration error text](https://api.flutter.dev/flutter/material/InputDecoration/errorText.html). The semantics node become a container, and we always set `pointer-events: none` on container nodes.
This PR introduces an `acceptsPointerEvents` getter on `SemanticRole` and `SemanticBehavior` to control when `pointer-events` should be `all` or `none`.
Fixes https://github.com/flutter/flutter/issues/141975
This is placeholder stuff that I added before the rest of the API to prove that we can call the engine symbols.
Today this is totally redundant as Flutter GPU has a bunch of automated tests which exercise every FFI call.
Part of https://github.com/flutter/flutter/issues/150953.
Provide a way to get the required minimum uniform byte alignment when referencing uniform blocks in a device buffer. Allow the user to explicitly flush DeviceBuffers (necessary for devices without shared memory).
Reverts: flutter/engine#54949
Initiated by: eyebrowsoffire
Reason for reverting: Incorrect golden diffs on engine roll, see https://github.com/flutter/flutter/pull/155181
Original PR Author: eyebrowsoffire
Reviewed By: {harryterkelsen}
This change reverts the following previous change:
This PR refactors the scene builder's logic in order to more aggressively merge flutter content and platform view content together. This essentially covers the case discussed in this flutter issue: https://github.com/flutter/flutter/issues/149863
This optimization ensures that each picture or platform view is applied to the lowest possible slice in the scene, which avoids the proliferation of redundant slices and overlays in the scene.
ui.Canvas and ui.SceneBuilder now use the DlPath object directly from the ui.Path object. This results in increased sharing of the wrapper objects which then increases the sharing of both the converted Impeller paths and Skia's volatile flag.
The VolatilePathTracker mechanism is deleted and rather than count the number of frames that a path is stable for, instead we count the number of times it is used for rendering. If a path is used 100 times in a single frame, it will become non-volatile and start being cached almost immediately. The cached Impeller paths are now also tracked for all instances of the same path, rather than for each call site that originated from a DisplayList dispatch.
This PR refactors the scene builder's logic in order to more aggressively merge flutter content and platform view content together. This essentially covers the case discussed in this flutter issue: https://github.com/flutter/flutter/issues/149863
This optimization ensures that each picture or platform view is applied to the lowest possible slice in the scene, which avoids the proliferation of redundant slices and overlays in the scene.
This removes usages of the deprecated top-level `instantiate` and
`invoke` methods and replaces it by method calls to the embedder
objects.
See [0] for the change that introduce this embedder API.
[0] https://dart-review.googlesource.com/c/sdk/+/383242/6
Relands https://github.com/flutter/engine/pull/54917. The change is the same as before, except now the native resources for `SkwasmColorFilter` and `SkwasmImageFilter` classes are no longer GC'd. Instead, we use manually managed native handles (vended and scoped by `withRawColorFilter` and `withRawImageFilter`). The bug in the previous PR was that filter objects were disposed with the paint while the framework continued holding onto them. When GC kicked the finalization registry, it attempted to double-free the filters.
The Dart analyzer will soon be changed so that if the `default` clause
of a `switch` statement is determined to be unreachable by the
exhaustiveness checker, a new warning of type
`unreachable_switch_default` will be issued. This parallels the behavior
of the existing `unreachable_switch_case` warning, which is issued
whenever a `case` clause of a `switch` statement is determined to be
unreachable.
Before adding the new warning to the analyzer, code in the engine needs
to first be updated to eliminate these unreachable `default` clauses, so
that the warning won't cause builds to break.
For more information, see
https://github.com/dart-lang/sdk/issues/54575.
In [some cases][1], text editing utilities re-focus the `<input />` element during a blur event. This causes an unusual sequence of `focusin` and `focusout` events, leading to the engine sending unintended events.
Consider the following HTML code:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<input type="" value="1" id="input1">
<input type="" value="2" id="input2">
<input type="" value="3" id="input3">
</div>
<script>
container.addEventListener('focusin', (ev) => {
console.log('focusin: focus was gained by', ev.target);
});
container.addEventListener('focusout', (ev) => {
console.log('focusout: focus is leaving', ev.target, 'and it will go to', ev.relatedTarget);
});
</script>
</body>
</html>
```
Clicking input1, then input2, then input3 produces the following console logs:
```
// Input1 is clicked
focusin: focus was gained by <input type value=â"1" id=â"input1">â
// Input2 is clicked
focusout: focus is leaving <input type value=â"1" id=â"input1">â and it will go to <input type value=â"2" id=â"input2">â
focusin: focus was gained by <input type value=â"2" id=â"input2">â
// Input3 is clicked
focusout: focus is leaving <input type value=â"2" id=â"input2">â and it will go to <input type value=â"3" id=â"input3">â
focusin: focus was gained by <input type value=â"3" id=â"input3">â
```
Now, let's add a blur handler that changes focus:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<input type="" value="1" id="input1">
<input type="" value="2" id="input2">
<input type="" value="3" id="input3">
</div>
<script>
container.addEventListener('focusin', (ev) => {
console.log('focusin: focus was gained by', ev.target);
});
container.addEventListener('focusout', (ev) => {
console.log('focusout: focus is leaving', ev.target, 'and it will go to', ev.relatedTarget);
});
input2.addEventListener('blur', (ev) => {
input2.focus();
});
</script>
</body>
</html>
```
The log sequence changes and gives the wrong impression that no dom element has focus:
```
// Input1 is clicked
focusin: focus was gained by <input type value=â"1" id=â"input1">â
// Input2 is clicked
focusout: focus is leaving <input type value=â"1" id=â"input1">â and it will go to <input type value=â"2" id=â"input2">â
focusin: focus was gained by <input type value=â"2" id=â"input2">â
// Input3 is clicked, but the handler kicks in and instead of the following line being a focusout, it results in a focusin call first.
focusin: focus was gained by <input type value=â"2" id=â"input2">â
focusout: focus is leaving <input type value=â"2" id=â"input2">â and it will go to null
```
In addition to that, during `focusout` processing, `activeElement` typically points to `<body />`. However, if an element is focused during a `blur` event, `activeElement` points to that focused element. Although, undocumented it can be verified with:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<input type="" value="1" id="input1">
<input type="" value="2" id="input2">
<input type="" value="3" id="input3">
</div>
<script>
container.addEventListener('focusin', (ev) => {
console.log('focusin: was gained by', ev.target);
});
container.addEventListener('focusout', (ev) => {
console.log('document.hasFocus()', document.hasFocus());
console.log('document.activeElement', document.activeElement);
console.log('focusout: focus is leaving', ev.target, 'and it will go to', ev.relatedTarget);
});
input2.addEventListener('blur', (ev) => {
input2.focus();
});
</script>
</body>
</html>
```
We leverage these behaviors to ignore `focusout` events when the document has focus but `activeElement` is not `<body />`.
https://github.com/flutter/flutter/issues/153022
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Adds the `crossOrigin` property to the `<img>` tag used for decoding. This allows us to use cross-origin images in CanvasKit as if it were loaded from the same origin, as long as the CORS headers are properly set on the server hosting the image.
In the case where the image doesn't have proper CORS headers, this change causes an error to occur while attempting to decode, rather than later on in Skia when the image is converted into a texture. Hitting the cross-origin error later causes Skia to behave in undefined ways.
Progress towards https://github.com/flutter/flutter/issues/149843
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Do not eagerly create an `SkPaint` object that's strongly referenced by `CkPaint`. Instead, when a `Canvas.draw*` is called, create a temporary `SkPaint` object, pass it to Skia, then immediately delete it. This way there are no persistent `SkPaint` handles lurking in the system that transitively hold onto expensive native resources.
Addresses the `Paint` issue in https://github.com/flutter/flutter/issues/153678 in CanvasKit
Spot checking some benchmarks. Here's the effect of this PR on `draw_rect_variable_paint`. It's a bit of a stress test as it creates 300K distinct `Paint` objects to render 600 pictures (a typical ratio does not normally exceed ten paints to one picture). Even so, the effect of creating an extra `SkPaint` on every `draw*` command does not look significant. However, removing a dependency on the GC for 300K objects looks like a good trade-off.
## Before
Allocation stats:
```
Paint Created: 300000
Paint Deleted: 300000
Paint Leaked: 300000
Picture Created: 600
Picture Deleted: 599
Picture Leaked: 599
```
Performance stats:
```
windowRenderDuration: (samples: 98 clean/2 outliers/100 measured/300 total)
| average: 4679.551020408163 μs
| outlier average: 5100 μs
| outlier/clean ratio: 1.0898481452084188x
| noise: 3.11%
sceneBuildDuration: (samples: 98 clean/2 outliers/100 measured/300 total)
| average: 4689.765306122449 μs
| outlier average: 5100 μs
| outlier/clean ratio: 1.087474461321549x
| noise: 3.19%
drawFrameDuration: (samples: 97 clean/3 outliers/100 measured/300 total)
| average: 8447.474226804125 μs
| outlier average: 9332.666666666666 μs
| outlier/clean ratio: 1.1047878236850721x
| noise: 3.52%
```
## After
Allocation stats:
```
Picture Created: 600
Picture Deleted: 599
Picture Leaked: 599
```
Performance stats:
```
windowRenderDuration: (samples: 97 clean/3 outliers/100 measured/300 total)
| average: 4780.40206185567 μs
| outlier average: 5133.666666666667 μs
| outlier/clean ratio: 1.0738985131877936x
| noise: 2.70%
sceneBuildDuration: (samples: 97 clean/3 outliers/100 measured/300 total)
| average: 4787.6082474226805 μs
| outlier average: 5133.666666666667 μs
| outlier/clean ratio: 1.0722821085936345x
| noise: 2.72%
drawFrameDuration: (samples: 97 clean/3 outliers/100 measured/300 total)
| average: 8243.309278350516 μs
| outlier average: 9033.333333333334 μs
| outlier/clean ratio: 1.0958382159768851x
| noise: 2.60%
```
Reverts: flutter/engine#54737
Initiated by: chingjun
Reason for reverting: Breaking internal tests. See b/363125155
Original PR Author: gaaclarke
Reviewed By: {matanlurey, jonahwilliams}
This change reverts the following previous change:
[This PR](https://github.com/flutter/engine/pull/54415) was reverted because it requires a manual roll into the framework.
issue: https://github.com/flutter/flutter/issues/127855
integration test: https://github.com/flutter/engine/pull/54415
This does the preliminary work for implementing wide gamut colors in the Flutter framework. Here are the following changes: 1) colors now specify a colorspace with which they are to be interpreted 1) colors now store their components as floats to accommodate bit depths more than 8
The storage of this Color class is weird with float/int storage but that is a temporary solution to support a smooth transition. Here is the plan for landing this:
1) Land this PR
1) Wait for it to roll into the Framework
1) Land https://github.com/flutter/flutter/pull/153938 which will make CupertinoDynamicColor implement Color
1) Land another engine PR that rips out the int storage: https://github.com/flutter/engine/pull/54714
Here are follow up PRs:
1) https://github.com/flutter/engine/pull/54473 - changes DlColor so the wide gamut colors are rendered
1) https://github.com/flutter/engine/pull/54567 - Hooks up these changes to take advantage of wide DlColor
1) https://github.com/flutter/flutter/pull/153319 - the integration test for the framework repo
There are some things that have been left as follow up PRs since they are technically breaking:
1) The math on `lerp` hasn't been updated to take advantage of the higher bit depth
1) `operator==` hasn't been updated to take advantage of the higher bit depth
1) `hashCode` hasn't been updated to take advantage of the higher bit depth
1) `alphaBlend` hasn't been updated to take advantage of the higher bit depth
1) `toString` hasn't been updated to take advantage of the higher bit depth
[This PR](https://github.com/flutter/engine/pull/54415) was reverted because it requires a manual roll into the framework.
issue: https://github.com/flutter/flutter/issues/127855
integration test: https://github.com/flutter/engine/pull/54415
This does the preliminary work for implementing wide gamut colors in the Flutter framework. Here are the following changes: 1) colors now specify a colorspace with which they are to be interpreted 1) colors now store their components as floats to accommodate bit depths more than 8
The storage of this Color class is weird with float/int storage but that is a temporary solution to support a smooth transition. Here is the plan for landing this:
1) Land this PR
1) Wait for it to roll into the Framework
1) Land https://github.com/flutter/flutter/pull/153938 which will make CupertinoDynamicColor implement Color
1) Land another engine PR that rips out the int storage: https://github.com/flutter/engine/pull/54714
Here are follow up PRs:
1) https://github.com/flutter/engine/pull/54473 - changes DlColor so the wide gamut colors are rendered
1) https://github.com/flutter/engine/pull/54567 - Hooks up these changes to take advantage of wide DlColor
1) https://github.com/flutter/flutter/pull/153319 - the integration test for the framework repo
There are some things that have been left as follow up PRs since they are technically breaking:
1) The math on `lerp` hasn't been updated to take advantage of the higher bit depth
1) `operator==` hasn't been updated to take advantage of the higher bit depth
1) `hashCode` hasn't been updated to take advantage of the higher bit depth
1) `alphaBlend` hasn't been updated to take advantage of the higher bit depth
1) `toString` hasn't been updated to take advantage of the higher bit depth
With [1] dart2wasm started using the new Wasm built-in string import
`wasm:js-string`.
With [2] dart2wasm started exporting `compile` and `compileStreaming`
from the generated JS runtime to compile dart2wasm-generated modules
with the `wasm:js-string` built-in, polyfilling it when not available.
Update Wasm compilation code in Flutter to use `compileStreaming` from
the JS runtime, enabling fast `jwasm:js-string` module when available.
[1]: 44c2e17600
[2]: 4cd6096da4
Closes https://github.com/flutter/flutter/issues/152636.
As of this PR, we no longer cherry-pick specific directories to run `dart analyze` on.
A few trailing errors across the repo had to be fixed in this PR.
Previously the "dialog" ARIA role was only set if the route or any of its descendants had the `namesRoute` flag. This PR sets the ARIA role unconditionally. Although it's always a good idea to have a label on the route, a missing label doesn't change the fact that the route is a route, so the ARIA role should still be set.
Fixes https://github.com/flutter/flutter/issues/153791
Remember the timestamp of _all_ `pointerup` events, not just those that were flushed. Clicks should be deduplicated after a `pointerup` even when not debouncing anything. This is because when not debouncing the engine already forwards all the pointer events to the framework, and sending click events on top only causes double-clicks.
Fixes https://github.com/flutter/flutter/issues/147050
Fixes https://github.com/flutter/flutter/issues/153623
Fixes https://github.com/flutter/flutter/issues/153788
* Avoids slow CPU resizer
* Avoids us having to write any code at all to resize these images
* Avoids reading from the GPU staging buffers that are not read cached (similar to Glyph cache performance issues).
Also changes the single frame codec upload to either use the device private storage path or to defer upload until the GPU returns. This allows us to ensure that mips are always constructed and makes sure that we don't need to keep around the CPU texture reisze that depends on the Skia software backend.
Separately, I updated the deferred task system to allow separate success/failure tasks to make it easier to track the final state.
The `type` attribute is needed for screen readers to tell the user whether the text field is a password or a plain text field.
Use `-webkit-text-security` for multi-line fields as a best effort (it's non-standard but is supported by all major browsers).
Fixes https://github.com/flutter/flutter/issues/153801
This removes the dependency on `dart:js` and allows that library to be removed from dart2wasm. Also updates `test` dependencies to work with the new `package:js` constraints.