1628 Commits

Author SHA1 Message Date
Jackson Gardner
d159d6cfc8 Initial support for images in Skwasm (flutter/engine#42019)
This partially implements https://github.com/flutter/flutter/issues/126341

It does not implement image codecs, because they are going to get complicated with transferring video frames to the web worker and so on. I am going to deal with image codecs in a subsequent change.
2023-05-16 18:35:17 +00:00
Jackson Gardner
148b626638 Use new unresolvedCodePoints API from skia. (flutter/engine#41991)
NOTE: this works off of a skia CL that is not merged yet, so we shouldn't merge this until it actually lands in skia and rolls into the engine. See https://skia-review.googlesource.com/c/skia/+/695716
2023-05-16 18:33:12 +00:00
Jackson Gardner
4daa0909c2 Compile skwasm at -Oz. (flutter/engine#42002)
We want to start from a place of small size, and optimize from there with skwasm. Since there is no baseline expectation of performance at `-O3`, let's start with the smallest possible binary.
2023-05-15 19:59:14 +00:00
Kevin Lubick
0946d27add Migrate uses of SkSurface factories (flutter/engine#41978)
In http://review.skia.org/687639, many SkSurface static methods were moved and one was deleted (SkSurface::MakeRasterN32Premul). (SkSurface::MakeNull was omitted accidentally and http://review.skia.org/696537glesource.com/c/skia/+/696537 has not rolled into Flutter yet)

This changes the calls in Flutter to match those moved functions. There should be no functional difference and everything was done pretty mechanically (e.g. find and replace)

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
2023-05-15 16:41:10 +00:00
Mouad Debbar
7b3b362623 [web] Cleaner output on LUCI (flutter/engine#41989)
Using ansi colors in LUCI results in output that looks like:
```
00:00 +0: loading flutter_tester_emulation_golden_test.dart                                                                                                                                            
00:01 +0: loading flutter_tester_emulation_golden_test.dart                                                                                                                                            
00:02 +0: loading flutter_tester_emulation_golden_test.dart
```

This PR disables colors on LUCI so that we get clean output that's easily scannable and searchable.
2023-05-12 21:50:22 +00:00
Bruno Leroux
fea415faa0 [Web+Linux] Fix pressing Meta keys throws (flutter/engine#41694)
## Description

This PR fixes Meta keys throwing exception on Chrome Linux.

The assertions throws because the DOM event sent when Meta keys is pressed is not coherent when Meta is the only pressed key.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/125672

## Tests

Adds 1 test.
2023-05-12 21:46:17 +00:00
Mouad Debbar
e87d7155d2 [web] Fix crash on old versions of Chrome (Intl.Segmenter missing) (flutter/engine#41986)
`Chrome < v87` have the `v8BreakIterator` API but don't have `Intl.Segmenter`. This caused crashes for some apps (see b/281377168).

This PR enhances our feature detection to take into account this API mismatch.
2023-05-12 19:59:30 +00:00
Jackson Gardner
d03ba5aacb Return fonts in a deterministic order. (flutter/engine#41907)
We need to make sure to return fonts in the order we passed them in, so that unit tests don't flake if they load in a different order.
2023-05-11 05:13:03 +00:00
Srujan Gaddam
df4bd5d036 Turn @staticInterop tear-off into closure (flutter/engine#41885)
@staticInterop members will start disallowing tear-offs, so this member should turn into a closure.

The static check wasn't added in time, so this is modifying the source code again.

ee3ce32c7c was the original change, but the static error didn't make it into the Dart SDK, so this is fixing another tear-off.

- [] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on writing and running engine tests.
2023-05-11 00:18:14 +00:00
Mouad Debbar
9fce37c015 [web] Expose PlatformLocation and HashUrlStrategy through ui_web (flutter/engine#41163)
1. Expose `PlatformLocation` and its subclass `BrowserPlatformLocation` through the new `ui_web`.
2. Expose `HashUrlStrategy` too. It's useful for users who want to extend and customize it instead of building their own from scratch.
3. `ui_web/url_strategy.dart` => `ui_web/navigation/url_strategy.dart`.
2023-05-10 23:57:46 +00:00
Yegor
bdfce08b64 [web] generalize focusability in semantics (flutter/engine#41831)
Introduce 2 new classes for a11y focus management:

* `AccessibilityFocusManager`: a generic class that attaches "focus" and "blur" event handlers, and forwards the events to the framework as `SemanticsAction.didGainAccessibilityFocus` and `SemanticsAction.didLoseAccessibilityFocus` respectively. Provides the `changeFocus` method for the framework to move a11y focus to the target element.
* `Focusable`: a role manager that provides generic focus management functionality to `SemanticsObject`s that don't need anything special.

Rewrites focus management using the above two classes as follows:

* All focusable nodes except text fields and incrementables get the `Focusable` role (all custom focus stuff in `Tappable` was removed and delegated to `Focusable`).
* `Incrementable` uses a custom `<input>` internally and so it cannot use the `Focusable` role. Instead, it uses `AccessibilityFocusManager` to manage the focus on the `<input>` element.

Behavioral changes:

* Fixes https://github.com/flutter/flutter/issues/118737, but more generally fixes all nodes that use the `isFocusable` and `hasFocus` bits.
* `Tappable` only partially implemented focusability (e.g. it didn't generate the respective `SemanticsAction` events). Now by delegating to `Focusable`, it will inherit all the functionality.
* `Incrementable` and `Checkable` (checkboxes, radios, switches) get focus management features for the first time.
* Elements that are not inherently focusable (text, images) can now be focused if semantics requires them to be.
* `TextField` is left alone for now as focus and on-screen keyboard interact with each other in non-obvious ways.
2023-05-10 22:40:20 +00:00
Mouad Debbar
fdb4e5468d [web] Re-enable history tests on Safari (flutter/engine#41901)
Fixes https://github.com/flutter/flutter/issues/51169
2023-05-10 19:58:05 +00:00
Yegor
0e9f0ef05f [web] dialog a11y fixes (flutter/engine#41681)
Fixes two issues in dialog accessibility:

* Fixes https://github.com/flutter/flutter/issues/45207 by setting `role="dialog"` on nodes that have both `scopesRoute` and `namesRoute` set. There's no guarantee that this combination of flags is an actual dialog, but it's close enough, and it makes the screen reader announce the appearance of the dialog. Note that `scopesRoute` alone is not sufficient, because Flutter uses it for overlays that are not semantically dialogs, such as dismiss barriers.
* Fixes an issue with focus management, where focus fails to transfer to background content after the dialog is dismissed. This happened because `EngineSemanticsOwner._semanticsTree` retained descendants of parents that were removed. This is benign in many cases. However, for focus this is problematic because the HTML element can go away and come back (losing focus along the way), but its corresponding `SemanticsObject` is never marked as "dirty" and fails to update and request focus.

I'm hoping this is sufficient to fix b/251839784 as well. Will work with the relevant team to find out.
2023-05-10 05:02:22 +00:00
Jackson Gardner
3c85b2e565 Implement text rendering in Skwasm (flutter/engine#41832)
This implements full text rendering with the Skwasm renderer.

The font fallback logic has been refactored to decouple the font fallback manager from any CanvasKit-specific types and functions.

A chunk of CanvasKit text rendering tests have been ported over to the renderer-agnostic `ui` tests.

Fixes https://github.com/flutter/flutter/issues/126339
2023-05-09 23:37:21 +00:00
Jackson Gardner
5c98a397a2 Get rid of "outrageous" default text styles for HTML renderer. (flutter/engine#41822)
The CanvasKit renderer doesn't do this, so we should just remove the red text global style.
2023-05-08 22:59:21 +00:00
Jackson Gardner
16360e9e25 Reland "Skwasm Font Loading (flutter/engine#41756)
This relands https://github.com/flutter/engine/pull/41246, which had to be reverted due to some issues parsing the font manifest.
2023-05-08 18:17:22 +00:00
Dan Field
ea5131772d Add a Display API to dart:ui that reports the physical size, DPR, and refresh rate of the main display (flutter/engine#41685)
Fixes https://github.com/flutter/flutter/issues/123307 - for Android, iOS, and Web, for the main display only (https://github.com/flutter/flutter/issues/125938 tracks supporting multiple displays, https://github.com/flutter/flutter/issues/125939 for desktop).

Desktop will need to be implemented for this, but given priority for a couple of our customers targetting foldable devices on Android I'm inclined to get this in before desktop can be finished.

The main concern for this right now is that on some Android foldable devices, setting a preferred orientation will cause letterboxing and the `MediaQuery` will _never_ get the full screen size when unfolded. This causes apps to think the screen is smaller than it is, as they've mainly been using `MediaQueryData.size` to figure this out. Android's recommendation is to not set a preferred orientation, and if you must to use the new method introduced in `ViewUtil.java` to calculate the maximal window size.
2023-05-06 18:28:22 +00:00
Jackson Gardner
f2970b73b0 Revert "Skwasm Font Loading" (flutter/engine#41750)
Reverts flutter/engine#41246

The new font manifest parsing fails in some cases.
2023-05-04 23:54:18 +00:00
Jackson Gardner
6f5ad9737e Skwasm Font Loading (flutter/engine#41246)
This implements font loading for the skwasm renderer.

In addition, it does some pretty major refactors:
1) Simplified the font collection interface to just have a single `loadAssetFonts` call, without the separate registration and debug fonts loading stuff
2) Debug fonts load now through http/asset mocking mechanisms instead of having a separate `downloadDebugTestFonts` call
3) Consolidated a few of our different unit test setup functions into a single `setUpUnitTests` function
2023-05-04 18:22:53 +00:00
Jackson Gardner
5189eda98b Populate fallback fonts from CIPD in tests (flutter/engine#41656)
This fixes https://github.com/flutter/flutter/issues/85793

The script that generates the font fallback data also rolls a package to CIPD with these files and updates the DEPS to download those files from CIPD. This makes sure that these tests are hermetic.
2023-05-04 05:12:54 +00:00
Jonah Williams
dfff522046 Remove physical model layer (flutter/engine#41593)
Removes the physical model layer and associated engine code. This was already deprecated and removed in the framework. By removing it in the engine, we can also remove the need for layer tree diff/paint/preroll to have the device pixel ratio. This will simplify some of the multi-view work

Fixes https://github.com/flutter/flutter/issues/125720
2023-05-03 20:28:53 +00:00
Mouad Debbar
9ed3f6008e [web] Improve null safety for color->css (flutter/engine#41699)
Turning `colorToCssString` into an extension method on `ui.Color` improves null safety and developer ergonomics.
2023-05-03 18:15:04 +00:00
Mouad Debbar
9cb01b94d5 [web] Remove unused function parameter (flutter/engine#41700)
The `hasAutofillOverlay` and `cssSelectorPrefix` parameters aren't really used in any useful way. Let's remove them.
2023-05-03 17:57:21 +00:00
Bruno Leroux
d56b8bee57 Web - Fix selection jump on Chrome for Android (flutter/engine#41202)
## Description

This PR fixes cursor jump on Chrome for Android when the user taps in a multiline `TextField`.

Using the following code sample:

<details><summary>Code sample</summary>

```dart

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Text Field Focus',
      home: MyCustomForm(),
    );
  }
}

// Define a custom Form widget.
class MyCustomForm extends StatelessWidget {
  const MyCustomForm({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Text Field Focus'),
      ),
      backgroundColor: Colors.amber,
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: TextField(
          decoration: const InputDecoration(
            fillColor: Colors.white,
            filled: true
          ),
          autofocus: true,
          maxLines: 3,
          controller: TextEditingController(text: '1\n2\n3\n4\n'),
        ),
      ),// This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

```
</details>

On a mobile browser, once the page is loaded, tap after the number 3: 

- Before this PR: the TextField content is automaticaly scrolled and the selection is set after number 1.

https://user-images.githubusercontent.com/840911/232051413-b913f890-6cb1-4c60-92d0-7a3bf74cc688.mov

## Implementation

A multiline `TextField` relies on an HTML `<textarea>` elements. When a tap occurs the selection should be updated from Flutter not by the HTML element itself. 
This PR prevents mouse events on Chrome for Android. Those events conflicts with Flutter selection changes.
Previously, mouse events were only prevented on desktop but they are also emitted on mobile, see https://bugs.chromium.org/p/chromium/issues/detail?id=119216#c11.

## Related Issue

Related to https://github.com/flutter/flutter/issues/124483 (partial fix because the issue is also reproducible on iOS/Safari).

## Tests

Adds 1 test.
2023-05-02 19:34:35 +00:00
Srujan Gaddam
08ab47dddf Turn @staticInterop tear-off into closure (flutter/engine#41643)
@staticInterop members will start disallowing tear-offs, so this member
should turn into a closure.

Unblocks a roll in the SDK that disallows tear-offs.

## Pre-launch Checklist

- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [X] I added new tests to check the change I am making or feature I am
adding, or Hixie said the PR is test-exempt. See [testing the engine]
for instructions on writing and running engine tests.
- [X] I updated/added relevant documentation (doc comments with `///`).
- [X] I signed the [CLA].
- [X] All existing and new tests are passing.
2023-05-01 16:18:32 -07:00
Srujan Gaddam
e253aeff60 Remove package:js references and move to dart:js_interop (flutter/engine#41212)
dart:js_interop and package:js will start conflicting. Eventually, we
want people to only use dart:js_interop, so this CL refactors code to do
that.

Unblocks https://dart-review.googlesource.com/c/sdk/+/294130/8 and
prevents confusing shadowing of dart:js_interop annotations like we do
today.

## Pre-launch Checklist

- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [Mentioned CL that is unblocked] I listed at least one issue that this
PR fixes in the description above.
- [X] I updated/added relevant documentation (doc comments with `///`).
- [Need test-exemption] I added new tests to check the change I am
making, or this PR is [test-exempt].
- [X] All existing and new tests are passing.
2023-04-25 12:20:12 -07:00
David Iglesias
dfd9ef5e60 [web] Fix HashUrlStrategy.addPopStateListener (flutter/engine#41384)
During a JS-interop refactor, we introduced a small bug in the `addPopStateListener` method of the `HashUrlStrategy` object (web).

This wasn't caught before because the existing tests were mocking the refactored code.

## Issues

Fixes: https://github.com/flutter/flutter/issues/125228

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
2023-04-21 17:26:31 +00:00
maRci002
da6f9f69f2 [web] change status bar color based on SystemUiOverlayStyle (flutter/engine#40599)
Closes flutter/flutter#123365

In my [example code](https://github.com/flutter/flutter/issues/123365#issue-1638490447) I'm using `SystemUiOverlayStyle.dark` which has `null` `statusBarColor` by default (_which can be changed via `Change status bar color` button_) in this case we do not override browser's default status bar color.

| Old behaviour | New behaviour |
| -- | -- |
| <video src="https://user-images.githubusercontent.com/8436039/227386349-e30cce47-ffc6-4465-bb30-cd2888f77d32.mp4" /> | <video src="https://user-images.githubusercontent.com/8436039/227580430-a25e57dc-9d5a-43a1-bcb3-3bd8abd753d8.mp4" /> |

In case of PWA the when `statusBarColor` is `null` it will use `theme_color` property from `manifest.json` (I don't know from where does flutter generate `manifest.json`).

The default status bar color for PWA is: `"theme_color": "#0175C2",`
f4caee6efb/examples/api/web/manifest.json (L7)

| Old PWA behaviour | New PWA behaviour |
| -- | -- |
| <video src="https://user-images.githubusercontent.com/8436039/227607373-79be7294-d9f7-4a45-9014-28720acce0c7.mp4" /> | <video src="https://user-images.githubusercontent.com/8436039/227607329-be16131f-4104-419a-8e16-2b229d73d95e.mp4" /> |

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
2023-04-20 14:33:07 +00:00
joshualitt
90138c2003 [web] Fix trivial type issue. (flutter/engine#40956) 2023-04-19 12:58:30 -07:00
Mouad Debbar
2bc352f431 [web] Remove non-ShadowDom mode (flutter/engine#39915)
If we still want to do this, here's a quick PR :)

Fixes https://github.com/flutter/flutter/issues/116204
2023-04-19 16:15:21 +00:00
Yegor
d5474b17ac [web:canvaskit] remove unnecessary instrumentation from picture (flutter/engine#41313)
Remove unnecessary instrumentation from picture. `UniqueRef`
automatically instruments all allocations, disposals, and garbage
collections, which covers `CkPicture`.
2023-04-18 16:49:00 -07:00
Yegor
1289bfa247 [web:canvaskit] clean up the rest of skia_object_cache usages (flutter/engine#41259)
This should go after https://github.com/flutter/engine/pull/41230.

Removes the remaining usages of `skia_object_cache.dart` and deletes it.

Also fixes https://github.com/flutter/flutter/issues/86632
2023-04-18 14:34:01 -07:00
Yegor
2fcdf5a731 [web:canvaskit] migrate Paint API to UniqueRef (flutter/engine#41230)
Migrate Paint API to `UniqueRef`. This includes `Paint`, `ImageFilter` (and all subtypes), `ColorFilter` (and all subtypes).

Also fix the following memory leaks:

* `CkPaint` is frequently used by layers where a one-off paint object is created, used, and immediately dropped. `CkPaint` now has a `dispose` method, and all one-off usages now dispose of the paint after they are done.
* `CkColorFilter.initRawImageFilter` was leaking the `SkColorFilter` created by `_initRawColorFilter` inside the expression.
* `CkManagedSkImageFilterConvertible.imageFilter` now takes a closure, which allows the implementation decide on the lifetime of the `SkImageFilter` vended to the caller. Because `CkColorFilter` is a const class it cannot store C++ instances inside its own fields, so it creates a temporary `SkImageFilter` class to be used by the caller and then it needs to delete it. Now it does.
2023-04-17 17:30:19 +00:00
Yegor
d1d577c2ae [web:canvaskit] move shaders to UniqueRef; fix minor memory leaks (flutter/engine#41172)
[web:canvaskit] move shaders to UniqueRef; fix minor memory leaks
2023-04-14 02:57:19 +00:00
LouiseHsu
7f3889d6b0 Revert "Add support for double tap action from Apple Pencil 2" (flutter/engine#41138)
Reverts flutter/engine#39637

Since this feature https://github.com/flutter/flutter/issues/73172 has
been scrapped for now, previous engine work should be reverted. Refer to
[this design
doc](https://docs.google.com/document/d/1r4P5r-jGt2Sjqro3ldCU2axUiHTpu3yhIycnI94OKQw/edit
) for more discussion and details.
2023-04-13 14:59:04 -07:00
Jackson Gardner
29eb026a0e Fix skwasm's canvasDrawArc declaration and write tests. (flutter/engine#41165)
Fix skwasm's canvasDrawArc declaration and write tests.
2023-04-13 21:26:17 +00:00
Jackson Gardner
fb0a83e944 Implement Gradient Shaders and Fragment Shaders in Skwasm (flutter/engine#41144)
Implement Gradient Shaders and Fragment Shaders in Skwasm
2023-04-13 20:58:46 +00:00
Yegor
aa5cde7646 [web:canvaskit] move path API to UniqueRef (flutter/engine#41136)
[web:canvaskit] move path API to UniqueRef
2023-04-12 23:52:26 +00:00
Jackson Gardner
56821f80e7 Don't use OffscreenCanvas in Safari, it doesn't support WebGL. (flutter/engine#41135)
Don't use `OffscreenCanvas` in Safari, it doesn't support WebGL.
2023-04-12 23:01:25 +00:00
Bernardo Ferrari
d87ae44e99 SemanticsAction / SemanticsFlag cleanup part 5 (flutter/engine#41126)
`SemanticsAction` / `SemanticsFlag` cleanup part 5
2023-04-12 20:10:05 +00:00
Jackson Gardner
28d9e0df0f Improve Wasm Debugging. (flutter/engine#41054)
Improve Wasm Debugging.
2023-04-12 00:52:04 +00:00
Jackson Gardner
4b8536c6e9 Implement shadows in the skwasm renderer. (flutter/engine#41056)
Implement shadows in the skwasm renderer.
2023-04-11 22:44:01 +00:00
htoor3
a5fdffa8c8 [web] - Move text editing nodes outside of shadowDOM, reland (flutter/engine#40968)
[web] - Move text editing nodes outside of shadowDOM, reland
2023-04-11 19:41:14 +00:00
Bernardo Ferrari
aa47305b4d SemanticsFlag/SemanticsAction cleanup (part 3) (flutter/engine#40567)
`SemanticsFlag`/`SemanticsAction` cleanup (part 3)
2023-04-10 22:32:03 +00:00
Jackson Gardner
34cfb4d663 Re-enable some wasm tests which have been fixed now. (flutter/engine#40931)
Re-enable some wasm tests which have been fixed now.
2023-04-10 20:15:52 +00:00
Jackson Gardner
439141c38d Skwasm scene (flutter/engine#40330)
Skwasm scene
2023-04-10 17:38:57 +00:00
Mouad Debbar
5d30f3f043 [web] Make 'Noto Color Emoji' opt-in (flutter/engine#40990)
[web] Make 'Noto Color Emoji' opt-in
2023-04-07 16:54:22 +00:00
htoor3
072045aa3d Revert "[web] Move text editing nodes outside of shadowDOM - reopened" (flutter/engine#40960)
Reverts flutter/engine#40904
2023-04-05 19:47:08 -07:00
htoor3
438394f01e [web] Move text editing nodes outside of shadowDOM - reopened (flutter/engine#40904)
[web] Move text editing nodes outside of shadowDOM - reopened
2023-04-05 23:42:21 +00:00
Yegor
7231a4d15c [web] fix SkFinalizationRegistry for dart2js (attempt 4) (flutter/engine#40938)
(this is attempt 4; details below)

Remove obsolete object caches and introduce a simpler way to manage
native objects:

* Remove the unused `SynchronousSkiaObjectCache`.
* Introduce new library `native_memory.dart` that's smaller and simpler
than `skia_object_cache.dart`.
* Introduce two types of native object references:
  * `UniqueRef` a reference with a unique Dart object owner.
* `CountedRef` a ref-counted reference with multiple Dart object owners.
* All native references use GC (via `FinalizationRegistry`) as a
back-up.
* The new library removes everything related to object resurrection that
was needed only in browsers that didn't support `FinalizationRegistry`.
All browsers support it now.
* Remove the ad hoc `SkParagraph` cache that predates the introduction
of `Paragraph.dispose`.
* Rewrite `CkParagraph` in terms of `UniqueRef`.
* Rewrite `CkImage` in terms of `CountedRef`; delete `SkiaObjectBox`.

This PR does not migrate all objects from the old
`skia_object_cache.dart` to `native_memory.dart`. That would be too big
of a change. The migration can be done in multiple smaller PRs.

This also removes a few unnecessary relayouts observed in
https://github.com/flutter/flutter/issues/120921, but not all of them
(more details in
https://github.com/flutter/flutter/issues/120921#issuecomment-1481958762)

## About attempt 4

More info about the revert of attempt 3 in
https://github.com/flutter/engine/pull/40937.

In this attempt I check that the browser supports `FinalizationRegistry`
before registering the object. This will allow the code to run in older
browsers, but there will be no protection from memory leaks when the app
fails to dispose of the respective objects.

## Benchmarks

Now that this landed in flutter/flutter I have some benchmark numbers
from the devicelab. The `text_out_of_picture_bounds` benchmark dropped
by 3-4x (lower is better):

<img width="358" alt="Screenshot 2023-04-04 at 6 13 06 PM"
src="https://user-images.githubusercontent.com/211513/229956170-a5399ed3-c779-4af0-babb-ea40440f96ff.png">

The repro provided in https://github.com/flutter/flutter/issues/123204
dropped from 110ms/frame to 10ms/frame.
2023-04-05 11:08:00 -07:00