From d48dbc5564346c33dd4fbd109690fbf7c9c5c489 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 28 May 2025 11:53:27 -0400 Subject: [PATCH 01/66] Roll Packages from 6eebe72ca397 to 5743798ede97 (1 revision) (#169586) https://github.com/flutter/packages/compare/6eebe72ca397...5743798ede97 2025-05-27 15619084+vashworth@users.noreply.github.com [file_selector_macos] Do not set nameFieldStringValue for NSOpenPanel (flutter/packages#9324) 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-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 4ee2635073465..9f1e57a5beb2a 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -6eebe72ca3975373a5fab06a009ec5ffeabdb495 +5743798ede9713b66c6e97d31d29e217af8ce958 From 6a15533bf04e8512fe6186a8876552a0e91f30e6 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Wed, 28 May 2025 10:55:00 -0500 Subject: [PATCH 02/66] Allow tests to use macOS 15.5 (#169536) Part of https://github.com/flutter/flutter/issues/167824 ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .ci.yaml | 30 +++++++-------- engine/src/flutter/.ci.yaml | 8 ++-- .../src/flutter/ci/builders/local_engine.json | 38 +++++++++---------- .../ci/builders/mac_android_aot_engine.json | 12 +++--- .../flutter/ci/builders/mac_clang_tidy.json | 14 +++---- .../flutter/ci/builders/mac_host_engine.json | 36 +++++++++--------- .../flutter/ci/builders/mac_ios_engine.json | 20 +++++----- .../ci/builders/mac_ios_engine_ddm.json | 8 ++-- engine/src/flutter/ci/builders/mac_unopt.json | 16 ++++---- 9 files changed, 91 insertions(+), 91 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index cbd47a3a03f95..7ad58fcc96ed5 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -142,7 +142,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none $flutter/osx_sdk : >- { @@ -158,7 +158,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none cpu: arm64 $flutter/osx_sdk : >- @@ -177,7 +177,7 @@ platform_properties: ] device_type: none mac_model: "Macmini8,1" - os: Mac-14 + os: Mac-14|Mac-15.5 tags: > ["devicelab", "hostonly", "mac"] $flutter/osx_sdk : >- @@ -194,7 +194,7 @@ platform_properties: [ {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -212,7 +212,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 device_type: none cpu: x86 $flutter/osx_sdk : >- @@ -227,7 +227,7 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: x86 device_type: "msm8952" mac_arm64_android: @@ -237,7 +237,7 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v1"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: arm64 device_type: "msm8952" @@ -249,7 +249,7 @@ platform_properties: {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: x86 device_type: "mokey" mac_arm64_mokey: @@ -259,7 +259,7 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v1"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: arm64 device_type: "mokey" @@ -270,7 +270,7 @@ platform_properties: {"dependency": "android_sdk", "version": "version:36v1"}, {"dependency": "open_jdk", "version": "version:21"} ] - os: Mac-14 + os: Mac-14|Mac-15.5 cpu: x86 device_type: "Pixel 7 Pro" mac_ios: @@ -284,7 +284,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14|Mac-15.1 + os: Mac-14|Mac-15.1|Mac-15.5 device_os: iOS-17|iOS-18 $flutter/osx_sdk : >- { @@ -301,7 +301,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "version:to_2025"} ] - os: Mac-14|Mac-15.1 + os: Mac-14|Mac-15.1|Mac-15.5 cpu: x86 device_os: iOS-17|iOS-18 $flutter/osx_sdk : >- @@ -319,7 +319,7 @@ platform_properties: {"dependency": "ruby", "version": "ruby_3.1-pod_1.13"}, {"dependency": "apple_signing", "version": "none"} ] - os: Mac-14|Mac-15.1 + os: Mac-14|Mac-15.1|Mac-15.5 cpu: arm64 device_os: iOS-17|iOS-18 $flutter/osx_sdk : >- @@ -5389,7 +5389,7 @@ targets: bringup: true timeout: 60 properties: - os: Mac-15 + os: Mac-15.3 device_os: iOS-18.4 $flutter/osx_sdk : >- { @@ -5458,7 +5458,7 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery__transition_perf_e2e_ios drone_dimensions: > - ["device_os=iOS-17|iOS-18","os=Mac-14", "cpu=x86"] + ["device_os=iOS-17|iOS-18","os=Mac-14|Mac-15.5", "cpu=x86"] - name: Mac_ios animated_blur_backdrop_filter_perf_ios__timeline_summary recipe: devicelab/devicelab_drone diff --git a/engine/src/flutter/.ci.yaml b/engine/src/flutter/.ci.yaml index 06a3a6f0ac2cb..4d0cd70f09d6f 100644 --- a/engine/src/flutter/.ci.yaml +++ b/engine/src/flutter/.ci.yaml @@ -30,7 +30,7 @@ platform_properties: {"dependency": "open_jdk", "version": "version:17"} ] device_type: none - os: Mac-14 + os: Mac-14|Mac-15.5 $flutter/osx_sdk : >- { "sdk_version": "16c5032a" @@ -449,7 +449,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14 + - os=Mac-14|Mac-15.5 - name: Mac clangd recipe: engine_v2/builder @@ -478,7 +478,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14 + - os=Mac-14|Mac-15.5 - cpu=x86 - name: Mac mac_ios_engine_ddm @@ -499,7 +499,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Mac-14 + - os=Mac-14|Mac-15.5 - cpu=x86 - name: Linux windows_android_aot_engine diff --git a/engine/src/flutter/ci/builders/local_engine.json b/engine/src/flutter/ci/builders/local_engine.json index 61ee3d8016a68..0c6fcfda69935 100644 --- a/engine/src/flutter/ci/builders/local_engine.json +++ b/engine/src/flutter/ci/builders/local_engine.json @@ -3,7 +3,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -70,7 +70,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -103,7 +103,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -136,7 +136,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -170,7 +170,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -206,7 +206,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -344,7 +344,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -377,7 +377,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -410,7 +410,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -494,7 +494,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -578,7 +578,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -610,7 +610,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -643,7 +643,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -676,7 +676,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -815,7 +815,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -899,7 +899,7 @@ { "cas_archive": false, "drone_dimensions": [ - "os=Mac-14", + "os=Mac-14|Mac-15.5", "device_type=none" ], "gclient_variables": { @@ -1037,7 +1037,7 @@ "name": "macos/wasm_release", "drone_dimensions": [ "device_type=none", - "os=Mac-14" + "os=Mac-14|Mac-15.5" ], "gclient_variables": { "download_android_deps": false, @@ -1067,7 +1067,7 @@ "name": "macos/wasm_debug_unopt", "drone_dimensions": [ "device_type=none", - "os=Mac-14" + "os=Mac-14|Mac-15.5" ], "gclient_variables": { "download_android_deps": false, diff --git a/engine/src/flutter/ci/builders/mac_android_aot_engine.json b/engine/src/flutter/ci/builders/mac_android_aot_engine.json index 17b794d4beaf5..05cb1c6888cad 100644 --- a/engine/src/flutter/ci/builders/mac_android_aot_engine.json +++ b/engine/src/flutter/ci/builders/mac_android_aot_engine.json @@ -22,7 +22,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -80,7 +80,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -140,7 +140,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -200,7 +200,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -258,7 +258,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -318,7 +318,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_clang_tidy.json b/engine/src/flutter/ci/builders/mac_clang_tidy.json index 29ff251b9658b..b3928b3dc358a 100644 --- a/engine/src/flutter/ci/builders/mac_clang_tidy.json +++ b/engine/src/flutter/ci/builders/mac_clang_tidy.json @@ -3,7 +3,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -36,7 +36,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -74,7 +74,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -129,7 +129,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -184,7 +184,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -239,7 +239,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -294,7 +294,7 @@ "recipe": "engine_v2/tester_engine", "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_host_engine.json b/engine/src/flutter/ci/builders/mac_host_engine.json index c8288e1c0ddc1..a0c6e3a09444e 100644 --- a/engine/src/flutter/ci/builders/mac_host_engine.json +++ b/engine/src/flutter/ci/builders/mac_host_engine.json @@ -18,7 +18,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -85,7 +85,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -141,7 +141,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -206,7 +206,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -257,7 +257,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -308,7 +308,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -371,7 +371,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -425,7 +425,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -478,7 +478,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -544,7 +544,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -601,7 +601,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -657,7 +657,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -723,7 +723,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -778,7 +778,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -833,7 +833,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -900,7 +900,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -958,7 +958,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -1015,7 +1015,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_ios_engine.json b/engine/src/flutter/ci/builders/mac_ios_engine.json index 1f264d9acb1d4..d16167cdca947 100644 --- a/engine/src/flutter/ci/builders/mac_ios_engine.json +++ b/engine/src/flutter/ci/builders/mac_ios_engine.json @@ -15,7 +15,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -62,7 +62,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -111,7 +111,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -158,7 +158,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -205,7 +205,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -252,7 +252,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -301,7 +301,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -352,7 +352,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -401,7 +401,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -450,7 +450,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json b/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json index 660da9467ae49..e3a39b920bbb1 100644 --- a/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json +++ b/engine/src/flutter/ci/builders/mac_ios_engine_ddm.json @@ -15,7 +15,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -64,7 +64,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -115,7 +115,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -164,7 +164,7 @@ { "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { diff --git a/engine/src/flutter/ci/builders/mac_unopt.json b/engine/src/flutter/ci/builders/mac_unopt.json index 7b964cbce1018..056a9dd5cf769 100644 --- a/engine/src/flutter/ci/builders/mac_unopt.json +++ b/engine/src/flutter/ci/builders/mac_unopt.json @@ -4,7 +4,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -57,7 +57,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -108,7 +108,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -165,7 +165,7 @@ ], "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -224,7 +224,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=x86" ], "gclient_variables": { @@ -281,7 +281,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -350,7 +350,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { @@ -418,7 +418,7 @@ }, "drone_dimensions": [ "device_type=none", - "os=Mac-14", + "os=Mac-14|Mac-15.5", "cpu=arm64" ], "gclient_variables": { From c08e9dff6865b91a3c20bb39980053951a6cae34 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 28 May 2025 10:55:01 -0500 Subject: [PATCH 03/66] Manually update vector_math package (#169476) Includes fixes and deprecations that will allow us to improve performance. --- dev/a11y_assessments/pubspec.yaml | 4 ++-- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/complex_layout/pubspec.yaml | 4 ++-- dev/benchmarks/imitation_game_flutter/pubspec.yaml | 4 ++-- dev/benchmarks/macrobenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/microbenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 4 ++-- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_views_layout/pubspec.yaml | 4 ++-- .../platform_views_layout_hybrid_composition/pubspec.yaml | 4 ++-- dev/benchmarks/test_apps/stocks/pubspec.yaml | 4 ++-- dev/integration_tests/android_engine_test/pubspec.yaml | 4 ++-- dev/integration_tests/android_semantics_testing/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 4 ++-- dev/integration_tests/channels/pubspec.yaml | 4 ++-- dev/integration_tests/deferred_components_test/pubspec.yaml | 4 ++-- dev/integration_tests/display_cutout_rotation/pubspec.yaml | 4 ++-- dev/integration_tests/external_textures/pubspec.yaml | 4 ++-- dev/integration_tests/flavors/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- .../ios_add2app_life_cycle/flutterapp/pubspec.yaml | 4 ++-- dev/integration_tests/ios_app_with_extensions/pubspec.yaml | 4 ++-- dev/integration_tests/ios_platform_view_tests/pubspec.yaml | 4 ++-- dev/integration_tests/keyboard_hot_restart/pubspec.yaml | 4 ++-- dev/integration_tests/new_gallery/pubspec.yaml | 4 ++-- dev/integration_tests/platform_interaction/pubspec.yaml | 4 ++-- dev/integration_tests/release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 4 ++-- dev/integration_tests/web/pubspec.yaml | 4 ++-- dev/integration_tests/web_compile_tests/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- dev/integration_tests/windows_startup_test/pubspec.yaml | 4 ++-- dev/manual_tests/pubspec.yaml | 4 ++-- dev/tools/android_driver_extensions/pubspec.yaml | 4 ++-- dev/tools/vitool/pubspec.yaml | 4 ++-- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 4 ++-- examples/flutter_view/pubspec.yaml | 4 ++-- examples/hello_world/pubspec.yaml | 4 ++-- examples/image_list/pubspec.yaml | 4 ++-- examples/layers/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 4 ++-- examples/platform_channel_swift/pubspec.yaml | 4 ++-- examples/platform_view/pubspec.yaml | 4 ++-- examples/splash/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 4 ++-- packages/flutter/pubspec.yaml | 4 ++-- packages/flutter/test_private/test/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_goldens/pubspec.yaml | 4 ++-- packages/flutter_localizations/pubspec.yaml | 4 ++-- packages/flutter_test/pubspec.yaml | 4 ++-- .../widget_preview_scaffold/lib/src/controls.dart.tmpl | 4 ++-- .../widget_preview_scaffold/lib/src/controls.dart | 4 ++-- .../widget_preview_scaffold/pubspec.yaml | 4 ++-- packages/flutter_web_plugins/pubspec.yaml | 4 ++-- packages/integration_test/example/pubspec.yaml | 4 ++-- packages/integration_test/integration_test_macos/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 61 files changed, 122 insertions(+), 122 deletions(-) diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml index 57c2fabf79d40..93ed4dc8e4a43 100644 --- a/dev/a11y_assessments/pubspec.yaml +++ b/dev/a11y_assessments/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -39,4 +39,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 4de15bb766baa..31186048464f0 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: d92e +# PUBSPEC CHECKSUM: d72b diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 5a93962ea7e8c..6c0188481b20b 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -88,4 +88,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: df02 +# PUBSPEC CHECKSUM: 7dfe diff --git a/dev/benchmarks/imitation_game_flutter/pubspec.yaml b/dev/benchmarks/imitation_game_flutter/pubspec.yaml index 171ad5feeb79f..d49e587085776 100644 --- a/dev/benchmarks/imitation_game_flutter/pubspec.yaml +++ b/dev/benchmarks/imitation_game_flutter/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -44,4 +44,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d34d +# PUBSPEC CHECKSUM: 684a diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 0ed004ef36151..2b472912b5ed1 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -215,4 +215,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: df02 +# PUBSPEC CHECKSUM: 7dfe diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index c5bce68f75dcd..3e5e6f40db8a1 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -142,4 +142,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 873f +# PUBSPEC CHECKSUM: 853c diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 480fa64302af8..7c3d893b5ce8f 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,4 +47,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 0c7c +# PUBSPEC CHECKSUM: 4c79 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index fec08c96a8155..582fc4e335747 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -65,7 +65,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -79,4 +79,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d68 +# PUBSPEC CHECKSUM: 2b65 diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 77c5d121d2d6b..e7a5396241c74 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webview_flutter: 4.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: f9ca +# PUBSPEC CHECKSUM: 94c7 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 33288ce9b305e..1d5b88bcdc6c7 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +86,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: df02 +# PUBSPEC CHECKSUM: 7dfe diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 85913a00c595f..2a750579b5153 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -82,4 +82,4 @@ flutter: generate: true uses-material-design: true -# PUBSPEC CHECKSUM: 07e8 +# PUBSPEC CHECKSUM: a4e5 diff --git a/dev/integration_tests/android_engine_test/pubspec.yaml b/dev/integration_tests/android_engine_test/pubspec.yaml index 4d49e4d155cf4..f3602ab482027 100644 --- a/dev/integration_tests/android_engine_test/pubspec.yaml +++ b/dev/integration_tests/android_engine_test/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c680 +# PUBSPEC CHECKSUM: 647d diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 0e9c1813b1ebb..f1fb328be410f 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b623 +# PUBSPEC CHECKSUM: b420 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 9a6182b4de3f2..683cb995d14d3 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -44,7 +44,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -96,4 +96,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4b9d +# PUBSPEC CHECKSUM: 649a diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index 0b72d18146568..8b059713dd84b 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -45,4 +45,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 597c +# PUBSPEC CHECKSUM: 8d79 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 42147f1d92d54..c33de1d4bd715 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/dev/integration_tests/display_cutout_rotation/pubspec.yaml b/dev/integration_tests/display_cutout_rotation/pubspec.yaml index bab2f32b39eac..9ea523419cefd 100644 --- a/dev/integration_tests/display_cutout_rotation/pubspec.yaml +++ b/dev/integration_tests/display_cutout_rotation/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: @@ -120,4 +120,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package -# PUBSPEC CHECKSUM: 4c82 +# PUBSPEC CHECKSUM: 807f diff --git a/dev/integration_tests/external_textures/pubspec.yaml b/dev/integration_tests/external_textures/pubspec.yaml index 5b72726edd1c3..3661c6d7ade23 100644 --- a/dev/integration_tests/external_textures/pubspec.yaml +++ b/dev/integration_tests/external_textures/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b175 +# PUBSPEC CHECKSUM: 4f72 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 27d356b076c01..cbc55d87d0122 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -87,4 +87,4 @@ flutter: flavors: - free -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index e51b8f1f97014..37879ec59e994 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: url_launcher_platform_interface: 2.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_web: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_windows: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_android: 2.8.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_avfoundation: 2.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_platform_interface: 6.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -273,4 +273,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: e06e +# PUBSPEC CHECKSUM: 396b diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index 4a43975bda9a4..a4826b357b835 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -104,4 +104,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: 59f1 +# PUBSPEC CHECKSUM: edee diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index a152704959671..1a5e57d7582c6 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -94,4 +94,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 8478 +# PUBSPEC CHECKSUM: 1975 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index a411871ef8511..3d1b58bd00b28 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/dev/integration_tests/keyboard_hot_restart/pubspec.yaml b/dev/integration_tests/keyboard_hot_restart/pubspec.yaml index 32c0d660cbf3c..dfd89dc70c8b7 100644 --- a/dev/integration_tests/keyboard_hot_restart/pubspec.yaml +++ b/dev/integration_tests/keyboard_hot_restart/pubspec.yaml @@ -15,9 +15,9 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: e5c4 diff --git a/dev/integration_tests/new_gallery/pubspec.yaml b/dev/integration_tests/new_gallery/pubspec.yaml index 03779e6946ac2..99d281f07d589 100644 --- a/dev/integration_tests/new_gallery/pubspec.yaml +++ b/dev/integration_tests/new_gallery/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: scoped_model: 2.0.0 shrine_images: 2.0.2 url_launcher: 6.3.1 - vector_math: 2.1.4 + vector_math: 2.2.0 async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -312,4 +312,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: d3dd +# PUBSPEC CHECKSUM: ecda diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index b7eb6379f103d..1c95a26232abd 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b175 +# PUBSPEC CHECKSUM: 4f72 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 7288e92330ff5..86111bf329527 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -36,4 +36,4 @@ dev_dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index e5033a20465b4..93f6fa905bd98 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -108,4 +108,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 59f1 +# PUBSPEC CHECKSUM: edee diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index c37497161b980..47cfc5aeea542 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index 713cd30ee0cee..656f35176f018 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -20,6 +20,6 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e351 +# PUBSPEC CHECKSUM: a84e diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index b5be54d6e95cc..faaa755b7270e 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -10,6 +10,6 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: e5c4 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 4202db0a828be..81c3e4ab54f42 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -44,7 +44,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -89,4 +89,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ef1b +# PUBSPEC CHECKSUM: 8d18 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index c7a9bda964265..034db977e6f8d 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -43,4 +43,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index e6dcd10ecab91..86fb2c881a2f9 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.6.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +64,4 @@ dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b175 +# PUBSPEC CHECKSUM: 4f72 diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 44baa2aa30628..c4210a078a4ac 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -37,4 +37,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/dev/tools/android_driver_extensions/pubspec.yaml b/dev/tools/android_driver_extensions/pubspec.yaml index 0bec3a6381a4a..63665982f92bc 100644 --- a/dev/tools/android_driver_extensions/pubspec.yaml +++ b/dev/tools/android_driver_extensions/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c572 +# PUBSPEC CHECKSUM: 636f diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 4783525d5155c..0414fb924d372 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: flutter: sdk: flutter args: 2.7.0 - vector_math: 2.1.4 + vector_math: 2.2.0 xml: 6.5.0 characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,4 +40,4 @@ dev_dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b7f0 +# PUBSPEC CHECKSUM: 10ed diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 6ef4ce2117f46..23039918f10d5 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -36,4 +36,4 @@ dev_dependencies: term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index ff6dd993d52ea..13dbccc02ab29 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -95,4 +95,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6451 +# PUBSPEC CHECKSUM: 024e diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index 087c50083931d..f896663247a24 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -12,11 +12,11 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: e5c4 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 5924bea065799..5d0d75bc58e06 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: @@ -73,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index 6cf8edea0359c..8ba222b39cef1 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -57,4 +57,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: 59f1 +# PUBSPEC CHECKSUM: edee diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index 932d773a20204..86cc15db9e785 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -39,4 +39,4 @@ flutter: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 8f042db7dda64..d77a4cf48aaa5 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index a92631ecceb38..30ca9a93c6457 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: df67 +# PUBSPEC CHECKSUM: 7d64 diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index cdf6bac97332e..7652f0c280faa 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -19,4 +19,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: e4c7 +# PUBSPEC CHECKSUM: e5c4 diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 97ac0c0a72656..a7647042fd9bf 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 6f99747685f82..36bfdbad5b9ee 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -69,4 +69,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b623 +# PUBSPEC CHECKSUM: b420 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 40dcf477c61e3..979ce065a91b1 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: collection: 1.19.1 material_color_utilities: 0.11.1 meta: 1.16.0 - vector_math: 2.1.4 + vector_math: 2.2.0 sky_engine: sdk: flutter @@ -55,4 +55,4 @@ dev_dependencies: vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b7a8 +# PUBSPEC CHECKSUM: afa5 diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 78e2f7e2a17f7..90bfb8154dcda 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: characters: 1.4.0 collection: 1.19.1 meta: 1.16.0 - vector_math: 2.1.4 + vector_math: 2.2.0 async: 2.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,4 +47,4 @@ dev_dependencies: process: 5.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bba6 +# PUBSPEC CHECKSUM: 50a3 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index aa4900a9f04a4..335a8982d9f3c 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: fake_async: 1.3.3 @@ -77,4 +77,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c572 +# PUBSPEC CHECKSUM: 636f diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index 778d64680f807..30746ccd1af84 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bba6 +# PUBSPEC CHECKSUM: 50a3 diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index df748cd70e32d..b7e56b088daba 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -40,4 +40,4 @@ dev_dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 887b +# PUBSPEC CHECKSUM: 1d78 diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index fdd20a4cd2604..6884a4ce2b429 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: stack_trace: 1.12.1 # Used by globalToLocal et al. - vector_math: 2.1.4 + vector_math: 2.2.0 # Used to detect memory leaks with `testWidgets`. leak_tracker_flutter_testing: 3.0.10 @@ -58,4 +58,4 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 597c +# PUBSPEC CHECKSUM: 8d79 diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl index 641c2fbdf9681..00f480eb8cd75 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/controls.dart.tmpl @@ -74,13 +74,13 @@ class ZoomControls extends StatelessWidget { void _zoomIn() { _transformationController.value = Matrix4.copy( _transformationController.value, - ).scaled(1.1); + ).scaledByDouble(1.1, 1.1, 1.1, 1); } void _zoomOut() { final Matrix4 updated = Matrix4.copy( _transformationController.value, - ).scaled(0.9); + ).scaledByDouble(0.9, 0.9, 0.9, 1); // Don't allow for zooming out past the original size of the widget. // Assumes scaling is evenly applied to the entire matrix. diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart index 641c2fbdf9681..00f480eb8cd75 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/controls.dart @@ -74,13 +74,13 @@ class ZoomControls extends StatelessWidget { void _zoomIn() { _transformationController.value = Matrix4.copy( _transformationController.value, - ).scaled(1.1); + ).scaledByDouble(1.1, 1.1, 1.1, 1); } void _zoomOut() { final Matrix4 updated = Matrix4.copy( _transformationController.value, - ).scaled(0.9); + ).scaledByDouble(0.9, 0.9, 0.9, 1); // Don't allow for zooming out past the original size of the widget. // Assumes scaling is evenly applied to the entire matrix. diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml index 3109d41c2374d..10977bc2870bc 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml @@ -52,7 +52,7 @@ dependencies: url_launcher_platform_interface: 2.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_web: 2.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_windows: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,4 +61,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 10cc +# PUBSPEC CHECKSUM: 6bc9 diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index cd36fd6e50035..e9d9de39bf699 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -36,4 +36,4 @@ dev_dependencies: test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4947 +# PUBSPEC CHECKSUM: dd44 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 124a931ff9469..8a6af369fe853 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -89,4 +89,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2fd8 +# PUBSPEC CHECKSUM: ccd5 diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 7e932ea46b428..94ad9eca69b6f 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -20,9 +20,9 @@ dependencies: collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: de8e +# PUBSPEC CHECKSUM: df8b diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index bc6c6f4531251..91aa41a378f3e 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -56,4 +56,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 26ea +# PUBSPEC CHECKSUM: 5ae7 From e8366e333494ec1b957460657c6d7bda753a167f Mon Sep 17 00:00:00 2001 From: Alex Li Date: Wed, 28 May 2025 23:59:20 +0800 Subject: [PATCH 04/66] =?UTF-8?q?=F0=9F=90=9B=20Use=20consist=20slashes=20?= =?UTF-8?q?when=20generating=20dep=20files=20(#169570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continue with https://github.com/flutter/flutter/pull/169467. I've noticed that paths in the depfile on Windows are generated with non-normalized paths. This PR normalizes every single file path before putting them into the output. This might also fix https://github.com/flutter/flutter/issues/163591 as a root cause and can be easily cherry-picked. ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/build_system/depfile.dart | 20 +++-- .../build_system/depfile_test.dart | 74 ++++++++++++++++--- 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_system/depfile.dart b/packages/flutter_tools/lib/src/build_system/depfile.dart index f575bb3019096..1114faf13910c 100644 --- a/packages/flutter_tools/lib/src/build_system/depfile.dart +++ b/packages/flutter_tools/lib/src/build_system/depfile.dart @@ -66,16 +66,19 @@ class DepfileService { } void _writeFilesToBuffer(List files, StringBuffer buffer) { + final bool backslash = _fileSystem.path.style.separator == r'\'; for (final File outputFile in files) { - if (_fileSystem.path.style.separator == r'\') { - // backslashes and spaces in a depfile have to be escaped if the - // platform separator is a backslash. - final String path = outputFile.path.replaceAll(r'\', r'\\').replaceAll(r' ', r'\ '); - buffer.write(' $path'); + String path = _fileSystem.path.normalize(outputFile.path); + if (backslash) { + // Backslashes in a depfile have to be escaped if the platform separator is a backslash. + path = path.replaceAll(r'\', r'\\'); } else { - final String path = outputFile.path.replaceAll(r' ', r'\ '); - buffer.write(' $path'); + // Convert all path separators to forward slashes. + path = path.replaceAll(r'\', r'/'); } + // Escape spaces. + path = path.replaceAll(r' ', r'\ '); + buffer.write(' $path'); } } @@ -93,7 +96,8 @@ class DepfileService { // The tool doesn't write duplicates to these lists. This call is an attempt to // be resilient to the outputs of other tools which write or user edits to depfiles. .toSet() - .map(_fileSystem.file) + // Normalize the path before creating a file object. + .map((String path) => _fileSystem.file(_fileSystem.path.normalize(path))) .toList(); } } diff --git a/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart b/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart index f0efccaf5e3ef..3855c40141ee8 100644 --- a/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/depfile_test.dart @@ -17,6 +17,7 @@ void main() { fileSystem = MemoryFileSystem.test(); depfileService = DepfileService(logger: BufferLogger.test(), fileSystem: fileSystem); }); + testWithoutContext('Can parse depfile from file', () { final File depfileSource = fileSystem.file('example.d')..writeAsStringSync(''' a.txt: b.txt @@ -48,22 +49,34 @@ a.txt c.txt d.txt: b.txt }); testWithoutContext('Can parse depfile with windows file paths', () { - fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); - depfileService = DepfileService(logger: BufferLogger.test(), fileSystem: fileSystem); + final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); + final DepfileService depfileService = DepfileService( + logger: BufferLogger.test(), + fileSystem: fileSystem, + ); final File depfileSource = fileSystem.file('example.d')..writeAsStringSync(r''' -C:\\a.txt: C:\\b.txt +C:\\a1.txt C:\\a2/a3.txt: C:\\b1.txt C:\\b2/b3.txt '''); final Depfile depfile = depfileService.parse(depfileSource); - expect(depfile.inputs.single.path, r'C:\b.txt'); - expect(depfile.outputs.single.path, r'C:\a.txt'); + expect(depfile.inputs.map((File e) => e.path).toList(), [ + r'C:\b1.txt', + r'C:\b2\b3.txt', + ]); + expect(depfile.outputs.map((File e) => e.path).toList(), [ + r'C:\a1.txt', + r'C:\a2\a3.txt', + ]); }); testWithoutContext( 'Can escape depfile with windows file paths and spaces in directory names', () { - fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); - depfileService = DepfileService(logger: BufferLogger.test(), fileSystem: fileSystem); + final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); + final DepfileService depfileService = DepfileService( + logger: BufferLogger.test(), + fileSystem: fileSystem, + ); final File inputFile = fileSystem.directory(r'Hello Flutter').childFile('a.txt').absolute ..createSync(recursive: true); @@ -73,8 +86,9 @@ C:\\a.txt: C:\\b.txt final File outputDepfile = fileSystem.file('depfile'); depfileService.writeToFile(depfile, outputDepfile); - expect(outputDepfile.readAsStringSync(), contains(r'C:\\Hello\ Flutter\\a.txt')); - expect(outputDepfile.readAsStringSync(), contains(r'C:\\Hello\ Flutter\\b.txt')); + final String output = outputDepfile.readAsStringSync(); + expect(output, contains(r'C:\\Hello\ Flutter\\a.txt')); + expect(output, contains(r'C:\\Hello\ Flutter\\b.txt')); }, ); @@ -88,8 +102,46 @@ C:\\a.txt: C:\\b.txt final File outputDepfile = fileSystem.file('depfile'); depfileService.writeToFile(depfile, outputDepfile); - expect(outputDepfile.readAsStringSync(), contains(r'/Hello\ Flutter/a.txt')); - expect(outputDepfile.readAsStringSync(), contains(r'/Hello\ Flutter/b.txt')); + final String output = outputDepfile.readAsStringSync(); + expect(output, contains(r'/Hello\ Flutter/a.txt')); + expect(output, contains(r'/Hello\ Flutter/b.txt')); + }); + + testWithoutContext('Can produce normalized paths', () { + final List<(FileSystemStyle style, String input, String output, List expects)> pairs = + <(FileSystemStyle style, String input, String output, List expects)>[ + ( + FileSystemStyle.posix, + r'Hello Flutter\a.txt', + r'Hello Flutter\b.txt', + [r'/Hello\ Flutter/a.txt', r'/Hello\ Flutter/b.txt'], + ), + ( + FileSystemStyle.windows, + r'Hello Flutter/a.txt', + r'Hello Flutter/b.txt', + [r'\\Hello\ Flutter\\a.txt', r'\\Hello\ Flutter\\b.txt'], + ), + ]; + + for (final (FileSystemStyle style, String input, String output, List expects) + in pairs) { + final FileSystem fileSystem = MemoryFileSystem.test(style: style); + final DepfileService depfileService = DepfileService( + logger: BufferLogger.test(), + fileSystem: fileSystem, + ); + final File inputFile = fileSystem.file(input).absolute..createSync(recursive: true); + final File outputFile = fileSystem.file(output).absolute..createSync(); + final Depfile depfile = Depfile([inputFile], [outputFile]); + final File outputDepfile = fileSystem.file('depfile'); + depfileService.writeToFile(depfile, outputDepfile); + + final String outputString = outputDepfile.readAsStringSync(); + for (final String path in expects) { + expect(outputString, contains(path)); + } + } }); testWithoutContext('Resilient to weird whitespace', () { From a5b51dbf223260ed0e89111aa7a831fe5d5b8566 Mon Sep 17 00:00:00 2001 From: "John \"codefu\" McDole" Date: Wed, 28 May 2025 12:57:47 -0700 Subject: [PATCH 05/66] Engine tests kvm=1 is required for some fuchsia (#169614) Undoes some changes from #168106 as these tests are looking for a KVM specifically for hardware accelerating the emulators. Tests are timing out as "infra failures" and making the tree go red. > KVM path /dev/kvm does not exist. Running without acceleration; emulator will be extremely slow and may not establish a connection with ffx in the allotted time. --- engine/src/flutter/ci/builders/linux_fuchsia_tests.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/src/flutter/ci/builders/linux_fuchsia_tests.json b/engine/src/flutter/ci/builders/linux_fuchsia_tests.json index c466959738407..d2b446bdd4385 100644 --- a/engine/src/flutter/ci/builders/linux_fuchsia_tests.json +++ b/engine/src/flutter/ci/builders/linux_fuchsia_tests.json @@ -139,6 +139,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", + "kvm=1", "os=Linux" ], "gclient_variables": { @@ -184,6 +185,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", + "kvm=1", "os=Linux" ], "gclient_variables": { @@ -229,6 +231,7 @@ "cas_archive": false, "drone_dimensions": [ "device_type=none", + "kvm=1", "os=Linux" ], "gclient_variables": { From 5e953e76c1c907fb7d333445da7a22865ef6f9ca Mon Sep 17 00:00:00 2001 From: Yegor Date: Wed, 28 May 2025 13:11:20 -0700 Subject: [PATCH 06/66] unskip text_painter_rtl_test on web (#169537) Fixes https://github.com/flutter/flutter/issues/32238 --- packages/flutter/test/painting/text_painter_rtl_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/test/painting/text_painter_rtl_test.dart b/packages/flutter/test/painting/text_painter_rtl_test.dart index 47915266e2dea..6632555b9dac4 100644 --- a/packages/flutter/test/painting/text_painter_rtl_test.dart +++ b/packages/flutter/test/painting/text_painter_rtl_test.dart @@ -383,7 +383,7 @@ void main() { ], ); painter.dispose(); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/32238 + }); test('TextPainter - line wrap mid-word', () { final TextPainter painter = TextPainter()..textDirection = TextDirection.ltr; From 8e8cb9255339b347bb551cc4c4101007fe83d63f Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 28 May 2025 13:15:01 -0700 Subject: [PATCH 07/66] Roll forward: "Initialize default-app-flavor" (#169298) (#169602) Closes https://github.com/flutter/flutter/issues/169598 (which explains the integration test failure). Closes https://github.com/flutter/flutter/issues/169160. Closes https://github.com/flutter/flutter/issues/165803. This is the only diff from 5d013c73baa70a8b3e1c541cb63e4c22654aa3cc: ```diff diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 61583210e47..67731019a05 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -308,10 +308,18 @@ class KernelSnapshot extends Target { if (flavor == null) { return; } - if (!dartDefines.any((String element) => element.startsWith(kAppFlavor))) { - // If the flavor is not already in the dart defines, add it. - dartDefines.add('$kAppFlavor=$flavor'); - } + + // It is possible there is a flavor already in dartDefines, from another + // part of the build process, but this should take precedence as it happens + // last (xcodebuild execution). + // + // See https://github.com/flutter/flutter/issues/169598. + + // If the flavor is already in the dart defines, remove it. + dartDefines.removeWhere((String define) => define.startsWith(kAppFlavor)); + + // Then, add it to the end. + dartDefines.add('$kAppFlavor=$flavor'); } } ``` --- .../lib/src/build_system/targets/common.dart | 24 ++--- .../lib/src/runner/flutter_command.dart | 12 +++ .../build_system/targets/common_test.dart | 99 ++++++++++--------- .../runner/flutter_command_test.dart | 92 +++++++++++++++++ .../default_flavor_test.dart | 74 ++++++++++++++ .../test/integration.shard/test_driver.dart | 5 +- 6 files changed, 247 insertions(+), 59 deletions(-) create mode 100644 packages/flutter_tools/test/integration.shard/default_flavor_test.dart diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 735c380b10f84..67731019a050d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -6,16 +6,14 @@ import 'package:package_config/package_config.dart'; import '../../artifacts.dart'; import '../../base/build.dart'; -import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; import '../../compile.dart'; import '../../dart/package_map.dart'; import '../../devfs.dart'; -import '../../globals.dart' as globals show platform, xcode; +import '../../globals.dart' as globals show xcode; import '../../project.dart'; -import '../../runner/flutter_command.dart'; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; @@ -310,15 +308,17 @@ class KernelSnapshot extends Target { if (flavor == null) { return; } - if (globals.platform.environment[kAppFlavor] != null) { - throwToolExit('$kAppFlavor is used by the framework and cannot be set in the environment.'); - } - if (dartDefines.any((String define) => define.startsWith(kAppFlavor))) { - throwToolExit( - '$kAppFlavor is used by the framework and cannot be ' - 'set using --${FlutterOptions.kDartDefinesOption} or --${FlutterOptions.kDartDefineFromFileOption}', - ); - } + + // It is possible there is a flavor already in dartDefines, from another + // part of the build process, but this should take precedence as it happens + // last (xcodebuild execution). + // + // See https://github.com/flutter/flutter/issues/169598. + + // If the flavor is already in the dart defines, remove it. + dartDefines.removeWhere((String define) => define.startsWith(kAppFlavor)); + + // Then, add it to the end. dartDefines.add('$kAppFlavor=$flavor'); } } diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 00f754f85914c..38ebd9ceb1202 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1411,6 +1411,18 @@ abstract class FlutterCommand extends Command { final String? cliFlavor = argParser.options.containsKey('flavor') ? stringArg('flavor') : null; final String? flavor = cliFlavor ?? defaultFlavor; + if (globals.platform.environment[kAppFlavor] != null) { + throwToolExit('$kAppFlavor is used by the framework and cannot be set in the environment.'); + } + if (dartDefines.any((String define) => define.startsWith(kAppFlavor))) { + throwToolExit( + '$kAppFlavor is used by the framework and cannot be ' + 'set using --${FlutterOptions.kDartDefinesOption} or --${FlutterOptions.kDartDefineFromFileOption}', + ); + } + if (flavor != null) { + dartDefines.add('$kAppFlavor=$flavor'); + } _addFlutterVersionToDartDefines(globals.flutterVersion, dartDefines); return BuildInfo( diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 2e2ad77efe7b7..1652a6f518b92 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -13,6 +13,7 @@ import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/common.dart'; import 'package:flutter_tools/src/build_system/targets/ios.dart'; import 'package:flutter_tools/src/compile.dart'; +import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:test/fake.dart'; @@ -440,58 +441,65 @@ void main() { ); testUsingContext( - "tool exits when $kAppFlavor is already set in user's environment", + 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if ios app', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); - final Future buildResult = const KernelSnapshot().build( - androidEnvironment - ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.android) - ..defines[kBuildMode] = BuildMode.debug.cliName - ..defines[kFlavor] = 'strawberry' - ..defines[kTrackWidgetCreation] = 'false', + final String build = iosEnvironment.buildDir.path; + final String flutterPatchedSdkPath = artifacts.getArtifactPath( + Artifact.flutterPatchedSdkPath, + platform: TargetPlatform.ios, + mode: BuildMode.debug, ); - - expect( - buildResult, - throwsToolExit( - message: '$kAppFlavor is used by the framework and cannot be set in the environment.', + fileSystem.directory('/ios/Runner.xcodeproj').createSync(recursive: true); + processManager.addCommands([ + FakeCommand( + command: [ + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), + '--sdk-root', + '$flutterPatchedSdkPath/', + '--target=flutter', + '--no-print-incremental-dependencies', + '-D$kAppFlavor=chocolate', + ...buildModeOptions(BuildMode.debug, []), + '--no-link-platform', + '--packages', + '/.dart_tool/package_config.json', + '--output-dill', + '$build/app.dill', + '--depfile', + '$build/kernel_snapshot_program.d', + '--incremental', + '--initialize-from-dill', + '$build/app.dill', + '--verbosity=error', + 'file:///lib/main.dart', + ], + stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n', ), - ); - }, - overrides: { - Platform: () => FakePlatform(environment: {kAppFlavor: 'I was already set'}), - }, - ); + ]); - testUsingContext( - 'tool exits when $kAppFlavor is set in --dart-define or --dart-define-from-file', - () async { - fileSystem.file('.dart_tool/package_config.json') - ..createSync(recursive: true) - ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); - final Future buildResult = const KernelSnapshot().build( - androidEnvironment - ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.android) + await const KernelSnapshot().build( + iosEnvironment + ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.ios) ..defines[kBuildMode] = BuildMode.debug.cliName ..defines[kFlavor] = 'strawberry' - ..defines[kDartDefines] = encodeDartDefines([kAppFlavor, 'strawberry']) + ..defines[kXcodeConfiguration] = 'Debug-chocolate' ..defines[kTrackWidgetCreation] = 'false', ); - expect( - buildResult, - throwsToolExit( - message: - '$kAppFlavor is used by the framework and cannot be set using --dart-define or --dart-define-from-file', - ), - ); + expect(processManager, hasNoRemainingExpectations); + }, + overrides: { + XcodeProjectInterpreter: + () => FakeXcodeProjectInterpreter(schemes: ['Runner', 'chocolate']), }, ); testUsingContext( - 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if ios app', + 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if macos app', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) @@ -499,10 +507,10 @@ void main() { final String build = iosEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, - platform: TargetPlatform.ios, + platform: TargetPlatform.darwin, mode: BuildMode.debug, ); - fileSystem.directory('/ios/Runner.xcodeproj').createSync(recursive: true); + fileSystem.directory('/macos/Runner.xcodeproj').createSync(recursive: true); processManager.addCommands([ FakeCommand( command: [ @@ -514,7 +522,6 @@ void main() { '--no-print-incremental-dependencies', '-D$kAppFlavor=chocolate', ...buildModeOptions(BuildMode.debug, []), - '--no-link-platform', '--packages', '/.dart_tool/package_config.json', '--output-dill', @@ -533,7 +540,7 @@ void main() { await const KernelSnapshot().build( iosEnvironment - ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.ios) + ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin) ..defines[kBuildMode] = BuildMode.debug.cliName ..defines[kFlavor] = 'strawberry' ..defines[kXcodeConfiguration] = 'Debug-chocolate' @@ -549,7 +556,7 @@ void main() { ); testUsingContext( - 'KernelSnapshot sets flavor in dartDefines from Xcode build configuration if macos app', + 'KernelSnapshot does not add kAppFlavor twice to Dart defines', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) @@ -560,7 +567,6 @@ void main() { platform: TargetPlatform.darwin, mode: BuildMode.debug, ); - fileSystem.directory('/macos/Runner.xcodeproj').createSync(recursive: true); processManager.addCommands([ FakeCommand( command: [ @@ -570,7 +576,7 @@ void main() { '$flutterPatchedSdkPath/', '--target=flutter', '--no-print-incremental-dependencies', - '-D$kAppFlavor=chocolate', + '-D$kAppFlavor=strawberry', ...buildModeOptions(BuildMode.debug, []), '--packages', '/.dart_tool/package_config.json', @@ -592,16 +598,17 @@ void main() { iosEnvironment ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin) ..defines[kBuildMode] = BuildMode.debug.cliName + ..defines[kDartDefines] = base64Encode(utf8.encode('FLUTTER_APP_FLAVOR=vanilla')) ..defines[kFlavor] = 'strawberry' - ..defines[kXcodeConfiguration] = 'Debug-chocolate' ..defines[kTrackWidgetCreation] = 'false', ); expect(processManager, hasNoRemainingExpectations); }, overrides: { - XcodeProjectInterpreter: - () => FakeXcodeProjectInterpreter(schemes: ['Runner', 'chocolate']), + Platform: () => macPlatform, + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }, ); diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 00b603d354f2a..fbda6491f992a 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -1270,6 +1270,98 @@ flutter: ); }); + testUsingContext( + "tool exits when $kAppFlavor is already set in user's environemnt", + () async { + final CommandRunner runner = createTestCommandRunner( + _TestRunCommandThatOnlyValidates(), + ); + expect( + runner.run(['run', '--no-pub', '--no-hot']), + throwsToolExit( + message: '$kAppFlavor is used by the framework and cannot be set in the environment.', + ), + ); + }, + overrides: { + DeviceManager: + () => FakeDeviceManager()..attachedDevices = [FakeDevice('name', 'id')], + FileSystem: () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + return fileSystem; + }, + ProcessManager: FakeProcessManager.empty, + Platform: () => FakePlatform()..environment = {kAppFlavor: 'AlreadySet'}, + }, + ); + + testUsingContext( + 'tool exits when $kAppFlavor is set in --dart-define', + () async { + final CommandRunner runner = createTestCommandRunner( + _TestRunCommandThatOnlyValidates(), + ); + expect( + runner.run([ + 'run', + '--dart-define=$kAppFlavor=AlreadySet', + '--no-pub', + '--no-hot', + ]), + throwsToolExit( + message: '$kAppFlavor is used by the framework and cannot be set using --dart-define', + ), + ); + }, + overrides: { + DeviceManager: + () => FakeDeviceManager()..attachedDevices = [FakeDevice('name', 'id')], + FileSystem: () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + return fileSystem; + }, + ProcessManager: FakeProcessManager.empty, + }, + ); + + testUsingContext( + 'tool exits when $kAppFlavor is set in --dart-define-from-file', + () async { + final CommandRunner runner = createTestCommandRunner( + _TestRunCommandThatOnlyValidates(), + ); + expect( + runner.run([ + 'run', + '--dart-define-from-file=config.json', + '--no-pub', + '--no-hot', + ]), + throwsToolExit( + message: '$kAppFlavor is used by the framework and cannot be set using --dart-define', + ), + ); + }, + overrides: { + DeviceManager: + () => FakeDeviceManager()..attachedDevices = [FakeDevice('name', 'id')], + FileSystem: () { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + fileSystem.file('config.json') + ..createSync() + ..writeAsStringSync('{"$kAppFlavor": "AlreadySet"}'); + return fileSystem; + }, + ProcessManager: FakeProcessManager.empty, + }, + ); + group('Flutter version', () { for (final String dartDefine in FlutterCommand.flutterVersionDartDefines) { testUsingContext( diff --git a/packages/flutter_tools/test/integration.shard/default_flavor_test.dart b/packages/flutter_tools/test/integration.shard/default_flavor_test.dart new file mode 100644 index 0000000000000..f84008a05d9c7 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/default_flavor_test.dart @@ -0,0 +1,74 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@Tags(['flutter-test-driver']) +library; + +import 'package:flutter_tools/src/base/file_system.dart'; + +import '../src/common.dart'; +import 'test_data/project.dart'; +import 'test_driver.dart'; +import 'test_utils.dart'; + +void main() { + final Project project = _DefaultFlavorProject(); + late Directory tempDir; + late FlutterTestTestDriver flutter; + + setUp(() async { + tempDir = createResolvedTempDirectorySync('default_flavor_test.'); + await project.setUpIn(tempDir); + flutter = FlutterTestTestDriver(tempDir); + }); + + tearDown(() async { + tryToDelete(tempDir); + }); + + testWithoutContext('Reads "default-flavor" in "flutter test"', () async { + await flutter.test(); + + // Without an assertion, this test always passes. + final int? exitCode = await flutter.done; + expect(exitCode, 0, reason: 'flutter test failed with exit code $exitCode'); + }); +} + +final class _DefaultFlavorProject extends Project { + @override + final String main = r''' + // Irrelevant to this test. + void main() {} + '''; + + @override + final String pubspec = r''' + name: test + environment: + sdk: ^3.7.0-0 + + flutter: + default-flavor: dev + + dependencies: + flutter: + sdk: flutter + dev_dependencies: + flutter_test: + sdk: flutter + '''; + + @override + final String test = r''' + import 'package:flutter/services.dart'; + import 'package:flutter_test/flutter_test.dart'; + + void main() { + test('receives default-flavor with flutter test', () async { + expect(appFlavor, 'dev'); + }); + } + '''; +} diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index ee9e9d953d761..5671f31071862 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -140,7 +140,10 @@ abstract final class FlutterTestDriver { _stderr.stream.listen((String message) => _debugPrint(message, topic: '<=stderr=')); } - Future get done async => _process?.exitCode; + /// Completes when process exits with the given exit code. + /// + /// If the process has never been started, complets with `null`. + Future get done async => _process?.exitCode; Future connectToVmService({bool pauseOnExceptions = false}) async { _vmService = await vmServiceConnectUri('$_vmServiceWsUri'); From c492ad41a36ddd524a8e3235e4cabb00c8b30e91 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 28 May 2025 16:15:10 -0400 Subject: [PATCH 08/66] Roll Skia from 82d326fc2148 to cc7963935d9d (1 revision) (#169597) https://skia.googlesource.com/skia.git/+log/82d326fc2148..cc7963935d9d 2025-05-28 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC codefu@google.com,kjlubick@google.com,nicolettep@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 19a13547b99d9..cff6baf50d7e3 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '82d326fc2148181e8d9ca848b17237fa4db75331', + 'skia_revision': 'cc7963935d9dd21630a15ef9d387296db936ef03', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 3e8b531b18d8218851624dda4d09935a08b4e63e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 28 May 2025 16:15:10 -0400 Subject: [PATCH 09/66] Roll Fuchsia Linux SDK from nC9hLWjYVlChDTEPh... to WvRLeTv2ocKsPOdrq... (#169604) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter Please CC codefu@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index cff6baf50d7e3..69d93bd8166d5 100644 --- a/DEPS +++ b/DEPS @@ -813,7 +813,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'nC9hLWjYVlChDTEPhMpsRnSYKFDw4zfIRl2sHkX3yCIC' + 'version': 'WvRLeTv2ocKsPOdrq6vLJD4yrP7nK7ElT9ieuFnvumUC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia index 0cec841153784..d83405a7f276d 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia +++ b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 6cf3b02f62f4fa04c4db32736c7dd291 +Signature: 14930a85cd4de0b2742abfacf64f042b ==================================================================================================== LIBRARY: fuchsia_sdk From af3627ac2bd26bb077a8cdd03e96834d72c4e72b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 28 May 2025 14:28:17 -0700 Subject: [PATCH 10/66] [Impeller] acquire the gpu sync switch when flush stored GPU tasks. (#169596) Potential fix for https://github.com/flutter/flutter/issues/166668 See: * https://github.com/flutter/flutter/blob/master/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm#L429 * https://github.com/flutter/flutter/blob/5d013c73baa70a8b3e1c541cb63e4c22654aa3cc/engine/src/flutter/fml/synchronization/sync_switch.cc#L41 We don't hold the sync switch lock when we flush tasks. So if we start flushing then immediately go to the background, then we might execute while backgrounded. --- .../flutter/ci/licenses_golden/excluded_files | 1 + .../backend/metal/playground_impl_mtl.h | 5 +- .../backend/metal/playground_impl_mtl.mm | 4 ++ .../flutter/impeller/playground/playground.cc | 4 ++ .../flutter/impeller/playground/playground.h | 5 ++ .../impeller/playground/playground_impl.h | 2 + .../impeller/renderer/backend/metal/BUILD.gn | 1 + .../renderer/backend/metal/context_mtl.h | 5 +- .../renderer/backend/metal/context_mtl.mm | 20 +++++- .../backend/metal/context_mtl_unittests.mm | 64 +++++++++++++++++++ 10 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files index ac78b4d2afea6..6d40f111216d7 100644 --- a/engine/src/flutter/ci/licenses_golden/excluded_files +++ b/engine/src/flutter/ci/licenses_golden/excluded_files @@ -191,6 +191,7 @@ ../../../flutter/impeller/renderer/backend/gles/test ../../../flutter/impeller/renderer/backend/gles/unique_handle_gles_unittests.cc ../../../flutter/impeller/renderer/backend/metal/allocator_mtl_unittests.mm +../../../flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/metal/swapchain_transients_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/metal/texture_mtl_unittests.mm ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk_unittests.cc diff --git a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h index 0935e5c816e27..2028a82529ba4 100644 --- a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h +++ b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.h @@ -38,7 +38,7 @@ class PlaygroundImplMTL final : public PlaygroundImpl { std::shared_ptr context_; std::shared_ptr concurrent_loop_; std::shared_ptr swapchain_transients_; - std::shared_ptr is_gpu_disabled_sync_switch_; + std::shared_ptr is_gpu_disabled_sync_switch_; // |PlaygroundImpl| std::shared_ptr GetContext() const override; @@ -50,6 +50,9 @@ class PlaygroundImplMTL final : public PlaygroundImpl { std::unique_ptr AcquireSurfaceFrame( std::shared_ptr context) override; + // |PlaygroundImpl| + void SetGPUDisabled(bool disabled) const override; + PlaygroundImplMTL(const PlaygroundImplMTL&) = delete; PlaygroundImplMTL& operator=(const PlaygroundImplMTL&) = delete; diff --git a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm index 978f01ab416fd..a276c11aeaa69 100644 --- a/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm +++ b/engine/src/flutter/impeller/playground/backend/metal/playground_impl_mtl.mm @@ -138,4 +138,8 @@ return fml::Status(); } +void PlaygroundImplMTL::SetGPUDisabled(bool disabled) const { + is_gpu_disabled_sync_switch_->SetSwitch(disabled); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/playground/playground.cc b/engine/src/flutter/impeller/playground/playground.cc index 3889d6d68d166..4b6d786c3021c 100644 --- a/engine/src/flutter/impeller/playground/playground.cc +++ b/engine/src/flutter/impeller/playground/playground.cc @@ -527,4 +527,8 @@ Playground::VKProcAddressResolver Playground::CreateVKProcAddressResolver() return impl_->CreateVKProcAddressResolver(); } +void Playground::SetGPUDisabled(bool value) const { + impl_->SetGPUDisabled(value); +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/playground/playground.h b/engine/src/flutter/impeller/playground/playground.h index 236e6de89c649..6878a5975156c 100644 --- a/engine/src/flutter/impeller/playground/playground.h +++ b/engine/src/flutter/impeller/playground/playground.h @@ -122,6 +122,11 @@ class Playground { std::function; VKProcAddressResolver CreateVKProcAddressResolver() const; + /// @brief Mark the GPU as unavilable. + /// + /// Only supported on the Metal backend. + void SetGPUDisabled(bool disabled) const; + protected: const PlaygroundSwitches switches_; diff --git a/engine/src/flutter/impeller/playground/playground_impl.h b/engine/src/flutter/impeller/playground/playground_impl.h index 387a2cb5af44e..ed2593fc98ffb 100644 --- a/engine/src/flutter/impeller/playground/playground_impl.h +++ b/engine/src/flutter/impeller/playground/playground_impl.h @@ -40,6 +40,8 @@ class PlaygroundImpl { virtual Playground::VKProcAddressResolver CreateVKProcAddressResolver() const; + virtual void SetGPUDisabled(bool disabled) const {} + protected: const PlaygroundSwitches switches_; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn b/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn index ac4a000492232..9103010bd1d60 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn +++ b/engine/src/flutter/impeller/renderer/backend/metal/BUILD.gn @@ -70,6 +70,7 @@ impeller_component("metal_unittests") { sources = [ "allocator_mtl_unittests.mm", + "context_mtl_unittests.mm", "swapchain_transients_mtl_unittests.mm", "texture_mtl_unittests.mm", ] diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h index 712cf7c1f69da..348830d0fe7ee 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.h @@ -146,6 +146,9 @@ class ContextMTL final : public Context, void StoreTaskForGPU(const fml::closure& task, const fml::closure& failure) override; + // visible for testing. + void FlushTasksAwaitingGPU(); + private: class SyncSwitchObserver : public fml::SyncSwitch::Observer { public: @@ -191,8 +194,6 @@ class ContextMTL final : public Context, std::shared_ptr CreateCommandBufferInQueue( id queue) const; - void FlushTasksAwaitingGPU(); - ContextMTL(const ContextMTL&) = delete; ContextMTL& operator=(const ContextMTL&) = delete; diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm index b30896f2b5d5b..b64547b93f248 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl.mm @@ -418,8 +418,26 @@ new ContextMTL(flags, device, command_queue, Lock lock(tasks_awaiting_gpu_mutex_); std::swap(tasks_awaiting_gpu, tasks_awaiting_gpu_); } + std::vector tasks_to_queue; for (const auto& task : tasks_awaiting_gpu) { - task.task(); + is_gpu_disabled_sync_switch_->Execute(fml::SyncSwitch::Handlers() + .SetIfFalse([&] { task.task(); }) + .SetIfTrue([&] { + // Lost access to the GPU + // immediately after it was + // activated. This may happen if + // the app was quickly + // foregrounded/backgrounded + // from a push notification. + // Store the tasks on the + // context again. + tasks_to_queue.push_back(task); + })); + } + if (!tasks_to_queue.empty()) { + Lock lock(tasks_awaiting_gpu_mutex_); + tasks_awaiting_gpu_.insert(tasks_awaiting_gpu_.end(), + tasks_to_queue.begin(), tasks_to_queue.end()); } } diff --git a/engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm new file mode 100644 index 0000000000000..cb3ee72e599f7 --- /dev/null +++ b/engine/src/flutter/impeller/renderer/backend/metal/context_mtl_unittests.mm @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/testing/testing.h" +#include "impeller/core/device_buffer_descriptor.h" +#include "impeller/core/formats.h" +#include "impeller/core/texture_descriptor.h" +#include "impeller/playground/playground_test.h" +#include "impeller/renderer/backend/metal/allocator_mtl.h" +#include "impeller/renderer/backend/metal/context_mtl.h" +#include "impeller/renderer/backend/metal/formats_mtl.h" +#include "impeller/renderer/backend/metal/texture_mtl.h" +#include "impeller/renderer/capabilities.h" + +#include +#include +#include + +#include "gtest/gtest.h" + +namespace impeller { +namespace testing { + +using ContextMTLTest = PlaygroundTest; +INSTANTIATE_METAL_PLAYGROUND_SUITE(ContextMTLTest); + +TEST_P(ContextMTLTest, FlushTask) { + auto& context_mtl = ContextMTL::Cast(*GetContext()); + + int executed = 0; + int failed = 0; + context_mtl.StoreTaskForGPU([&]() { executed++; }, [&]() { failed++; }); + + context_mtl.FlushTasksAwaitingGPU(); + + EXPECT_EQ(executed, 1); + EXPECT_EQ(failed, 0); +} + +TEST_P(ContextMTLTest, FlushTaskWithGPULoss) { + auto& context_mtl = ContextMTL::Cast(*GetContext()); + + int executed = 0; + int failed = 0; + context_mtl.StoreTaskForGPU([&]() { executed++; }, [&]() { failed++; }); + + // If tasks are flushed while the GPU is disabled, then + // they should not be executed. + SetGPUDisabled(/*disabled=*/true); + context_mtl.FlushTasksAwaitingGPU(); + + EXPECT_EQ(executed, 0); + EXPECT_EQ(failed, 0); + + // Toggling availibility should flush tasks. + SetGPUDisabled(/*disabled=*/false); + + EXPECT_EQ(executed, 1); + EXPECT_EQ(failed, 0); +} + +} // namespace testing +} // namespace impeller From 2180d9fe80754e48defca5db176c4d87e3d28c2c Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 28 May 2025 14:36:28 -0700 Subject: [PATCH 11/66] [Impeller] Update FAQ for WebGPU/Dawn. (#169616) From the thread on the insiders channel. --- engine/src/flutter/impeller/docs/faq.md | 50 ++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/engine/src/flutter/impeller/docs/faq.md b/engine/src/flutter/impeller/docs/faq.md index 9ff20fbd43822..4cf4dbda80c8d 100644 --- a/engine/src/flutter/impeller/docs/faq.md +++ b/engine/src/flutter/impeller/docs/faq.md @@ -290,6 +290,54 @@ at startup time. But it still aims to support Skia’s general 2D API and has th same spec. requirements. The design decisions made to support those requirements make offline shader compilation impossible. -As of August 2024, Flutter has no plans to use Graphite. However, we, the +As of May 2025, Flutter has no plans to use Graphite. However, we, the Flutter team, are in constant communication with the Skia team and freely share insights and ideas across Impeller and Graphite. + +### How does WebGPU/Dawn fit into the rendering landscape in Flutter? + +To access graphics/compute accelerators on the device, you need to go through a client API like Vulkan, OpenGL, Metal, DirectX, etc… Rendering engines like Impeller, Skia, ThreeJS (we’ll call them middleware) all have the same concern. The client APIs are extremely low-level, not fully platform/device agnostic, and difficult to target/maintain individually. Depending on the application's needs, you can get away with targeting just one client API. Sometimes, client APIs can be layered on top of another. For instance, running WebGL in the browser likely uses Metal under the hood (via Angle) when the browser is running on macOS. + +```mermaid +flowchart TD + GraphicsHardware["Graphics Hardware"] + Impeller --> OpenGL + Skia --> OpenGL + Others --> OpenGL + Impeller --> Metal + Skia --> Metal + Others --> Metal + Impeller --> Vulkan + Skia --> Vulkan + Others --> Vulkan + OpenGL --> GraphicsHardware + Metal --> GraphicsHardware + Vulkan --> GraphicsHardware + +``` + +WebGPU, or Dawn/wgpu.rs in JS garb, purports to be a sensible and portable abstraction layer over the [client APIs](https://dawn.googlesource.com/dawn/+/HEAD/docs/support.md). For middleware, that presents an interesting value proposition. Instead of doing mostly the same thing multiple times, you just target one API and let the WebGPU library take care of the rest. + +```mermaid +flowchart TD + GraphicsHardware["Graphics Hardware"] + Impeller --> Dawn + Skia --> Dawn + Others --> Dawn + OpenGL --> GraphicsHardware + Metal --> GraphicsHardware + Vulkan --> GraphicsHardware + Dawn --> OpenGL + Dawn --> Metal + Dawn --> Vulkan +``` + +However, for middleware like Impeller, there are a few practical considerations that make Dawn unsuitable for use today. For one, the binary size of the library is larger than the entire Flutter Engine. Flutter users are incredibly sensitive to binary size and more than doubling the size of the engine is a tough pill to swallow. In comparison, Impeller adds only about 100kb of binary size to the Flutter Engine today. Next, the WebGPU abstraction locks us out of features available directly in client API that Impeller freely exploits for performance (framebuffer-fetch, fixed-rate compression for intermediate render targets, etc…). Impeller would either have to wait for official support for it in Dawn or poke holes in the API which increases our support surface. But, we are not averse to having a WebGPU backend for Flutter. In fact, we’ve already done experiments where our compiler can target [WGSL](https://github.com/chinmaygarde/wgsl_sandbox) and are ready to support WebGPU when/where it makes sense. But, right now, we are in a situation where a WebGPU backend will be **in-addition-to** the other backends and not **instead-of**. This defeats the primary value proposition of WebGPU/Dawn which is not having to maintain multiple backends in the first place. + +As of May 2025, Impeller has no plans to add a WebGPU/Dawn backend. We will re-evaluate this decision if/when one or both of the following conditions hold: +* WebGPU is the only available client API on the platform capable of servicing Flutters needs. Hypothetically, this could be a path Impeller takes on the web instead of using WebGL 2. Though, we must admit it's a tough decision today. +* WebGPU is the preferred client API on a platform and is available on that platform already (negating Impellers concerns about binary size). Flutter targets no such platforms today. + +We do get queries about WebGPU from the perspective of application developers, **not** middleware like Impeller. Flutter does have the ability to poke a hole in the middleware for applications to support specific rendering use-cases. For instance, plugins use it to render into a texture using client APIs directly. But as soon as you attempt to do your own rendering, you hit a massive usability cliff where you need to support all client APIs portably. WebGPU starts looking like just the thing you need. FWIW, application developers can write bindings to WebGPU using the plugin model with FFI and use those bindings to write a renderer that renders to a texture that gets composited in a Flutter application. But it's going to be very hard. And developers will likely lose the benefits of stateful hot-reload and all the other developer affordances that are part of Flutters value proposition unless significant investments are made in the developer experience. The author's role as a middleware developer with the constraints listed above disincentives them from making such an investment. So this is a call to the community for a high-quality WebGPU package. + +Admittedly, a gap in Flutters rendering support is that there is no way to create a delightful 3D renderer in Flutter without also first escaping from Flutter. That an escape hatch (via FFI/plugins) exists is perhaps missing the point. Talking about how someone could use WebGPU once they use that escape hatch even more so. A potentially exciting proposal is [Flutter GPU](https://docs.google.com/document/d/1Sh1BAC5c_kkuMVreo7ymBzPoMzb7lamZRPsI7GBXv5M/edit?resourcekey=0-5w8u2V-LS41tCHeoE8bDTQ&tab=t.0). It would expose a really low-level (but still Dart) interface to accelerators in a portable manner. Package authors will then be able to write renderers in Dart (similar to ThreeJS) that integrate well with existing Canvas APIs (no platform views, no texture composition, etc…). The progress is compelling but slow given current resource constraints on the team. From 1ce59f419d95190894bb28e9129da05adfa51da2 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Wed, 28 May 2025 14:46:19 -0700 Subject: [PATCH 12/66] integration_tests: Check if BuildContext is mounted in display_cutout_test (#169008) These changes highlight where code was not safely checking whether the BuildContext was mounted before using it. The `use_build_context_synchronously` lint rule is changing to catch these cases. ## 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]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../integration_test/display_cutout_test.dart | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart b/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart index a42117faad32b..7c14d8ede825d 100644 --- a/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart +++ b/dev/integration_tests/display_cutout_rotation/integration_test/display_cutout_test.dart @@ -22,6 +22,9 @@ void main() { // Load app widget. await tester.pumpWidget(const MyApp()); final BuildContext context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } final Iterable displayFeatures = getCutouts(tester, context); // Test is expecting one cutout setup in the test harness. expect(displayFeatures.length, 1, reason: 'Single cutout display feature expected'); @@ -40,6 +43,9 @@ void main() { // Load app widget. await tester.pumpWidget(const MyApp()); final BuildContext context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } // Verify that app code thinks there is a left cutout. final Iterable displayFeatures = getCutouts(tester, context); @@ -60,6 +66,9 @@ void main() { // Load app widget. await tester.pumpWidget(widgetUnderTest); BuildContext context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } Iterable displayFeatures = getCutouts(tester, context); // Test is expecting one cutout setup in the test harness. expect(displayFeatures.length, 1, reason: 'Single cutout display feature expected'); @@ -76,6 +85,9 @@ void main() { // Requery for display features after rotation. context = tester.element(find.byType(Text)); + if (!context.mounted) { + fail('BuildContext not mounted'); + } displayFeatures = getCutouts(tester, context); // Test is expecting one cutout setup in the test harness. expect(displayFeatures.length, 1, reason: 'Single cutout display feature expected'); @@ -116,7 +128,7 @@ Future setOrientationAndWaitUntilRotation( } while (true) { final BuildContext context = tester.element(find.byType(Text)); - if (expectedOrientation == MediaQuery.of(context).orientation) { + if (context.mounted && expectedOrientation == MediaQuery.of(context).orientation) { break; } await tester.pumpAndSettle(); From f5f9f351f0f80d6097d1ae179d947395ffc20078 Mon Sep 17 00:00:00 2001 From: Nate Biggs Date: Wed, 28 May 2025 17:47:17 -0400 Subject: [PATCH 13/66] Add dynamic module loader to flutter wasm entrypoint script. (#169313) Adds support for loading dynamic module files to the Flutter wasm entrypoint script. The Dart SDK already tries to import this function when dynamic modules are enabled. ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Nate Biggs --- .../lib/web_ui/flutter_js/src/entrypoint_loader.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js b/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js index f7c35aee5294e..9a8176da85341 100644 --- a/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js +++ b/engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js @@ -174,7 +174,17 @@ export class FlutterEntrypointLoader { importsPromise = Promise.resolve({}); } const compiledDartApp = await compiledDartAppPromise; - const dartApp = await compiledDartApp.instantiate(await importsPromise); + const dartApp = await compiledDartApp.instantiate(await importsPromise, { + loadDynamicModule: async (wasmUri, mjsUri) => { + const wasmBytes = fetch(resolveUrlWithSegments(entrypointBaseUrl, wasmUri)); + let mjsRuntimeUri = resolveUrlWithSegments(entrypointBaseUrl, mjsUri); + if (this._ttPolicy != null) { + mjsRuntimeUri = this._ttPolicy.createScriptURL(mjsRuntimeUri); + } + const mjsModule = import(mjsRuntimeUri); + return [await wasmBytes, await mjsModule]; + } + }); await dartApp.invokeMain(); } } From f2625754b316b5c1739828226f2c48945f9962d7 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Wed, 28 May 2025 18:52:39 -0500 Subject: [PATCH 14/66] Fix minify logic (#169607) It's meant to be ignored unless explicitly set. Introduced in https://github.com/flutter/flutter/commit/cb3150f998481913088974b20f78b384eb32ee9e --- .../lib/src/commands/build_web.dart | 2 +- .../lib/src/web/compiler_config.dart | 9 ++++++--- .../commands.shard/hermetic/build_web_test.dart | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index f930f2fbfa894..003503dfa0eb3 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -175,7 +175,7 @@ class BuildWebCommand extends BuildSubCommand { ); final bool sourceMaps = boolArg('source-maps'); - final bool minify = boolArg('minify'); + final bool? minify = argResults!.wasParsed('minify') ? boolArg('minify') : null; final List compilerConfigs; diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart index 10d5757b4d89c..8978e0847e22f 100644 --- a/packages/flutter_tools/lib/src/web/compiler_config.dart +++ b/packages/flutter_tools/lib/src/web/compiler_config.dart @@ -38,6 +38,7 @@ sealed class WebCompilerConfig { /// Returns which target this compiler outputs (js or wasm) CompileTarget get compileTarget; final WebRendererMode renderer; + List toCommandOptions(BuildMode buildMode); String get buildKey; @@ -112,6 +113,7 @@ class JsCompilerConfig extends WebCompilerConfig { /// Arguments to use in the full JS compile, but not CFE-only. /// /// Includes the contents of [toSharedCommandOptions]. + @override List toCommandOptions(BuildMode buildMode) => [ if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', ...toSharedCommandOptions(buildMode), @@ -130,7 +132,7 @@ class JsCompilerConfig extends WebCompilerConfig { 'nativeNullAssertions': nativeNullAssertions, 'noFrequencyBasedMinification': noFrequencyBasedMinification, 'minify': minify, - 'sourceMaps': sourceMaps, + WebCompilerConfig.kSourceMapsEnabled: sourceMaps, }; return jsonEncode(settings); } @@ -167,6 +169,7 @@ class WasmCompilerConfig extends WebCompilerConfig { BuildMode.jitRelease => throw ArgumentError('Invalid build mode for web'), }; + @override List toCommandOptions(BuildMode buildMode) { final bool stripSymbols = buildMode == BuildMode.release && stripWasm; return [ @@ -181,8 +184,8 @@ class WasmCompilerConfig extends WebCompilerConfig { String get buildKey { final Map settings = { ...super._buildKeyMap, - 'stripWasm': stripWasm, - 'sourceMaps': sourceMaps, + kStripWasm: stripWasm, + WebCompilerConfig.kSourceMapsEnabled: sourceMaps, }; return jsonEncode(settings); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart index 57dd06dc8114b..82f20eba8d534 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart @@ -400,7 +400,7 @@ void main() { ); testUsingContext( - 'Defaults to web renderer canvaskit mode when no option is specified', + 'Defaults to web renderer canvaskit and minify mode when no option is specified', () async { final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); final CommandRunner runner = createTestCommandRunner(buildCommand); @@ -419,8 +419,17 @@ void main() { ) { expect(target, isA()); final List configs = (target as WebServiceWorker).compileConfigs; - expect(configs.length, 1); - expect(configs.first.renderer, WebRendererMode.canvaskit); + expect(configs, hasLength(1)); + final WebCompilerConfig config = configs.single; + expect(config.renderer, WebRendererMode.canvaskit); + expect(config.compileTarget, CompileTarget.js); + final List options = config.toCommandOptions(BuildMode.release); + expect(options, [ + '--minify', + '--native-null-assertions', + '--no-source-maps', + '-O4', + ]); }), }, ); @@ -445,7 +454,7 @@ void main() { ) { expect(target, isA()); final List configs = (target as WebServiceWorker).compileConfigs; - expect(configs.length, 2); + expect(configs, hasLength(2)); expect(configs[0].renderer, WebRendererMode.skwasm); expect(configs[0].compileTarget, CompileTarget.wasm); expect(configs[1].renderer, WebRendererMode.canvaskit); From 9c89a8fff9e6eb0a1065f99dafeb1c8a172a4d16 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 29 May 2025 08:39:26 -0400 Subject: [PATCH 15/66] Roll Skia from cc7963935d9d to 274d78ef2666 (21 revisions) (#169665) https://skia.googlesource.com/skia.git/+log/cc7963935d9d..274d78ef2666 2025-05-29 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll ANGLE from 2a18fdbf4c8c to e7118451f513 (18 revisions) 2025-05-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 8888289eb6d9 to 58febb14bdad (6 revisions) 2025-05-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll Dawn from 0dc9ec06d441 to f53bc591dafd (28 revisions) 2025-05-29 syoussefi@google.com [vulkan] Switch to VK_EXT_debug_utils 2025-05-29 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-28 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-28 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-28 danieldilan@google.com Add bounds check to onDrawPoints for ganesh Device 2025-05-28 bungeman@google.com [gn] Remove msvc env setting 2025-05-28 michaelludwig@google.com [graphite] Separate HSL and regular color matrix filter shaders 2025-05-28 kainino@chromium.org [graphite] Handle Dawn breaking change in QueueWorkDoneCallback 2025-05-28 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-28 kjlubick@google.com Rename SkRecorder::Type::kRaster -> kCPU 2025-05-28 thomsmit@google.com [graphite] Add test for static vertices padding. 2025-05-28 lukasza@google.com Revert "[rust png] Round-trip `kOpaque_SkAlphaType` when encoding." 2025-05-28 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-28 syoussefi@google.com [graphite][vulkan] Prepare for more extensive property queries 2025-05-28 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 9b8253ba5637 to 8888289eb6d9 (8 revisions) 2025-05-28 kjlubick@google.com Fix integer overflow in SkSL RP code 2025-05-28 lukasza@chromium.org [rust png] Round-trip `kOpaque_SkAlphaType` when encoding. If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC codefu@google.com,kjlubick@google.com,nicolettep@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 69d93bd8166d5..27adcfb99d089 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'cc7963935d9dd21630a15ef9d387296db936ef03', + 'skia_revision': '274d78ef26665c0d31efb4730629338d709a7e8d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/engine/src/flutter/ci/licenses_golden/licenses_skia b/engine/src/flutter/ci/licenses_golden/licenses_skia index c37a342db8877..5c5c6e5996c37 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_skia +++ b/engine/src/flutter/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: aebc333eca857a2ca876b998e04ccf66 +Signature: ddb6b26375f26587a0adee6403c032d1 ==================================================================================================== LIBRARY: etc1 @@ -9895,6 +9895,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia +ORIGIN: ../../../flutter/third_party/skia/gm/hdr_pip_blur.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/core/SkCPUContext.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/core/SkCPURecorder.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/core/SkRecorder.h + ../../../flutter/third_party/skia/LICENSE @@ -9926,6 +9927,7 @@ ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/Serializat ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp + ../../../flutter/third_party/skia/LICENSE TYPE: LicenseType.bsd +FILE: ../../../flutter/third_party/skia/gm/hdr_pip_blur.cpp FILE: ../../../flutter/third_party/skia/include/core/SkCPUContext.h FILE: ../../../flutter/third_party/skia/include/core/SkCPURecorder.h FILE: ../../../flutter/third_party/skia/include/core/SkRecorder.h From 8b18dde77fa59ba7f87540c05d1aba787198e77a Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Thu, 29 May 2025 09:35:15 -0400 Subject: [PATCH 16/66] Reduce some CI timeouts (#169512) - `Linux docs_test`: Has been running consistently under 25m, while timeout was set at 90m. - `Linux coverage`: Has been running consistently under 1.2h (~75m), while timeout was set at 120m. --- .ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 7ad58fcc96ed5..f6a85130f01b6 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -394,7 +394,7 @@ targets: bringup: true # https://github.com/flutter/flutter/issues/164591 presubmit: false recipe: flutter/coverage - timeout: 120 + timeout: 90 enabled_branches: # Don't run this on release branches - master @@ -617,7 +617,7 @@ targets: - name: Linux docs_test recipe: flutter/flutter_drone - timeout: 90 # https://github.com/flutter/flutter/issues/120901 + timeout: 30 properties: cores: "32" dependencies: >- From 5df6008ec7e8527243fb77e00ff320fd56a1f04c Mon Sep 17 00:00:00 2001 From: stuartmorgan-g Date: Thu, 29 May 2025 07:27:06 -0700 Subject: [PATCH 17/66] Update triage for new team-devexp (#169668) Adds the new `team-devexp` to the flowchart, and updates references to `d: devtools` to reflect that it's now `a: devtools`. --- docs/triage/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/triage/README.md b/docs/triage/README.md index f9ffc110a66ff..e51acaecfc5ca 100644 --- a/docs/triage/README.md +++ b/docs/triage/README.md @@ -83,6 +83,7 @@ In general the flow chart for team assignment is as follows, stopping as soon as - If it's about the Flutter engine, add `team-engine`. - If it's about the Flutter framework, add `team-framework`. - If it's about the Flutter tool, add `team-tool`. +- If it's about developer tools, add `team-devexp`. - If it's about a first-party package: - If it's about `go_router` or `go_router_builder`, add `team-go_router`. - If it's about `two_dimensional_scrollables`, add `team-framework`. @@ -92,7 +93,7 @@ In general the flow chart for team assignment is as follows, stopping as soon as _It is expected that some bugs will end up being re-assigned to a different team during secondary triage. If there are specific categories of issues where this always happens, the flow chart above should be updated accordingly, but having it happen occasionally is just the process working as expected; in some cases only the engineers working on an issue will know how the work is divided among teams._ -Bugs relating to the developer tools should be moved to the `flutter/devtools` repo, unless it looks like the first step is a change to the core parts of Flutter (in which case it should receive the `d: devtools` label as well as the pertinent labels for where the work should occur). Issues tagged with `d: devtools` or moved to the `flutter/devtools` repo will be triaged as described by [flutter/devtools/wiki/Triage](https://github.com/flutter/devtools/wiki/Triage). +Bugs relating to the developer tools should be moved to the `flutter/devtools` repo, unless it looks like the first step is a change to the core parts of Flutter (in which case it should receive the `a: devtools` label as well as the pertinent labels for where the work should occur). Issues tagged with `team-devexp` and/or `a: devtools`, or moved to the `flutter/devtools` repo, will be triaged as described by [flutter/devtools/wiki/Triage](https://github.com/flutter/devtools/wiki/Triage). Bugs relating to the IntelliJ IDEs should be moved to the `flutter/flutter-intellij` repo, unless it looks like the first step is a change to the core parts of Flutter (in which case it should receive the `d: intellij` label as well as the pertinent labels for where the work should occur). Issues tagged with `d: intellij` will be reviewed by the Flutter IntelliJ team as described by [flutter/flutter-intellij/wiki/Triaging](https://github.com/flutter/flutter-intellij/wiki/Triaging). From 8abf4e7a545897dfd4ef54e8456af299ec9fa3f3 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 29 May 2025 07:27:10 -0700 Subject: [PATCH 18/66] [Impeller] Maintain a global map of each context's currently active thread-local command pools (#169548) The Impeller Vulkan back end creates a thread-local map of contexts to CommandPoolVK instances for each thread that uses Vulkan. This allows a thread to obtain the CommandPoolVK that is currently in use for a given context. When a context is shut down, the Vulkan resources used by each thread's local CommandPoolVK for that context must be freed. To do this, CommandPoolVK maintains a global map of CommandPoolVK instances. Prior to this PR Impeller was appending to the context's pool list in the global map each time a new CommandPoolVK was created. In the original implementation this worked because Impeller was only creating one CommandPoolVK per thread for a given context. However, CommandPoolVK later adopted a recycling scheme where each frame creates a new CommandPoolVK instance that acquires a Vulkan command pool from the CommandPoolRecyclerVK. So inserting every CommandPoolVK into the global map will cause the global map to grow unbounded. This PR changes the structure of the global map. The global map will now associate each context with a map of thread IDs to the CommandPoolVK that is currently placed in the thread's local storage. When a thread calls CommandPoolRecyclerVK::Dispose to clear its thread-local CommandPoolVK for a context, the corresponding entry is also removed from the global map. Fixes https://github.com/flutter/flutter/issues/169208 --- .../golden_playground_test_mac.cc | 8 ++++ .../backend/vulkan/command_pool_vk.cc | 47 ++++++++++++------- .../renderer/backend/vulkan/command_pool_vk.h | 17 ++++--- .../vulkan/command_pool_vk_unittests.cc | 19 ++++++++ .../renderer/backend/vulkan/context_vk.cc | 6 ++- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc b/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc index a6e6e3b66d3f4..a49cac03a61ca 100644 --- a/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc +++ b/engine/src/flutter/impeller/golden_tests/golden_playground_test_mac.cc @@ -132,6 +132,11 @@ void GoldenPlaygroundTest::SetTypographerContext( void GoldenPlaygroundTest::TearDown() { ASSERT_FALSE(dlopen("/usr/local/lib/libMoltenVK.dylib", RTLD_NOLOAD)); + + auto context = GetContext(); + if (context) { + context->DisposeThreadLocalCachedResources(); + } } namespace { @@ -280,6 +285,9 @@ RuntimeStage::Map GoldenPlaygroundTest::OpenAssetAsRuntimeStage( } std::shared_ptr GoldenPlaygroundTest::GetContext() const { + if (!pimpl_->screenshotter) { + return nullptr; + } return pimpl_->screenshotter->GetPlayground().GetContext(); } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc index d6176b2c3b808..dfa80c252b486 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc @@ -171,10 +171,23 @@ static thread_local std::unique_ptr tls_command_pool_map; // with that context. static Mutex g_all_pools_map_mutex; static std::unordered_map< - const ContextVK*, - std::vector>> g_all_pools_map + uint64_t, + std::unordered_map>> g_all_pools_map IPLR_GUARDED_BY(g_all_pools_map_mutex); +CommandPoolRecyclerVK::CommandPoolRecyclerVK( + const std::shared_ptr& context) + : context_(context), context_hash_(context->GetHash()) {} + +// Visible for testing. +// Returns the number of pools in g_all_pools_map for the given context. +int CommandPoolRecyclerVK::GetGlobalPoolCount(const ContextVK& context) { + Lock all_pools_lock(g_all_pools_map_mutex); + auto it = g_all_pools_map.find(context.GetHash()); + return it != g_all_pools_map.end() ? it->second.size() : 0; +} + // TODO(matanlurey): Return a status_or<> instead of nullptr when we have one. std::shared_ptr CommandPoolRecyclerVK::Get() { auto const strong_context = context_.lock(); @@ -187,8 +200,7 @@ std::shared_ptr CommandPoolRecyclerVK::Get() { tls_command_pool_map.reset(new CommandPoolMap()); } CommandPoolMap& pool_map = *tls_command_pool_map.get(); - auto const hash = strong_context->GetHash(); - auto const it = pool_map.find(hash); + auto const it = pool_map.find(context_hash_); if (it != pool_map.end()) { return it->second; } @@ -201,11 +213,11 @@ std::shared_ptr CommandPoolRecyclerVK::Get() { auto const resource = std::make_shared( std::move(data->pool), std::move(data->buffers), context_); - pool_map.emplace(hash, resource); + pool_map.emplace(context_hash_, resource); { Lock all_pools_lock(g_all_pools_map_mutex); - g_all_pools_map[strong_context.get()].push_back(resource); + g_all_pools_map[context_hash_][std::this_thread::get_id()] = resource; } return resource; @@ -275,30 +287,33 @@ void CommandPoolRecyclerVK::Reclaim( RecycledData{.pool = std::move(pool), .buffers = std::move(buffers)}); } -CommandPoolRecyclerVK::~CommandPoolRecyclerVK() { - // Ensure all recycled pools are reclaimed before this is destroyed. - Dispose(); -} - void CommandPoolRecyclerVK::Dispose() { CommandPoolMap* pool_map = tls_command_pool_map.get(); if (pool_map) { - pool_map->clear(); + pool_map->erase(context_hash_); + } + + { + Lock all_pools_lock(g_all_pools_map_mutex); + auto found = g_all_pools_map.find(context_hash_); + if (found != g_all_pools_map.end()) { + found->second.erase(std::this_thread::get_id()); + } } } -void CommandPoolRecyclerVK::DestroyThreadLocalPools(const ContextVK* context) { +void CommandPoolRecyclerVK::DestroyThreadLocalPools() { // Delete the context's entry in this thread's command pool map. if (tls_command_pool_map.get()) { - tls_command_pool_map.get()->erase(context->GetHash()); + tls_command_pool_map.get()->erase(context_hash_); } // Destroy all other thread-local CommandPoolVK instances associated with // this context. Lock all_pools_lock(g_all_pools_map_mutex); - auto found = g_all_pools_map.find(context); + auto found = g_all_pools_map.find(context_hash_); if (found != g_all_pools_map.end()) { - for (auto& weak_pool : found->second) { + for (auto& [thread_id, weak_pool] : found->second) { auto pool = weak_pool.lock(); if (!pool) { continue; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h index 30f2b3c3688ae..1fc9d06b32fb4 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk.h @@ -103,8 +103,6 @@ class CommandPoolVK final { class CommandPoolRecyclerVK final : public std::enable_shared_from_this { public: - ~CommandPoolRecyclerVK(); - /// A unique command pool and zero or more recycled command buffers. struct RecycledData { vk::UniqueCommandPool pool; @@ -112,16 +110,13 @@ class CommandPoolRecyclerVK final }; /// @brief Clean up resources held by all per-thread command pools - /// associated with the given context. - /// - /// @param[in] context The context. - static void DestroyThreadLocalPools(const ContextVK* context); + /// associated with the context. + void DestroyThreadLocalPools(); /// @brief Creates a recycler for the given |ContextVK|. /// /// @param[in] context The context to create the recycler for. - explicit CommandPoolRecyclerVK(std::weak_ptr context) - : context_(std::move(context)) {} + explicit CommandPoolRecyclerVK(const std::shared_ptr& context); /// @brief Gets a command pool for the current thread. /// @@ -137,11 +132,15 @@ class CommandPoolRecyclerVK final std::vector&& buffers, bool should_trim = false); - /// @brief Clears all recycled command pools to let them be reclaimed. + /// @brief Clears this context's thread-local command pool. void Dispose(); + // Visible for testing. + static int GetGlobalPoolCount(const ContextVK& context); + private: std::weak_ptr context_; + uint64_t context_hash_; Mutex recycled_mutex_; std::vector recycled_ IPLR_GUARDED_BY(recycled_mutex_); diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc index 42da1b896e50f..69b4e06c4ea6c 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/command_pool_vk_unittests.cc @@ -228,5 +228,24 @@ TEST(CommandPoolRecyclerVKTest, ExtraCommandBufferAllocationsTriggerTrim) { context->Shutdown(); } +TEST(CommandPoolRecyclerVKTest, RecyclerGlobalPoolMapSize) { + auto context = MockVulkanContextBuilder().Build(); + auto const recycler = context->GetCommandPoolRecycler(); + + // The global pool list for this context should initially be empty. + EXPECT_EQ(CommandPoolRecyclerVK::GetGlobalPoolCount(*context), 0); + + // Creating a pool for this thread should insert the pool into the global map. + auto pool = recycler->Get(); + EXPECT_EQ(CommandPoolRecyclerVK::GetGlobalPoolCount(*context), 1); + + // Disposing this thread's pool should remove it from the global map. + pool.reset(); + recycler->Dispose(); + EXPECT_EQ(CommandPoolRecyclerVK::GetGlobalPoolCount(*context), 0); + + context->Shutdown(); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 6066065ca2b34..a9a42ad35a560 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -134,7 +134,9 @@ ContextVK::~ContextVK() { if (device_holder_ && device_holder_->device) { [[maybe_unused]] auto result = device_holder_->device->waitIdle(); } - CommandPoolRecyclerVK::DestroyThreadLocalPools(this); + if (command_pool_recycler_) { + command_pool_recycler_->DestroyThreadLocalPools(); + } } Context::BackendType ContextVK::GetBackendType() const { @@ -421,7 +423,7 @@ void ContextVK::Setup(Settings settings) { } auto command_pool_recycler = - std::make_shared(weak_from_this()); + std::make_shared(shared_from_this()); if (!command_pool_recycler) { VALIDATION_LOG << "Could not create command pool recycler."; return; From fdc8c20d0d68e9f51a0c1d1dae2d34def1606d0f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 29 May 2025 10:56:57 -0400 Subject: [PATCH 19/66] Roll Skia from 274d78ef2666 to 58f43e55f1ba (1 revision) (#169669) https://skia.googlesource.com/skia.git/+log/274d78ef2666..58f43e55f1ba 2025-05-29 ccameron@chromium.org skcms_TFType: Add default to switch statements If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC codefu@google.com,kjlubick@google.com,nicolettep@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 27adcfb99d089..3687009c54054 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '274d78ef26665c0d31efb4730629338d709a7e8d', + 'skia_revision': '58f43e55f1bace20db6549c9df60224a10dfdfe1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/engine/src/flutter/ci/licenses_golden/licenses_skia b/engine/src/flutter/ci/licenses_golden/licenses_skia index 5c5c6e5996c37..3fc9ea80b83f9 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_skia +++ b/engine/src/flutter/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ddb6b26375f26587a0adee6403c032d1 +Signature: d6d4946d982498335b54856dfd82e238 ==================================================================================================== LIBRARY: etc1 From f582fcbb04188ad6785f6ef32a29f07a51e0a20f Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 29 May 2025 11:53:08 -0400 Subject: [PATCH 20/66] Roll customer_testing to 7f55026290e721fc648d3811664bbf3abca911d5 (#169671) --- dev/customer_testing/tests.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/customer_testing/tests.version b/dev/customer_testing/tests.version index 0ebc04f747379..62beb57172b0b 100644 --- a/dev/customer_testing/tests.version +++ b/dev/customer_testing/tests.version @@ -1 +1 @@ -c9cbc600e3974fb5f2fe505def53f1dc11cefda7 +7f55026290e721fc648d3811664bbf3abca911d5 From 2a821a70de86804d98e5b70ce9041211ba79b134 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 29 May 2025 12:41:49 -0400 Subject: [PATCH 21/66] Roll Packages from 5743798ede97 to 44630668aec6 (5 revisions) (#169674) https://github.com/flutter/packages/compare/5743798ede97...44630668aec6 2025-05-29 15619084+vashworth@users.noreply.github.com Allow tests to use macOS 14 or 15.5 (flutter/packages#9328) 2025-05-29 sokolovskyi.konstantin@gmail.com [camera_web] Remove mocktail dependency. (flutter/packages#9195) 2025-05-28 engine-flutter-autoroll@skia.org Roll Flutter from 4372bfbc6c23 to 0e536eb9fe4b (27 revisions) (flutter/packages#9334) 2025-05-28 robert.odrowaz@leancode.pl [camera_avfoundation] Implementation swift migration - part 3.5 (flutter/packages#9254) 2025-05-28 15619084+vashworth@users.noreply.github.com [webview_flutter_wkwebview] Fix `testNilRequest` test for macOS 15.5 (flutter/packages#9330) 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-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 9f1e57a5beb2a..f437e1dfd01b7 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -5743798ede9713b66c6e97d31d29e217af8ce958 +44630668aec62e9fdef92a761d5cd045c26c0828 From 0d349d78431a6c39aac6edb9312ee193cfb26466 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Thu, 29 May 2025 10:06:51 -0700 Subject: [PATCH 22/66] [reland] Make build_android_host_app_with_module_aar build using an aar (#169311) Relands https://github.com/flutter/flutter/pull/169171. I needed to copy the configuration from the FGP that respects the `engine.realm` file if it exists. Link to passing run on last commit, when using a local engine: https://ci.chromium.org/ui/p/flutter/builders/try/Linux%20build_android_host_app_with_module_aar/8596/overview Link to failure before the fix: https://ci.chromium.org/ui/p/flutter/builders/try/Linux%20build_android_host_app_with_module_aar/8505/overview ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Gray Mackall --- ...uild_android_host_app_with_module_aar.dart | 14 ++++++- .../app/build.gradle | 9 +++- .../settings.gradle | 42 ++++++++++++++++++- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart b/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart index ddd685646be6f..85f28b75049b9 100644 --- a/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart +++ b/dev/devicelab/bin/tasks/build_android_host_app_with_module_aar.dart @@ -214,6 +214,17 @@ class ModuleTest { return TaskResult.failure('Failed to build editable host .apk'); } + section('Flutter build aar succeeds'); + + await inDirectory(projectDir, () async { + await flutter( + 'build', + options: ['aar', '--no-profile'], + output: stdout, + stderr: stderr, + ); + }); + section('Add to existing Android app'); final Directory hostApp = Directory(path.join(tempDir.path, 'hello_host_app')); @@ -237,13 +248,12 @@ class ModuleTest { ); // Modify gradle version to the passed in version. - // This is somehow the wrong file. final File gradleWrapperProperties = File( path.join(hostApp.path, 'gradle', 'wrapper', 'gradle-wrapper.properties'), ); String propertyContent = await gradleWrapperProperties.readAsString(); propertyContent = propertyContent.replaceFirst('REPLACEME', gradleVersion); - section(propertyContent); + section('Modify gradle wrapper file contents'); await gradleWrapperProperties.writeAsString(propertyContent, flush: true); // Modify AGP version to the passed in version. diff --git a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle index 518a685691b97..f21e519eb06bd 100644 --- a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle +++ b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/app/build.gradle @@ -29,8 +29,15 @@ android { versionCode 1 versionName "1.0" } + buildTypes { + profile { + initWith debug + } + } } dependencies { - implementation project(':flutter') + debugImplementation 'io.flutter.devicelab.hello:flutter_debug:1.0' + profileImplementation 'io.flutter.devicelab.hello:flutter_profile:1.0' + releaseImplementation 'io.flutter.devicelab.hello:flutter_release:1.0' } diff --git a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle index 6c933debbaf4c..5368feb7ecde7 100644 --- a/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle +++ b/dev/integration_tests/pure_android_host_apps/android_host_app_v2_embedding/settings.gradle @@ -2,6 +2,44 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositories { + google() + mavenCentral() + def flutterStorageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://storage.googleapis.com" + maven { + url = uri("$flutterStorageUrl/download.flutter.io") + } + maven { + url = uri("../hello/build/host/outputs/repo") + } + // BEGIN ci only configuration for getting engine artifacts in pre-submit environments + def flutterSdkPath = { + def properties = new Properties() + file("../hello/.android/local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + + settings.ext.flutterSdkPath = flutterSdkPath() + + def engineRealm = + new File("${settings.ext.flutterSdkPath}/bin/cache/engine.realm") + .getText('UTF-8') + .trim() + + if (engineRealm) { // In Groovy, a non-empty string is true + engineRealm += "/" + } + + maven { + url = uri("${flutterStorageUrl}/${engineRealm}download.flutter.io") + } + + // END ci only configuration for getting engine artifacts in pre-submit environments + } +} + include ':app' -setBinding(new Binding([gradle: this])) -evaluate(new File(settingsDir.parentFile, 'hello/.android/include_flutter.groovy')) From c6fe412e9a06b634eb0d8942a04d9321a96103eb Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Thu, 29 May 2025 10:30:32 -0700 Subject: [PATCH 23/66] Re-enable SelectableRegion web tests (#169541) This change re-enables some `SelectableRegion` tests now that https://github.com/flutter/flutter/issues/125582 has been closed. ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --------- Co-authored-by: Renzo Olivares --- .../widgets/scrollable_selection_test.dart | 9 +- .../test/widgets/selectable_region_test.dart | 86 ++++++++++++++++++- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/packages/flutter/test/widgets/scrollable_selection_test.dart b/packages/flutter/test/widgets/scrollable_selection_test.dart index a21bf8f35da5e..807e40e8567d1 100644 --- a/packages/flutter/test/widgets/scrollable_selection_test.dart +++ b/packages/flutter/test/widgets/scrollable_selection_test.dart @@ -4,7 +4,6 @@ import 'dart:ui' as ui; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -188,7 +187,7 @@ void main() { expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('mouse can select multiple widgets on double-click drag - horizontal', ( WidgetTester tester, @@ -238,7 +237,7 @@ void main() { expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('mouse can select multiple widgets on triple-click drag', ( WidgetTester tester, @@ -310,7 +309,7 @@ void main() { expect(paragraph4.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('mouse can select multiple widgets on triple-click drag - horizontal', ( WidgetTester tester, @@ -372,7 +371,7 @@ void main() { expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); await gesture.up(); - }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + }); testWidgets('select to scroll forward', (WidgetTester tester) async { final ScrollController controller = ScrollController(); diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 2e4b6f6d8eaee..6c5104294208f 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -443,8 +443,88 @@ void main() { expect(pageController.page, isNotNull); expect(pageController.page, 1.0); }, - variant: TargetPlatformVariant.mobile(), - skip: kIsWeb, // https://github.com/flutter/flutter/issues/125582. + variant: const TargetPlatformVariant({ + TargetPlatform.android, + TargetPlatform.fuchsia, + }), + // [intended] Web does not support double tap + drag gestures on the tested platforms. + skip: kIsWeb, + ); + + testWidgets( + 'Vertical PageView beats SelectionArea child touch drag gestures on iOS', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/150897. + final PageController pageController = PageController(); + const String testValue = 'abc def ghi jkl mno pqr stu vwx yz'; + addTearDown(pageController.dispose); + + await tester.pumpWidget( + MaterialApp( + home: PageView( + scrollDirection: Axis.vertical, + controller: pageController, + children: [ + Center( + child: SelectableRegion( + selectionControls: materialTextSelectionControls, + child: const Text(testValue), + ), + ), + const SizedBox(height: 200.0, child: Center(child: Text('Page 2'))), + ], + ), + ), + ); + + final RenderParagraph paragraph = tester.renderObject( + find.descendant(of: find.text(testValue), matching: find.byType(RichText)), + ); + final Offset gPos = textOffsetToPosition(paragraph, testValue.indexOf('g')); + final Offset pPos = textOffsetToPosition(paragraph, testValue.indexOf('p')); + + // A double tap + drag should take precedence over parent drags. + final TestGesture gesture = await tester.startGesture(gPos); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await gesture.down(gPos); + await tester.pumpAndSettle(); + await gesture.moveTo(pPos); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph.selections, isNotEmpty); + expect( + paragraph.selections[0], + TextSelection( + baseOffset: testValue.indexOf('g'), + extentOffset: testValue.indexOf('p') + 3, + ), + ); + + expect(pageController.page, isNotNull); + expect(pageController.page, 0.0); + // A vertical drag directly on the SelectableRegion should move the page + // view to the next page. + final Rect selectableTextRect = tester.getRect(find.byType(SelectableRegion)); + // Simulate a pan by drag vertically first. + await gesture.down(selectableTextRect.center); + await tester.pump(); + await gesture.moveTo(selectableTextRect.center + const Offset(0.0, -200.0)); + // Introduce horizontal movement. + await gesture.moveTo(selectableTextRect.center + const Offset(5.0, -300.0)); + await gesture.moveTo(selectableTextRect.center + const Offset(-10.0, -400.0)); + // Continue dragging vertically. + await gesture.moveTo(selectableTextRect.center + const Offset(0.0, -500.0)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(pageController.page, isNotNull); + expect(pageController.page, 1.0); + }, + variant: TargetPlatformVariant.only(TargetPlatform.iOS), ); testWidgets('mouse single-click selection collapses the selection', ( @@ -6261,7 +6341,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('Copy'), findsNothing); }, - skip: !kIsWeb, // [intended] + skip: !kIsWeb, // [intended] This test verifies web behavior. ); }); From a7bab0fe865e066904c0a652468d909374143ea7 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 29 May 2025 12:35:29 -0500 Subject: [PATCH 24/66] [web] Pass the same optimization level to both stages of JS compiler (#169642) Ensures that late variables names are cleaned up Fixes https://github.com/flutter/flutter/issues/134423 --- .../lib/src/web/compiler_config.dart | 2 +- .../build_system/targets/web_test.dart | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart index 8978e0847e22f..a0f1610a3d281 100644 --- a/packages/flutter_tools/lib/src/web/compiler_config.dart +++ b/packages/flutter_tools/lib/src/web/compiler_config.dart @@ -97,6 +97,7 @@ class JsCompilerConfig extends WebCompilerConfig { if (nativeNullAssertions) '--native-null-assertions', if (!sourceMaps) '--no-source-maps', if (buildMode == BuildMode.debug) '--enable-asserts', + '-O${optimizationLevelForBuildMode(buildMode)}', ]; @override @@ -117,7 +118,6 @@ class JsCompilerConfig extends WebCompilerConfig { List toCommandOptions(BuildMode buildMode) => [ if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', ...toSharedCommandOptions(buildMode), - '-O${optimizationLevelForBuildMode(buildMode)}', if (dumpInfo) '--stage=dump-info-all', if (noFrequencyBasedMinification) '--no-frequency-based-minification', if (csp) '--csp', diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index 13a2f6e361763..03cdbc85af4cf 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -523,6 +523,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -566,6 +567,7 @@ name: foo '-DFLUTTER_WEB_USE_SKIA=true', '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -609,6 +611,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -654,6 +657,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -698,6 +702,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -741,6 +746,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -785,6 +791,7 @@ name: foo '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--native-null-assertions', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -831,6 +838,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O3', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -876,6 +884,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -936,6 +945,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -981,6 +991,7 @@ name: foo '-DFLUTTER_WEB_USE_SKIA=true', '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -1026,6 +1037,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -1074,6 +1086,7 @@ name: foo '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', '--enable-asserts', + '-O1', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -1119,6 +1132,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -1165,6 +1179,7 @@ name: foo '-DFLUTTER_WEB_USE_SKWASM=false', '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', '--no-source-maps', + '-O4', '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', From ae11f77f20ffd0ecf8ee1f7053b42d134f7bce3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kilczan?= Date: Thu, 29 May 2025 19:51:19 +0200 Subject: [PATCH 25/66] Fix the "Missing ExternalProject for :" error (#168403) Fix the "Missing ExternalProject for :" error This fixes #168296 ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- packages/flutter_tools/lib/src/base/file_system.dart | 12 +++++++++++- .../test/general.shard/base/file_system_test.dart | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/base/file_system.dart b/packages/flutter_tools/lib/src/base/file_system.dart index d2a302b23235d..e07e5574fab92 100644 --- a/packages/flutter_tools/lib/src/base/file_system.dart +++ b/packages/flutter_tools/lib/src/base/file_system.dart @@ -63,7 +63,17 @@ class FileSystemUtils { /// /// On Windows it replaces all '\' with '\\'. On other platforms, it returns the /// path unchanged. - String escapePath(String path) => _platform.isWindows ? path.replaceAll(r'\', r'\\') : path; + String escapePath(String path) { + if (_platform.isWindows) { + path = path.replaceAll(r'\', r'\\'); + if (path.startsWith(RegExp('[a-z]:'))) { + // ensure that the drive letter is upper case see + // https://youtrack.jetbrains.com/issue/IDEA-329756/Importing-symlinked-Gradle-included-build-fails#focus=Comments-27-11721320.0-0 + return path[0].toUpperCase() + path.substring(1); + } + } + return path; + } /// Returns true if the file system [entity] has not been modified since the /// latest modification to [referenceFile]. diff --git a/packages/flutter_tools/test/general.shard/base/file_system_test.dart b/packages/flutter_tools/test/general.shard/base/file_system_test.dart index 2256ff0c1b496..c342d144281ba 100644 --- a/packages/flutter_tools/test/general.shard/base/file_system_test.dart +++ b/packages/flutter_tools/test/general.shard/base/file_system_test.dart @@ -316,6 +316,9 @@ void main() { expect(fsUtils.escapePath(r'C:\foo\bar\cool.dart'), r'C:\\foo\\bar\\cool.dart'); expect(fsUtils.escapePath(r'foo\bar\cool.dart'), r'foo\\bar\\cool.dart'); expect(fsUtils.escapePath('C:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart'); + expect(fsUtils.escapePath('c:/foo/bar/cool.dart'), 'C:/foo/bar/cool.dart'); + expect(fsUtils.escapePath('x:/foo/bar/cool.dart'), 'X:/foo/bar/cool.dart'); + expect(fsUtils.escapePath(r'a:\foo\bar\cool.dart'), r'A:\\foo\\bar\\cool.dart'); }); testWithoutContext('on Linux', () { From fe1c9d61a78806a8d6db5c1fc2ec6b89f53eb35a Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 29 May 2025 14:00:56 -0500 Subject: [PATCH 26/66] Validate build configuration during Xcode build phase (#169395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can run iOS/macOS Flutter apps through either the Flutter CLI or Xcode. However, it's often required to first run the Flutter CLI to generate required files and settings. Some of these settings/files (like dev dependencies) are specific to the build mode. However, you can change the build mode through Xcode too. When you change the build mode through Xcode, the Flutter-generated files and setting may not be correct. This PR checks if the current build mode matches the one last used by the Flutter CLI. If it doesn't, it'll print a warning like this: ![Screenshot 2025-05-23 at 5 14 58 PM](https://github.com/user-attachments/assets/47d15cc4-f05d-4034-8be6-67f37828aa61) If the build action is `install`, which indicates the app is being built for distribution, this will print as an error and fail the build: ![Screenshot 2025-05-23 at 5 16 12 PM](https://github.com/user-attachments/assets/339b65bd-6425-4595-b26b-a60c722bbcf9) ## 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]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- dev/devicelab/bin/tasks/module_test_ios.dart | 20 +- dev/integration_tests/ios_host_app/Podfile | 4 + .../ios_host_app/PodfileMissingPostInstall | 12 + packages/flutter_tools/bin/xcode_backend.dart | 50 +- .../flutter_tools/lib/src/build_info.dart | 3 - .../lib/src/build_system/targets/darwin.dart | 146 ----- .../lib/src/build_system/targets/ios.dart | 44 +- .../lib/src/build_system/targets/macos.dart | 34 - .../lib/src/commands/build_ios_framework.dart | 7 - .../src/commands/build_macos_framework.dart | 6 - .../flutter_tools/lib/src/ios/devices.dart | 3 - packages/flutter_tools/lib/src/ios/mac.dart | 2 - .../lib/src/ios/xcode_build_settings.dart | 16 +- .../lib/src/macos/build_macos.dart | 2 - .../flutter_tools/lib/src/xcode_project.dart | 2 - .../build_system/targets/ios_test.dart | 183 ------ .../build_system/targets/macos_test.dart | 184 ------ .../general.shard/ios/xcodeproj_test.dart | 71 +-- .../general.shard/xcode_backend_test.dart | 154 ++++- .../integration.shard/xcode_backend_test.dart | 6 +- .../xcode_dev_dependencies_test.dart | 529 ---------------- .../xcode_verify_configuration_test.dart | 588 ++++++++++++++++++ 22 files changed, 826 insertions(+), 1240 deletions(-) create mode 100644 dev/integration_tests/ios_host_app/PodfileMissingPostInstall delete mode 100644 packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart create mode 100644 packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 0a3c624ef03fa..f66178d1eb412 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -257,7 +257,7 @@ dependencies: }); await inDirectory(projectDir, () async { - await flutter('pub', options: ['get']); + await flutter('build', options: ['ios', '--config-only']); }); section('Add to existing iOS Objective-C app'); @@ -275,7 +275,13 @@ dependencies: section('Validate iOS Objective-C host app Podfile'); final File podfile = File(path.join(objectiveCHostApp.path, 'Podfile')); - String podfileContent = await podfile.readAsString(); + final String correctPodfileContents = await podfile.readAsString(); + final File podfileMissingPostInstall = File( + path.join(objectiveCHostApp.path, 'PodfileMissingPostInstall'), + ); + + podfile.writeAsStringSync(podfileMissingPostInstall.readAsStringSync()); + final String podFailure = await eval( 'pod', ['install'], @@ -289,18 +295,12 @@ dependencies: !podFailure.contains( 'Add `flutter_post_install(installer)` to your Podfile `post_install` block to build Flutter plugins', )) { - print(podfileContent); + print(podfile.readAsStringSync()); throw TaskResult.failure( 'pod install unexpectedly succeed without "flutter_post_install" post_install block', ); } - podfileContent = ''' -$podfileContent - -post_install do |installer| - flutter_post_install(installer) -end - '''; + String podfileContent = correctPodfileContents; await podfile.writeAsString(podfileContent, flush: true); await exec( diff --git a/dev/integration_tests/ios_host_app/Podfile b/dev/integration_tests/ios_host_app/Podfile index 1301ea35cc8d1..4662a55328449 100644 --- a/dev/integration_tests/ios_host_app/Podfile +++ b/dev/integration_tests/ios_host_app/Podfile @@ -10,3 +10,7 @@ end target 'FlutterUITests' do inherit! :search_paths end + +post_install do |installer| + flutter_post_install(installer) +end diff --git a/dev/integration_tests/ios_host_app/PodfileMissingPostInstall b/dev/integration_tests/ios_host_app/PodfileMissingPostInstall new file mode 100644 index 0000000000000..1301ea35cc8d1 --- /dev/null +++ b/dev/integration_tests/ios_host_app/PodfileMissingPostInstall @@ -0,0 +1,12 @@ +platform :ios, '13.0' + +flutter_application_path = '../hello' +load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') + +target 'Host' do + install_all_flutter_pods flutter_application_path +end + +target 'FlutterUITests' do + inherit! :search_paths +end diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index f2ef7eeb9f508..e8b83e1ebb547 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -506,6 +506,8 @@ class Context { final String buildMode = parseFlutterBuildMode(); + _validateBuildMode(platform, buildMode); + final List flutterArgs = _generateFlutterArgsForAssemble( command: 'build', buildMode: buildMode, @@ -534,6 +536,53 @@ class Context { echo('Project $projectPath built and packaged successfully.'); } + /// Validate that the build mode targeted matches the build mode set by the + /// Flutter CLI. + /// If it doesn't match, print a warning unless the Xcode action is `install`, + /// which means the app is being archived for distribution. In that case, print + /// an error and fail the build. + /// + /// The targeted build mode might not match the one set by Flutter CLI when it + /// is changed and ran directly through Xcode. + /// + /// Flutter may change settings or files depending on the build mode. For + /// example, dev dependencies are excluded from release builds and requires + /// the Flutter CLI to update certain files. + void _validateBuildMode(TargetPlatform platform, String currentBuildMode) { + final String? buildModeCLILastUsed = environment['FLUTTER_CLI_BUILD_MODE']; + + // Also fail the build if ACTION=install, which indicates the app is being + // built for distribution. + final String? action = environment['ACTION']; + final bool fatal = action == 'install'; + + if (buildModeCLILastUsed == null) { + final String message = + 'Your Flutter build settings are outdated. Please run ' + '"flutter build ${platform.name} --config-only --$currentBuildMode" in your Flutter ' + 'project and try again.\n'; + if (fatal) { + echoXcodeError(message); + exitApp(-1); + } else { + echoXcodeWarning(message); + return; + } + } + if (currentBuildMode != buildModeCLILastUsed) { + final String message = + 'Your Flutter project is currently configured for $buildModeCLILastUsed mode. ' + 'Please run `flutter build ${platform.name} --config-only --$currentBuildMode` ' + 'in your Flutter project to update your settings.\n'; + if (fatal) { + echoXcodeError(message); + exitApp(-1); + } else { + echoXcodeWarning(message); + } + } + } + List _generateFlutterArgsForAssemble({ required String command, required String buildMode, @@ -626,7 +675,6 @@ class Context { '--DartDefines=${environment['DART_DEFINES'] ?? ''}', '--ExtraFrontEndOptions=${environment['EXTRA_FRONT_END_OPTIONS'] ?? ''}', '-dSrcRoot=${environment['SRCROOT'] ?? ''}', - '-dDevDependenciesEnabled=${environment['FLUTTER_DEV_DEPENDENCIES_ENABLED'] ?? ''}', ]); if (platform == TargetPlatform.ios) { diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 07414db3ff424..a4e941a9c5939 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -999,9 +999,6 @@ const String kXcodeAction = 'Action'; /// to the BUILT_PRODUCTS_DIR prior to the build. const String kXcodePreAction = 'PreBuildAction'; -// Whether the last Flutter tool invocation enabled dev dependencies. -const String kDevDependenciesEnabled = 'DevDependenciesEnabled'; - final Converter _defineEncoder = utf8.encoder.fuse(base64.encoder); final Converter _defineDecoder = base64.decoder.fuse(utf8.decoder); diff --git a/packages/flutter_tools/lib/src/build_system/targets/darwin.dart b/packages/flutter_tools/lib/src/build_system/targets/darwin.dart index 60fe4ac4bfb66..92f36377b1fef 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/darwin.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/darwin.dart @@ -5,155 +5,9 @@ import 'package:meta/meta.dart'; import '../../artifacts.dart'; -import '../../base/common.dart'; -import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; -import '../../flutter_plugins.dart'; -import '../../globals.dart' as globals; -import '../../project.dart'; import '../build_system.dart'; -import '../exceptions.dart'; - -/// A target that checks that dev dependencies are enabled on debug/profile -/// builds and disabled on release builds. -/// -/// The Flutter tool enables/disables dev dependencies using the build mode. -/// These can get out of sync if the user switches the build mode in Xcode. -/// -/// Implementers should override [CheckDevDependencies.inputs] to add a [Source] -/// that changes when dev dependencies status changes. -abstract class CheckDevDependencies extends Target { - const CheckDevDependencies(); - - @override - List get dependencies => []; - - @override - List get inputs => [ - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/darwin.dart', - ), - Source.fromProject((FlutterProject project) => project.flutterPluginsDependenciesFile), - ]; - - @override - List get outputs => const []; - - // The command that turns on dev dependencies. - // Displayed in the error message if dev dependencies are off in a debug build. - @visibleForOverriding - String get debugBuildCommand; - - // The command that turns on dev dependencies. - // Displayed in the error message if dev dependencies are off in a profile build. - @visibleForOverriding - String get profileBuildCommand; - - // The command that turns off dev dependencies. - // Displayed in the error message if dev dependencies are off in a release build. - @visibleForOverriding - String get releaseBuildCommand; - - // Check that dev dependencies are enabled on debug or profile builds and - // disabled on release builds. - // - // The Flutter tool enables/disables dev dependencies using the build mode. - // These can get out of sync if the user switches the build mode in Xcode. - @override - Future build(Environment environment) async { - final String? buildModeEnvironment = environment.defines[kBuildMode]; - if (buildModeEnvironment == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment); - final String? devDependenciesEnabledString = environment.defines[kDevDependenciesEnabled]; - if (devDependenciesEnabledString == null) { - throw MissingDefineException(kDevDependenciesEnabled, name); - } - - final bool? devDependenciesEnabled = bool.tryParse( - environment.defines[kDevDependenciesEnabled] ?? '', - ); - if (devDependenciesEnabled == null) { - throw Exception( - 'Unexpected $kDevDependenciesEnabled define value: "$devDependenciesEnabledString"', - ); - } - - if (devDependenciesEnabled && buildMode.isRelease) { - // Supress this error if the project has no dev dependencies. - if (!_hasDevDependencies(environment)) { - environment.logger.printTrace( - 'Ignoring dev dependencies error as the project has no dev dependencies', - ); - return; - } - - _printXcodeError( - 'Release builds should not have Dart dev dependencies enabled\n' - '\n' - 'This error happens if:\n' - '\n' - '1. Your pubspec.yaml has dev dependencies\n' - '2. Your last Flutter CLI action turned on dev dependencies\n' - '3. You do a release build in Xcode\n' - '\n' - 'You can turn off Dart dev dependencies by running this in your Flutter project:\n' - '\n' - ' $releaseBuildCommand\n' - '\n', - ); - throwToolExit('Dev dependencies enabled in release build'); - } else if (!devDependenciesEnabled && !buildMode.isRelease) { - // Supress this error if the project has no dev dependencies. - if (!_hasDevDependencies(environment)) { - environment.logger.printTrace( - 'Ignoring dev dependencies error as the project has no dev dependencies', - ); - return; - } - - final bool profile = buildMode == BuildMode.profile; - _printXcodeError( - '${profile ? 'Profile' : 'Debug'} builds require Dart dev dependencies\n' - '\n' - 'This error happens if:\n' - '\n' - '1. Your pubspec.yaml has dev dependencies\n' - '2. Your last Flutter CLI action turned off dev dependencies\n' - '3. You do a debug or profile build in Xcode\n' - '\n' - 'You can turn on Dart dev dependencies by running this in your Flutter project:\n' - '\n' - ' ${profile ? profileBuildCommand : debugBuildCommand}\n' - '\n', - ); - throwToolExit('Dev dependencies disabled in ${profile ? 'profile' : 'debug'} build'); - } - } - - // Check if the iOS project has Dart dev dependencies. On error, assumes true. - bool _hasDevDependencies(Environment environment) { - // If the app has no plugins, the .flutter-plugins-dependencies file isn't generated. - final FlutterProject project = FlutterProject.fromDirectory(environment.projectDir); - final File pluginsFile = project.flutterPluginsDependenciesFile; - if (!pluginsFile.existsSync()) { - return false; - } - - try { - return flutterPluginsListHasDevDependencies(pluginsFile); - } on Exception catch (e) { - environment.logger.printWarning('Unable to parse .flutter-plugins-dependencies file:\n$e'); - return true; - } - } - - void _printXcodeError(String message) { - globals.stdio.stderrWrite('error: $message'); - } -} abstract class UnpackDarwin extends Target { const UnpackDarwin(); diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index 85c36f9b61180..8d0c6a80dae19 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -484,37 +484,6 @@ class DebugIosLLDBInit extends IosLLDBInit { BuildMode get buildMode => BuildMode.debug; } -class CheckDevDependenciesIos extends CheckDevDependencies { - const CheckDevDependenciesIos(); - - @override - String get name => 'check_dev_dependencies_ios'; - - @override - List get inputs { - return [ - ...super.inputs, - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart', - ), - - // The generated Xcode properties file contains - // the FLUTTER_DEV_DEPENDENCIES_ENABLED configuration. - // This target should re-run whenever that value changes. - Source.fromProject((FlutterProject project) => project.ios.generatedXcodePropertiesFile), - ]; - } - - @override - String get debugBuildCommand => 'flutter build ios --config-only --debug'; - - @override - String get profileBuildCommand => 'flutter build ios --config-only --profile'; - - @override - String get releaseBuildCommand => 'flutter build ios --config-only --release'; -} - /// The base class for all iOS bundle targets. /// /// This is responsible for setting up the basic App.framework structure, including: @@ -667,7 +636,6 @@ class DebugIosApplicationBundle extends IosAssetBundle { @override List get dependencies => [ - const CheckDevDependenciesIos(), const DebugUniversalFramework(), const DebugIosLLDBInit(), ...super.dependencies, @@ -699,11 +667,7 @@ class ProfileIosApplicationBundle extends _IosAssetBundleWithDSYM { String get name => 'profile_ios_bundle_flutter_assets'; @override - List get dependencies => const [ - CheckDevDependenciesIos(), - AotAssemblyProfile(), - InstallCodeAssets(), - ]; + List get dependencies => const [AotAssemblyProfile(), InstallCodeAssets()]; } /// Build a release iOS application bundle. @@ -714,11 +678,7 @@ class ReleaseIosApplicationBundle extends _IosAssetBundleWithDSYM { String get name => 'release_ios_bundle_flutter_assets'; @override - List get dependencies => const [ - CheckDevDependenciesIos(), - AotAssemblyRelease(), - InstallCodeAssets(), - ]; + List get dependencies => const [AotAssemblyRelease(), InstallCodeAssets()]; @override Future build(Environment environment) async { diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index 8b415a013d44d..72aa7c8ba9b40 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -559,7 +559,6 @@ class DebugMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { @override List get dependencies => const [ - CheckDevDependenciesMacOS(), KernelSnapshot(), DebugMacOSFramework(), DebugUnpackMacOS(), @@ -606,7 +605,6 @@ class ProfileMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { @override List get dependencies => const [ - CheckDevDependenciesMacOS(), CompileMacOSFramework(), InstallCodeAssets(), ProfileUnpackMacOS(), @@ -634,7 +632,6 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { @override List get dependencies => const [ - CheckDevDependenciesMacOS(), CompileMacOSFramework(), InstallCodeAssets(), ReleaseUnpackMacOS(), @@ -675,34 +672,3 @@ class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets { } } } - -class CheckDevDependenciesMacOS extends CheckDevDependencies { - const CheckDevDependenciesMacOS(); - - @override - String get name => 'check_dev_dependencies_macos'; - - @override - List get inputs { - return [ - ...super.inputs, - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/macos.dart', - ), - - // The generated Xcode properties file contains - // the FLUTTER_DEV_DEPENDENCIES_ENABLED configuration. - // This target should re-run whenever that value changes. - Source.fromProject((FlutterProject project) => project.macos.generatedXcodePropertiesFile), - ]; - } - - @override - String get debugBuildCommand => 'flutter build macos --config-only --debug'; - - @override - String get profileBuildCommand => 'flutter build macos --config-only --profile'; - - @override - String get releaseBuildCommand => 'flutter build macos --config-only --release'; -} diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index b1fd7ce6c2ceb..c4b37a78e954a 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -17,7 +17,6 @@ import '../build_info.dart'; import '../build_system/build_system.dart'; import '../build_system/targets/ios.dart'; import '../cache.dart'; -import '../features.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../macos/cocoapod_utils.dart'; @@ -487,11 +486,6 @@ end final Status status = globals.logger.startProgress(' ├─Building App.xcframework...'); final List frameworks = []; - // Dev dependencies are removed from release builds if the explicit package - // dependencies flag is on. - final bool devDependenciesEnabled = - !featureFlags.isExplicitPackageDependenciesEnabled || !buildInfo.mode.isRelease; - try { for (final EnvironmentType sdkType in EnvironmentType.values) { final Directory outputBuildDirectory = switch (sdkType) { @@ -514,7 +508,6 @@ end globals.artifacts!, ).map((DarwinArch e) => e.name).join(' '), kSdkRoot: await globals.xcode!.sdkLocation(sdkType), - kDevDependenciesEnabled: devDependenciesEnabled.toString(), ...buildInfo.toBuildSystemEnvironment(), }, artifacts: globals.artifacts!, diff --git a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart index 9ce44f3f9d54f..3dc4bc3eedb87 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart @@ -15,7 +15,6 @@ import '../build_info.dart'; import '../build_system/build_system.dart'; import '../build_system/targets/macos.dart'; import '../cache.dart'; -import '../features.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../macos/cocoapod_utils.dart'; @@ -234,10 +233,6 @@ end ) async { final Status status = globals.logger.startProgress(' ├─Building App.xcframework...'); try { - // Dev dependencies are removed from release builds if the explicit package - // dependencies flag is on. - final bool devDependenciesEnabled = - !featureFlags.isExplicitPackageDependenciesEnabled || !buildInfo.mode.isRelease; final Environment environment = Environment( projectDir: globals.fs.currentDirectory, packageConfigPath: packageConfigPath(), @@ -251,7 +246,6 @@ end kDarwinArchs: defaultMacOSArchsForEnvironment( globals.artifacts!, ).map((DarwinArch e) => e.name).join(' '), - kDevDependenciesEnabled: devDependenciesEnabled.toString(), ...buildInfo.toBuildSystemEnvironment(), }, artifacts: globals.artifacts!, diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index b7aed7cf48cac..a349c615cea79 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -23,7 +23,6 @@ import '../convert.dart'; import '../device.dart'; import '../device_port_forwarder.dart'; import '../device_vm_service_discovery_for_attach.dart'; -import '../features.dart'; import '../globals.dart' as globals; import '../macos/xcdevice.dart'; import '../mdns_discovery.dart'; @@ -701,7 +700,6 @@ class IOSDevice extends Device { await updateGeneratedXcodeProperties( project: FlutterProject.current(), buildInfo: debuggingOptions.buildInfo, - featureFlags: featureFlags, targetOverride: mainPath, ); } @@ -945,7 +943,6 @@ class IOSDevice extends Device { await updateGeneratedXcodeProperties( project: flutterProject, buildInfo: debuggingOptions.buildInfo, - featureFlags: featureFlags, targetOverride: mainPath, configurationBuildDir: bundle.parent.absolute.path, ); diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 97904dd30f7a6..e4f98f203b4fe 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -18,7 +18,6 @@ import '../base/utils.dart'; import '../build_info.dart'; import '../cache.dart'; import '../device.dart'; -import '../features.dart'; import '../flutter_manifest.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; @@ -290,7 +289,6 @@ Future buildXcodeProject({ project: project, targetOverride: targetOverride, buildInfo: buildInfo, - featureFlags: featureFlags, ); if (app.project.usesSwiftPackageManager) { final String? iosDeploymentTarget = buildSettings['IPHONEOS_DEPLOYMENT_TARGET']; diff --git a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart index d197625676b13..13d24cc9202b8 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -7,7 +7,6 @@ import '../base/common.dart'; import '../base/file_system.dart'; import '../build_info.dart'; import '../cache.dart'; -import '../features.dart'; import '../flutter_manifest.dart'; import '../globals.dart' as globals; import '../project.dart'; @@ -31,21 +30,14 @@ String flutterMacOSFrameworkDir(BuildMode mode, FileSystem fileSystem, Artifacts Future updateGeneratedXcodeProperties({ required FlutterProject project, required BuildInfo buildInfo, - required FeatureFlags featureFlags, String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, String? configurationBuildDir, }) async { - // Dev dependencies are removed from release builds if the explicit package - // dependencies flag is on. - final bool devDependenciesEnabled = - !featureFlags.isExplicitPackageDependenciesEnabled || !buildInfo.mode.isRelease; - final List xcodeBuildSettings = await _xcodeBuildSettingsLines( project: project, buildInfo: buildInfo, - devDependenciesEnabled: devDependenciesEnabled, targetOverride: targetOverride, useMacOSConfig: useMacOSConfig, buildDirOverride: buildDirOverride, @@ -154,7 +146,6 @@ String? parsedBuildNumber({required FlutterManifest manifest, BuildInfo? buildIn Future> _xcodeBuildSettingsLines({ required FlutterProject project, required BuildInfo buildInfo, - required bool devDependenciesEnabled, String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, @@ -190,11 +181,8 @@ Future> _xcodeBuildSettingsLines({ parsedBuildNumber(manifest: project.manifest, buildInfo: buildInfo) ?? '1'; xcodeBuildSettings.add('FLUTTER_BUILD_NUMBER=$buildNumber'); - // Whether the current project can have dev dependencies. - // If true, the project should be built using debug mode. - // If false, the project should be build using release or profile mode. - // This can be true even if the project has no dev dependencies. - xcodeBuildSettings.add('FLUTTER_DEV_DEPENDENCIES_ENABLED=$devDependenciesEnabled'); + // The current build mode being targeted. + xcodeBuildSettings.add('FLUTTER_CLI_BUILD_MODE=${buildInfo.mode.cliName}'); // CoreDevices in debug and profile mode are launched, but not built, via Xcode. // Set the CONFIGURATION_BUILD_DIR so Xcode knows where to find the app diff --git a/packages/flutter_tools/lib/src/macos/build_macos.dart b/packages/flutter_tools/lib/src/macos/build_macos.dart index 7d0e1405643fc..062ea5ce47e70 100644 --- a/packages/flutter_tools/lib/src/macos/build_macos.dart +++ b/packages/flutter_tools/lib/src/macos/build_macos.dart @@ -14,7 +14,6 @@ import '../base/terminal.dart'; import '../base/utils.dart'; import '../build_info.dart'; import '../convert.dart'; -import '../features.dart'; import '../globals.dart' as globals; import '../ios/migrations/metal_api_validation_migration.dart'; import '../ios/xcode_build_settings.dart'; @@ -149,7 +148,6 @@ Future buildMacOS({ await updateGeneratedXcodeProperties( project: flutterProject, buildInfo: buildInfo, - featureFlags: featureFlags, targetOverride: targetOverride, useMacOSConfig: true, ); diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index 8e9c98a884d7e..33635ef1b2b39 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -755,7 +755,6 @@ def __lldb_init_module(debugger: lldb.SBDebugger, _): await xcode.updateGeneratedXcodeProperties( project: parent, buildInfo: BuildInfo.dummy, - featureFlags: featureFlags, targetOverride: bundle.defaultMainPath, ); } @@ -972,7 +971,6 @@ class MacOSProject extends XcodeBasedProject { await xcode.updateGeneratedXcodeProperties( project: parent, buildInfo: BuildInfo.dummy, - featureFlags: featureFlags, useMacOSConfig: true, ); } diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart index a342f441eb436..c08fafc3d6b78 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -7,13 +7,11 @@ import 'dart:async'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/ios.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; @@ -49,32 +47,6 @@ const List _kSharedConfig = [ 'path/to/iPhoneOS.sdk', ]; -const String _kPluginsFileWithoutDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": false - } - ] - } -} -'''; - -const String _kPluginsFileWithDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": true - } - ] - } -} -'''; - void main() { late Environment environment; late MemoryFileSystem fileSystem; @@ -1274,161 +1246,6 @@ void main() { }, ); }); - - group('CheckDevDependenciesIos', () { - testUsingContext('throws if build mode define missing', () async { - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('throws if dev dependencies define missing', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'debug'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('does not throw if dev dependencies enabled in debug mode', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in release mode', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in profile mode', () async { - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if there are no dependencies', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - }); - - testUsingContext('does not throw if there are no dev dependencies', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithoutDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesIos().build(environment); - - expect( - logger.traceText, - contains('Ignoring dev dependencies error as the project has no dev dependencies'), - ); - }); - - testUsingContext('throws if dev dependencies disabled in debug mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies enabled in release mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies enabled in release build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies disabled in profile mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'profile'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in profile build'), - ), - ), - ); - }); - - testUsingContext( - 'assumes project has dev dependencies if .flutter-plugins-dependencies is malformed', - () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync('This is not valid JSON'); - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesIos().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }, - ); - }); } class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter { diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart index 9ffe1850010f6..e57483454f1af 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart @@ -5,12 +5,10 @@ import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/macos.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:test/fake.dart'; @@ -22,32 +20,6 @@ import '../../../src/fake_process_manager.dart'; import '../../../src/fakes.dart'; import '../../../src/package_config.dart'; -const String _kPluginsFileWithoutDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": false - } - ] - } -} -'''; - -const String _kPluginsFileWithDevDependencies = ''' -{ - "plugins": { - "ios": [ - { - "name": "foo_package", - "dev_dependency": true - } - ] - } -} -'''; - void main() { late Environment environment; late MemoryFileSystem fileSystem; @@ -997,162 +969,6 @@ void main() { ProcessManager: () => processManager, }, ); - - group('CheckDevDependenciesMacOS', () { - testUsingContext('throws if build mode define missing', () async { - environment.defines.remove(kBuildMode); - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('throws if dev dependencies define missing', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'debug'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA(const TypeMatcher()), - ); - }); - - testUsingContext('does not throw if dev dependencies enabled in debug mode', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in release mode', () async { - const String projectPath = 'path/to/project'; - fileSystem.directory(projectPath).createSync(recursive: true); - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if dev dependencies disabled in profile mode', () async { - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if there are no dependencies', () async { - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - }); - - testUsingContext('does not throw if there are no dev dependencies', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithoutDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await const CheckDevDependenciesMacOS().build(environment); - - expect( - logger.traceText, - contains('Ignoring dev dependencies error as the project has no dev dependencies'), - ); - }); - - testUsingContext('throws if dev dependencies disabled in debug mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies enabled in release mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'release'; - environment.defines[kDevDependenciesEnabled] = 'true'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies enabled in release build'), - ), - ), - ); - }); - - testUsingContext('throws if dev dependencies disabled in profile mode', () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync(_kPluginsFileWithDevDependencies); - - environment.defines[kBuildMode] = 'profile'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in profile build'), - ), - ), - ); - }); - - testUsingContext( - 'assumes project has dev dependencies if .flutter-plugins-dependencies is malformed', - () async { - final Directory projectDir = fileSystem.currentDirectory; - final File pluginsFile = projectDir.childFile('.flutter-plugins-dependencies'); - - pluginsFile.writeAsStringSync('This is not valid JSON'); - environment.defines[kBuildMode] = 'debug'; - environment.defines[kDevDependenciesEnabled] = 'false'; - - await expectLater( - const CheckDevDependenciesMacOS().build(environment), - throwsA( - isA().having( - (ToolExit e) => e.toString(), - 'description', - contains('Dev dependencies disabled in debug build'), - ), - ), - ); - }, - ); - }); } class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter { diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart index 427748f2b15dd..bb8ffeedf24e3 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart @@ -10,7 +10,6 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/ios/xcode_build_settings.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/project.dart'; @@ -19,7 +18,6 @@ import 'package:unified_analytics/unified_analytics.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/fake_process_manager.dart'; -import '../../src/fakes.dart'; const String xcodebuild = '/usr/bin/xcodebuild'; @@ -1109,7 +1107,6 @@ Information about project "Runner": late Artifacts localIosArtifacts; late FakePlatform macOS; late FileSystem fs; - late FeatureFlags featureFlags; setUp(() { fs = MemoryFileSystem.test(); @@ -1119,7 +1116,6 @@ Information about project "Runner": ); macOS = FakePlatform(operatingSystem: 'macos'); fs.file(xcodebuild).createSync(recursive: true); - featureFlags = TestFeatureFlags(); }); group('arm simulator', () { @@ -1176,11 +1172,7 @@ Build settings for action build and target plugin2: ''', ), ]); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect( @@ -1232,11 +1224,7 @@ Build settings for action build and target plugin2: exitCode: 1, ), ]); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect( @@ -1300,11 +1288,7 @@ Build settings for action build and target plugin2: ''', ), ]); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect( @@ -1347,11 +1331,7 @@ Build settings for action build and target plugin2: fs.directory('path/to/project'), ); await expectLater( - () => updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ), + () => updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo), throwsToolExit(message: '32-bit iOS local engine binaries are not supported.'), ); }); @@ -1366,7 +1346,7 @@ Build settings for action build and target plugin2: await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - featureFlags: featureFlags, + useMacOSConfig: true, ); @@ -1408,7 +1388,7 @@ Build settings for action build and target plugin2: await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - featureFlags: featureFlags, + useMacOSConfig: true, ); @@ -1445,11 +1425,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.readAsStringSync(), contains('EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386\n')); @@ -1468,11 +1444,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1502,11 +1474,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1532,11 +1500,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1571,11 +1535,7 @@ Build settings for action build and target plugin2: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); @@ -1627,7 +1587,6 @@ Build settings for action build and target plugin2: await updateGeneratedXcodeProperties( project: FlutterProject.fromDirectoryTest(fs.directory('path/to/project')), buildInfo: buildInfo, - featureFlags: featureFlags, ); final File localPropertiesFile = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); @@ -1865,7 +1824,7 @@ flutter: await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - featureFlags: featureFlags, + configurationBuildDir: 'path/to/project/build/ios/iphoneos', ); @@ -1891,11 +1850,7 @@ flutter: final FlutterProject project = FlutterProject.fromDirectoryTest( fs.directory('path/to/project'), ); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - featureFlags: featureFlags, - ); + await updateGeneratedXcodeProperties(project: project, buildInfo: buildInfo); final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); diff --git a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart index 93a998b73a500..1ff451367ffdf 100644 --- a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart @@ -53,7 +53,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', '-dTargetDeviceOSVersion=', 'debug_ios_bundle_flutter_assets', ], @@ -104,6 +103,7 @@ void main() { 'CONFIGURATION': buildMode, 'FLUTTER_ROOT': flutterRoot.path, 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -128,7 +128,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], if (platform == TargetPlatform.macos) ...[ '--build-inputs=/Flutter/ephemeral/FlutterInputs.xcfilelist', @@ -169,7 +168,6 @@ void main() { const String treeShake = 'true'; const String srcRoot = '/path/to/project'; const String iOSVersion = '18.3.1'; - const String devDependenciesEnabled = 'true'; final TestContext context = TestContext( ['build', platformName], { @@ -193,7 +191,7 @@ void main() { 'TREE_SHAKE_ICONS': treeShake, 'SRCROOT': srcRoot, 'TARGET_DEVICE_OS_VERSION': iOSVersion, - 'FLUTTER_DEV_DEPENDENCIES_ENABLED': devDependenciesEnabled, + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -219,7 +217,6 @@ void main() { '--DartDefines=$dartDefines', '--ExtraFrontEndOptions=$extraFrontEndOptions', '-dSrcRoot=$srcRoot', - '-dDevDependenciesEnabled=$devDependenciesEnabled', if (platform == TargetPlatform.ios) ...[ '-dTargetDeviceOSVersion=$iOSVersion', '-dCodesignIdentity=$expandedCodeSignIdentity', @@ -237,6 +234,137 @@ void main() { expect(context.stdout, contains('built and packaged successfully.')); expect(context.stderr, isEmpty); }); + + test( + 'exits with useful error message when missing FLUTTER_CLI_BUILD_MODE during archive', + () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'install', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + }, + commands: [], + fileSystem: fileSystem, + ); + expect(() => context.run(), throwsException); + expect( + context.stderr, + contains( + 'error: Your Flutter build settings are outdated. ' + 'Please run "flutter build ${platform.name} --config-only --release" ' + 'in your Flutter project and try again.', + ), + ); + }, + ); + + test('exits with useful error message when build mode mismatches during archive', () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'install', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': 'debug', + }, + commands: [], + fileSystem: fileSystem, + ); + expect(() => context.run(), throwsException); + expect( + context.stderr, + contains( + 'error: Your Flutter project is currently configured for debug mode. ' + 'Please run `flutter build ${platform.name} --config-only --release` ' + 'in your Flutter project to update your settings.', + ), + ); + }); + + test('prints useful warning message when missing FLUTTER_CLI_BUILD_MODE', () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'build', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + }, + commands: [], + fileSystem: fileSystem, + fakeProcessManager: FakeProcessManager.any(), + ); + context.run(); + expect( + context.stderr, + contains( + 'warning: Your Flutter build settings are outdated. ' + 'Please run "flutter build ${platform.name} --config-only --release" ' + 'in your Flutter project and try again.', + ), + ); + }); + + test('prints useful warning message when build mode mismatches', () { + final Directory buildDir = fileSystem.directory('/path/to/builds') + ..createSync(recursive: true); + final Directory flutterRoot = fileSystem.directory('/path/to/flutter') + ..createSync(recursive: true); + + const String buildMode = 'Release'; + + final TestContext context = TestContext( + ['build', platformName], + { + 'ACTION': 'debug', + 'CONFIGURATION': buildMode, + 'BUILT_PRODUCTS_DIR': buildDir.path, + 'FLUTTER_ROOT': flutterRoot.path, + 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': 'debug', + }, + commands: [], + fileSystem: fileSystem, + fakeProcessManager: FakeProcessManager.any(), + ); + context.run(); + expect( + context.stderr, + contains( + 'warning: Your Flutter project is currently configured for debug mode. ' + 'Please run `flutter build ${platform.name} --config-only --release` ' + 'in your Flutter project to update your settings.', + ), + ); + }); }); } @@ -281,6 +409,7 @@ void main() { 'BUILT_PRODUCTS_DIR': buildDir.path, 'FLUTTER_ROOT': flutterRoot.path, 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -332,6 +461,7 @@ void main() { 'CONFIGURATION': buildMode, 'FLUTTER_ROOT': flutterRoot.path, 'INFOPLIST_PATH': 'Info.plist', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -356,7 +486,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -389,7 +518,6 @@ void main() { const String treeShake = 'true'; const String srcRoot = '/path/to/project'; const String iOSVersion = '18.3.1'; - const String devDependenciesEnabled = 'true'; final TestContext context = TestContext( ['prepare', platformName], { @@ -413,7 +541,7 @@ void main() { 'TREE_SHAKE_ICONS': treeShake, 'SRCROOT': srcRoot, 'TARGET_DEVICE_OS_VERSION': iOSVersion, - 'FLUTTER_DEV_DEPENDENCIES_ENABLED': devDependenciesEnabled, + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -439,7 +567,6 @@ void main() { '--DartDefines=$dartDefines', '--ExtraFrontEndOptions=$extraFrontEndOptions', '-dSrcRoot=$srcRoot', - '-dDevDependenciesEnabled=$devDependenciesEnabled', if (platform == TargetPlatform.ios) ...[ '-dTargetDeviceOSVersion=$iOSVersion', '-dCodesignIdentity=$expandedCodeSignIdentity', @@ -472,6 +599,7 @@ void main() { 'ARCHS': 'arm64 x86_64', 'ONLY_ACTIVE_ARCH': 'YES', 'NATIVE_ARCH': 'arm64e', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -496,7 +624,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -527,6 +654,7 @@ void main() { 'ARCHS': 'arm64', 'ONLY_ACTIVE_ARCH': 'YES', 'NATIVE_ARCH': 'x86_64', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -551,7 +679,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -581,6 +708,7 @@ void main() { 'INFOPLIST_PATH': 'Info.plist', 'ARCHS': 'arm64 x86_64', 'NATIVE_ARCH': 'arm64e', + 'FLUTTER_CLI_BUILD_MODE': buildMode.toLowerCase(), }, commands: [ FakeCommand( @@ -605,7 +733,6 @@ void main() { '--DartDefines=', '--ExtraFrontEndOptions=', '-dSrcRoot=', - '-dDevDependenciesEnabled=', if (platform == TargetPlatform.ios) ...['-dTargetDeviceOSVersion='], '-dPreBuildAction=PrepareFramework', 'debug_unpack_$platformName', @@ -902,7 +1029,8 @@ class TestContext extends Context { required this.fileSystem, required List commands, File? scriptOutputStreamFile, - }) : processManager = FakeProcessManager.list(commands), + FakeProcessManager? fakeProcessManager, + }) : processManager = fakeProcessManager ?? FakeProcessManager.list(commands), super( arguments: arguments, environment: environment, diff --git a/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart b/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart index fdb0ee508f3ce..d422cecfcfc20 100644 --- a/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/integration.shard/xcode_backend_test.dart @@ -58,7 +58,11 @@ void main() { final ProcessResult result = await Process.run( xcodeBackendPath, ['build'], - environment: {'CONFIGURATION': 'Debug', 'ACTION': 'install'}, + environment: { + 'CONFIGURATION': 'Debug', + 'ACTION': 'install', + 'FLUTTER_CLI_BUILD_MODE': 'debug', + }, ); expect(result.stderr, contains('warning: Flutter archive not built in Release mode.')); expect(result.exitCode, isNot(0)); diff --git a/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart b/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart deleted file mode 100644 index 95c54871fa4b8..0000000000000 --- a/packages/flutter_tools/test/integration.shard/xcode_dev_dependencies_test.dart +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:file/file.dart'; -import 'package:flutter_tools/src/base/io.dart'; - -import '../src/common.dart'; -import 'test_utils.dart'; - -void main() { - late Directory tempDir; - late Directory projectDir; - - setUpAll(() async { - tempDir = createResolvedTempDirectorySync('xcode_dev_dependencies_test.'); - projectDir = tempDir.childDirectory('project')..createSync(); - final Directory tempPluginADir = tempDir.childDirectory('plugin_a')..createSync(); - - // Create a Flutter project. - await processManager.run([ - flutterBin, - 'create', - projectDir.path, - '--project-name=testapp', - ], workingDirectory: projectDir.path); - - // Create a Flutter plugin to add as a dev dependency to the Flutter project. - await processManager.run([ - flutterBin, - 'create', - tempPluginADir.path, - '--template=plugin', - '--project-name=plugin_a', - '--platforms=ios,macos', - ], workingDirectory: tempPluginADir.path); - - // Add a dev dependency on plugin_a - await processManager.run([ - flutterBin, - 'pub', - 'add', - 'dev:plugin_a', - '--path', - tempPluginADir.path, - ], workingDirectory: projectDir.path); - }); - - tearDownAll(() { - tryToDelete(tempDir); - }); - - group( - 'Xcode build iOS app', - () { - test('succeeds after flutter build ios --config-only', () async { - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); - }); - - test('fails in Release mode if dev dependencies enabled', () async { - // Enable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode release build should error that dev dependencies are enabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Release', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Release builds should not have Dart dev dependencies enabled', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - - test('fails in Debug mode if dev dependencies disabled', () async { - // Disable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--release', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode debug build should error that dev dependencies are disabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Debug builds require Dart dev dependencies', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - }, - skip: !platform.isMacOS, // [intended] iOS builds only work on macos. - ); - - group( - 'Xcode build iOS module', - () { - test('succeeds after flutter build ios --config-only', () async { - final String appDirectory = fileSystem.path.join( - getFlutterRoot(), - 'dev', - 'integration_tests', - 'ios_add2app_life_cycle', - ); - final String moduleDirectory = fileSystem.path.join(appDirectory, 'flutterapp'); - - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: moduleDirectory, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final ProcessResult podResult = await processManager.run( - const ['pod', 'install'], - workingDirectory: appDirectory, - environment: const {'LANG': 'en_US.UTF-8'}, - ); - - expect(podResult, const ProcessResultMatcher()); - - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios_add2app.xcworkspace', - '-scheme', - 'ios_add2app', - '-sdk', - 'iphonesimulator', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: appDirectory, - ); - - expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); - }); - - test('fails in Release mode if dev dependencies enabled', () async { - final String appDirectory = fileSystem.path.join( - getFlutterRoot(), - 'dev', - 'integration_tests', - 'ios_add2app_life_cycle', - ); - final String moduleDirectory = fileSystem.path.join(appDirectory, 'flutterapp'); - - // Enable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: moduleDirectory, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final ProcessResult podResult = await processManager.run( - const ['pod', 'install'], - workingDirectory: appDirectory, - environment: const {'LANG': 'en_US.UTF-8'}, - ); - - expect(podResult, const ProcessResultMatcher()); - - // Xcode release build should error that dev dependencies are enabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios_add2app.xcworkspace', - '-scheme', - 'ios_add2app', - '-sdk', - 'iphonesimulator', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Release', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: appDirectory, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Release builds should not have Dart dev dependencies enabled', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - - test('abc fails in Debug mode if dev dependencies disabled', () async { - final String appDirectory = fileSystem.path.join( - getFlutterRoot(), - 'dev', - 'integration_tests', - 'ios_add2app_life_cycle', - ); - final String moduleDirectory = fileSystem.path.join(appDirectory, 'flutterapp'); - - // Disable dev dependencies by generating release configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'ios', - '--config-only', - '--release', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: moduleDirectory, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final ProcessResult podResult = await processManager.run( - const ['pod', 'install'], - workingDirectory: appDirectory, - environment: const {'LANG': 'en_US.UTF-8'}, - ); - - expect(podResult, const ProcessResultMatcher()); - - // Xcode debug build should error that dev dependencies are disabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'ios_add2app.xcworkspace', - '-scheme', - 'ios_add2app', - '-sdk', - 'iphonesimulator', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: appDirectory, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'Debug builds require Dart dev dependencies', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - }, - skip: !platform.isMacOS, // [intended] iOS builds only work on macos. - ); - - group( - 'Xcode build macOS app', - () { - test('succeeds after flutter build macos --config-only', () async { - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'macos', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); - }); - - test('fails in Release mode if dev dependencies enabled', () async { - // Enable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'macos', - '--config-only', - '--debug', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode release build should error that dev dependencies are enabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Release', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'error: Release builds should not have Dart dev dependencies enabled', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - - test('fails in Debug mode if dev dependencies disabled', () async { - // Disable dev dependencies by generating debug configuration files - final List flutterCommand = [ - flutterBin, - ...getLocalEngineArguments(), - 'build', - 'macos', - '--config-only', - '--release', - ]; - final ProcessResult flutterResult = await processManager.run( - flutterCommand, - workingDirectory: projectDir.path, - ); - - expect(flutterResult, const ProcessResultMatcher()); - - // Xcode debug build should error that dev dependencies are disabled. - final List xcodeCommand = [ - 'xcodebuild', - '-workspace', - 'macos/Runner.xcworkspace', - '-scheme', - 'Runner', - 'CODE_SIGNING_ALLOWED=NO', - 'CODE_SIGNING_REQUIRED=NO', - 'CODE_SIGN_IDENTITY=-', - 'EXPANDED_CODE_SIGN_IDENTITY=-', - 'COMPILER_INDEX_STORE_ENABLE=NO', - 'VERBOSE_SCRIPT_LOGGING=true', - '-configuration', - 'Debug', - ]; - final ProcessResult xcodeResult = await processManager.run( - xcodeCommand, - workingDirectory: projectDir.path, - ); - - expect( - xcodeResult, - const ProcessResultMatcher( - exitCode: 65, - stdoutPattern: 'error: Debug builds require Dart dev dependencies', - stderrPattern: '** BUILD FAILED **', - ), - ); - }); - }, - skip: !platform.isMacOS, // [intended] iOS builds only work on macos. - ); -} diff --git a/packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart b/packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart new file mode 100644 index 0000000000000..02b6b5d5c5df2 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/xcode_verify_configuration_test.dart @@ -0,0 +1,588 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/io.dart'; + +import '../src/common.dart'; +import 'test_utils.dart'; + +void main() { + late Directory tempDir; + late Directory projectDir; + + setUpAll(() async { + tempDir = createResolvedTempDirectorySync('xcode_dev_dependencies_test.'); + projectDir = tempDir.childDirectory('project')..createSync(); + final Directory tempPluginADir = tempDir.childDirectory('plugin_a')..createSync(); + + // Create a Flutter project. + await processManager.run([ + flutterBin, + 'create', + projectDir.path, + '--project-name=testapp', + ], workingDirectory: projectDir.path); + + // Create a Flutter plugin to add as a dev dependency to the Flutter project. + await processManager.run([ + flutterBin, + 'create', + tempPluginADir.path, + '--template=plugin', + '--project-name=plugin_a', + '--platforms=ios,macos', + ], workingDirectory: tempPluginADir.path); + + // Add a dev dependency on plugin_a + await processManager.run([ + flutterBin, + 'pub', + 'add', + 'dev:plugin_a', + '--path', + tempPluginADir.path, + ], workingDirectory: projectDir.path); + }); + + tearDownAll(() { + tryToDelete(tempDir); + }); + + group( + 'Xcode build iOS app', + () { + test( + 'succeeds when Flutter CLI last used configuration matches Xcode configuration', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'generic/platform=iOS Simulator', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); + }, + ); + + test( + 'fails if Flutter CLI last used configuration does not match Xcode configuration when archiving', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + 'archive', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Release', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + exitCode: 65, + stdoutPattern: 'error: Your Flutter project is currently configured for debug mode.', + stderrPattern: '** ARCHIVE FAILED **', + ), + ); + }, + ); + + test( + 'warns if Flutter CLI last used configuration does not match Xcode configuration when building', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--release', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'ios/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + stdoutPattern: + 'warning: Your Flutter project is currently configured for release mode.', + ), + ); + }, + ); + }, + skip: !platform.isMacOS, // [intended] iOS builds only work on macos. + ); + + group( + 'Xcode build iOS module', + () { + test( + 'succeeds when Flutter CLI last used configuration matches Xcode configuration', + () async { + final Directory moduleDirectory = projectDir.childDirectory('hello'); + await processManager.run([ + flutterBin, + 'create', + moduleDirectory.path, + '--template=module', + '--project-name=hello', + ], workingDirectory: projectDir.path); + + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: moduleDirectory.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final Directory hostAppDirectory = projectDir.childDirectory('hello_host_app'); + hostAppDirectory.createSync(); + + copyDirectory( + fileSystem.directory( + fileSystem.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'ios_host_app'), + ), + hostAppDirectory, + ); + + final ProcessResult podResult = await processManager.run( + const ['pod', 'install'], + workingDirectory: hostAppDirectory.path, + environment: const {'LANG': 'en_US.UTF-8'}, + ); + + expect(podResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'Host.xcworkspace', + '-scheme', + 'Host', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: hostAppDirectory.path, + ); + + expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); + }, + ); + + test( + 'fails if Flutter CLI last used configuration does not match Xcode configuration when archiving', + () async { + final Directory moduleDirectory = projectDir.childDirectory('hello'); + await processManager.run([ + flutterBin, + 'create', + moduleDirectory.path, + '--template=module', + '--project-name=hello', + ], workingDirectory: projectDir.path); + + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: moduleDirectory.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final Directory hostAppDirectory = projectDir.childDirectory('hello_host_app'); + hostAppDirectory.createSync(); + + copyDirectory( + fileSystem.directory( + fileSystem.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'ios_host_app'), + ), + hostAppDirectory, + ); + + final ProcessResult podResult = await processManager.run( + const ['pod', 'install'], + workingDirectory: hostAppDirectory.path, + environment: const {'LANG': 'en_US.UTF-8'}, + ); + + expect(podResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + 'archive', + '-workspace', + 'Host.xcworkspace', + '-scheme', + 'Host', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Release', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: hostAppDirectory.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + exitCode: 65, + stdoutPattern: 'error: Your Flutter project is currently configured for debug mode.', + stderrPattern: '** ARCHIVE FAILED **', + ), + ); + }, + ); + + test( + 'warns if Flutter CLI last used configuration does not match Xcode configuration when building', + () async { + final Directory moduleDirectory = projectDir.childDirectory('hello'); + await processManager.run([ + flutterBin, + 'create', + moduleDirectory.path, + '--template=module', + '--project-name=hello', + ], workingDirectory: projectDir.path); + + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'ios', + '--config-only', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: moduleDirectory.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final Directory hostAppDirectory = projectDir.childDirectory('hello_host_app'); + hostAppDirectory.createSync(); + + copyDirectory( + fileSystem.directory( + fileSystem.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'ios_host_app'), + ), + hostAppDirectory, + ); + + final ProcessResult podResult = await processManager.run( + const ['pod', 'install'], + workingDirectory: hostAppDirectory.path, + environment: const {'LANG': 'en_US.UTF-8'}, + ); + + expect(podResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'Host.xcworkspace', + '-scheme', + 'Host', + '-destination', + 'generic/platform=iOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: hostAppDirectory.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + stdoutPattern: + 'warning: Your Flutter project is currently configured for release mode.', + ), + ); + }, + ); + }, + skip: !platform.isMacOS, // [intended] iOS builds only work on macos. + ); + + group( + 'Xcode build macOS app', + () { + test( + 'succeeds when Flutter CLI last used configuration matches Xcode configuration', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'macos', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'platform=macOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect(xcodeResult, const ProcessResultMatcher(stdoutPattern: '** BUILD SUCCEEDED **')); + }, + ); + + test( + 'fails if Flutter CLI last used configuration does not match Xcode configuration when archiving', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'macos', + '--config-only', + '--debug', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + 'archive', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'platform=macOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Release', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + exitCode: 65, + stdoutPattern: 'error: Your Flutter project is currently configured for debug mode.', + stderrPattern: '** ARCHIVE FAILED **', + ), + ); + }, + ); + + test( + 'warns if Flutter CLI last used configuration does not match Xcode configuration when building', + () async { + final List flutterCommand = [ + flutterBin, + ...getLocalEngineArguments(), + 'build', + 'macos', + '--config-only', + '--release', + ]; + final ProcessResult flutterResult = await processManager.run( + flutterCommand, + workingDirectory: projectDir.path, + ); + + expect(flutterResult, const ProcessResultMatcher()); + + final List xcodeCommand = [ + 'xcodebuild', + '-workspace', + 'macos/Runner.xcworkspace', + '-scheme', + 'Runner', + '-destination', + 'platform=macOS', + 'CODE_SIGNING_ALLOWED=NO', + 'CODE_SIGNING_REQUIRED=NO', + 'CODE_SIGN_IDENTITY=-', + 'EXPANDED_CODE_SIGN_IDENTITY=-', + 'COMPILER_INDEX_STORE_ENABLE=NO', + 'VERBOSE_SCRIPT_LOGGING=true', + '-configuration', + 'Debug', + ]; + final ProcessResult xcodeResult = await processManager.run( + xcodeCommand, + workingDirectory: projectDir.path, + ); + + expect( + xcodeResult, + const ProcessResultMatcher( + stdoutPattern: + 'warning: Your Flutter project is currently configured for release mode.', + ), + ); + }, + ); + }, + skip: !platform.isMacOS, // [intended] iOS builds only work on macos. + ); +} From 422d8d2dade18d544b0b10dd09a73cba99a3a9bc Mon Sep 17 00:00:00 2001 From: Nicholas Shahan Date: Thu, 29 May 2025 12:00:57 -0700 Subject: [PATCH 27/66] [tests] Increase linux timeout and skip on others (#169627) With this change the web.shard test suite runs all existing tests on all platforms with the version of the web debug builds that is the flutter tools default (does not support stateful hot reload). The linux bot configuration will also run some of the tests using the new web debug build (supports stateful hot reload). The timeout has been increased for this configuration to allow the additional tests to run to completion. The mac and windows configurations skip all tests for the new web debug builds. In the future the new build output will become the flutter tools default and the balance of where the tests tests are run will flip until the ability to opt out of the new build output is removed. This change is not ideal because we are still not fully testing all features with the two versions of the web debug builds that are available to users. If given the opportunity we should add additional bot configurations to run all the tests with the output that supports stateful hot reload. Fixes: https://github.com/flutter/flutter/issues/169304 Issue: https://github.com/flutter/flutter/issues/169634 --- .ci.yaml | 4 ++-- .../test/web.shard/expression_evaluation_web_amd_test.dart | 1 - .../expression_evaluation_web_ddc_library_bundle_test.dart | 2 +- .../test/web.shard/hot_reload_web_errors_test.dart | 1 + .../flutter_tools/test/web.shard/hot_reload_web_test.dart | 1 + .../test/web.shard/hot_reload_with_asset_web_test.dart | 1 + .../web.shard/hot_restart_web_ddc_library_bundle_test.dart | 1 + .../web.shard/stateless_stateful_hot_reload_web_test.dart | 1 + 8 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index f6a85130f01b6..f4aedb4e11836 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2246,7 +2246,7 @@ targets: - name: Linux web_tool_tests recipe: flutter/flutter_drone - timeout: 60 + timeout: 90 # https://github.com/flutter/flutter/issues/169634 properties: dependencies: >- [ @@ -2261,7 +2261,7 @@ targets: ["framework", "hostonly", "shard", "linux"] # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 presubmit_max_attempts: "2" - test_timeout_secs: "3600" # https://github.com/flutter/flutter/issues/162714 + test_timeout_secs: "5400" # https://github.com/flutter/flutter/issues/162714 runIf: - dev/** - packages/flutter_tools/** diff --git a/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart b/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart index 0a8db50894b33..6e72fb1da42c2 100644 --- a/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart +++ b/packages/flutter_tools/test/web.shard/expression_evaluation_web_amd_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. @Tags(['flutter-test-driver']) -@Skip('https://github.com/flutter/flutter/issues/169304') library; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart b/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart index 7064367ee05a8..f95ddc338ec80 100644 --- a/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart +++ b/packages/flutter_tools/test/web.shard/expression_evaluation_web_ddc_library_bundle_test.dart @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) -@Skip('https://github.com/flutter/flutter/issues/169304') library; import '../src/common.dart'; diff --git a/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart b/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart index 9c35bb76157c8..de811a8457b94 100644 --- a/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_reload_web_errors_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart b/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart index a388b3afd242d..5763757c3d34b 100644 --- a/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_reload_web_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/hot_reload_with_asset_web_test.dart b/packages/flutter_tools/test/web.shard/hot_reload_with_asset_web_test.dart index 45551c06a080f..6621653ac686b 100644 --- a/packages/flutter_tools/test/web.shard/hot_reload_with_asset_web_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_reload_with_asset_web_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart b/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart index 542e728e3b7e2..ccb808f225a28 100644 --- a/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart +++ b/packages/flutter_tools/test/web.shard/hot_restart_web_ddc_library_bundle_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; diff --git a/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart b/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart index 6b0ab1447bb02..4f1440423b130 100644 --- a/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart +++ b/packages/flutter_tools/test/web.shard/stateless_stateful_hot_reload_web_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('linux') // https://github.com/flutter/flutter/issues/169304 @Tags(['flutter-test-driver']) library; From ed68dd8c22b16fc48b13db48100f9b059c5b5d1f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 29 May 2025 15:23:20 -0400 Subject: [PATCH 28/66] Roll Skia from 58f43e55f1ba to 191ef95dbe54 (8 revisions) (#169686) https://skia.googlesource.com/skia.git/+log/58f43e55f1ba..191ef95dbe54 2025-05-29 lukasza@chromium.org Reland "[rust png] Round-trip `kOpaque_SkAlphaType` when encoding". 2025-05-29 kjlubick@google.com Revert "[rust png] Make `SkTypeface_fontations.cpp` agnostic to PNG decoder" 2025-05-29 kjlubick@google.com Make Bazel boilerplate presubmit platform dependent 2025-05-29 mike@reedtribe.org Remove pathops dependency 2025-05-29 mike@reedtribe.org More uses for DirectBlit 2025-05-29 lehoangquyen@chromium.org graphite: Add internalMSAATileSize option to ContextOptions 2025-05-29 bungeman@google.com [pdf] Artifact types and subtypes are names 2025-05-29 kjlubick@google.com [rust png] Make `SkTypeface_fontations.cpp` agnostic to PNG decoder If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC codefu@google.com,kjlubick@google.com,nicolettep@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3687009c54054..2764503e828c4 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '58f43e55f1bace20db6549c9df60224a10dfdfe1', + 'skia_revision': '191ef95dbe5483104ef6aaf8842b77fc97af8ae3', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/engine/src/flutter/ci/licenses_golden/licenses_skia b/engine/src/flutter/ci/licenses_golden/licenses_skia index 3fc9ea80b83f9..f86bffb6d2515 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_skia +++ b/engine/src/flutter/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d6d4946d982498335b54856dfd82e238 +Signature: 5aeb0da65bd13e6fe657b800e4bfc052 ==================================================================================================== LIBRARY: etc1 From 09c7f4fa5bdbe7b631d33728d7a8a78df2058b72 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 29 May 2025 12:39:20 -0700 Subject: [PATCH 29/66] [Impeller] libImpeller: Allow setting ellipses. (#169610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/flutter/flutter/issues/168750 Screenshot 2025-05-28 at 11 41 24 AM --- .../impeller/toolkit/interop/impeller.cc | 6 +++++ .../impeller/toolkit/interop/impeller.h | 12 +++++++++ .../impeller/toolkit/interop/impeller.hpp | 9 +++++++ .../toolkit/interop/impeller_unittests.cc | 25 +++++++++++++++++++ .../toolkit/interop/paragraph_style.cc | 10 ++++++++ .../toolkit/interop/paragraph_style.h | 2 ++ 6 files changed, 64 insertions(+) diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.cc b/engine/src/flutter/impeller/toolkit/interop/impeller.cc index 3c75dd0b3fbb9..ea54089bee0b5 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.cc +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.cc @@ -1159,6 +1159,12 @@ void ImpellerParagraphStyleSetLocale(ImpellerParagraphStyle paragraph_style, GetPeer(paragraph_style)->SetLocale(ReadString(locale)); } +IMPELLER_EXTERN_C +void ImpellerParagraphStyleSetEllipsis(ImpellerParagraphStyle paragraph_style, + const char* ellipsis) { + GetPeer(paragraph_style)->SetEllipsis(ReadString(ellipsis)); +} + IMPELLER_EXTERN_C void ImpellerDisplayListBuilderDrawParagraph(ImpellerDisplayListBuilder builder, ImpellerParagraph paragraph, diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.h b/engine/src/flutter/impeller/toolkit/interop/impeller.h index 4353fc599a82b..78f47645ae2a0 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.h +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.h @@ -2472,6 +2472,18 @@ void ImpellerParagraphStyleSetLocale( ImpellerParagraphStyle IMPELLER_NONNULL paragraph_style, const char* IMPELLER_NONNULL locale); +//------------------------------------------------------------------------------ +/// @brief Set the UTF-8 string to use as the ellipsis. Pass `nullptr` to +/// clear the setting to default. +/// +/// @param[in] paragraph_style The paragraph style. +/// @param[in] data The ellipsis string UTF-8 data, or null. +/// +IMPELLER_EXPORT +void ImpellerParagraphStyleSetEllipsis( + ImpellerParagraphStyle IMPELLER_NONNULL paragraph_style, + const char* IMPELLER_NULLABLE ellipsis); + //------------------------------------------------------------------------------ // Paragraph Builder //------------------------------------------------------------------------------ diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.hpp b/engine/src/flutter/impeller/toolkit/interop/impeller.hpp index a5dd4cc40d456..7085671911c9b 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.hpp +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.hpp @@ -168,6 +168,7 @@ struct Proc { PROC(ImpellerParagraphStyleRelease) \ PROC(ImpellerParagraphStyleRetain) \ PROC(ImpellerParagraphStyleSetBackground) \ + PROC(ImpellerParagraphStyleSetEllipsis) \ PROC(ImpellerParagraphStyleSetFontFamily) \ PROC(ImpellerParagraphStyleSetFontSize) \ PROC(ImpellerParagraphStyleSetFontStyle) \ @@ -1088,6 +1089,14 @@ class ParagraphStyle return *this; } + //---------------------------------------------------------------------------- + /// @see ImpellerParagraphStyleSetEllipsis + /// + ParagraphStyle& SetEllipsis(const char* ellipsis) { + gGlobalProcTable.ImpellerParagraphStyleSetEllipsis(Get(), ellipsis); + return *this; + } + //---------------------------------------------------------------------------- /// @see ImpellerParagraphStyleSetMaxLines /// diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc b/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc index 8e36a18f4994c..48812e71385b9 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc +++ b/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc @@ -631,4 +631,29 @@ TEST_P(InteropPlaygroundTest, CanGetPathBounds) { ASSERT_EQ(bounds.height, 100); } +TEST_P(InteropPlaygroundTest, CanControlEllipses) { + hpp::TypographyContext context; + auto style = hpp::ParagraphStyle{}; + style.SetFontSize(50); + style.SetForeground(hpp::Paint{}.SetColor({.red = 1.0, .alpha = 1.0})); + const auto text = std::string{"The quick brown fox jumped over the lazy dog"}; + style.SetEllipsis("🐶"); + auto para1 = + hpp::ParagraphBuilder{context}.PushStyle(style).AddText(text).Build(250); + style.SetForeground(hpp::Paint{}.SetColor({.green = 1.0, .alpha = 1.0})); + style.SetEllipsis(nullptr); + auto para2 = + hpp::ParagraphBuilder{context}.PushStyle(style).AddText(text).Build(250); + auto dl = hpp::DisplayListBuilder{} + .DrawParagraph(para1, {100, 100}) + .DrawParagraph(para2, {100, 200}) + .Build(); + ASSERT_TRUE( + OpenPlaygroundHere([&](const auto& context, const auto& surface) -> bool { + hpp::Surface window(surface.GetC()); + window.Draw(dl); + return true; + })); +} + } // namespace impeller::interop::testing diff --git a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc index 25982bf27c5ca..780d6e03fc93c 100644 --- a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc +++ b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.cc @@ -4,6 +4,8 @@ #include "impeller/toolkit/interop/paragraph_style.h" +#include "flutter/fml/string_conversion.h" + namespace impeller::interop { ParagraphStyle::ParagraphStyle() = default; @@ -84,4 +86,12 @@ void ParagraphStyle::SetTextDecoration( decoration_ = decoration; } +void ParagraphStyle::SetEllipsis(const std::string& string) { + if (string.empty()) { + style_.ellipsis = {}; + return; + } + style_.ellipsis = fml::Utf8ToUtf16(string); +} + } // namespace impeller::interop diff --git a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h index 26e33d1855862..d3bab1f060253 100644 --- a/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h +++ b/engine/src/flutter/impeller/toolkit/interop/paragraph_style.h @@ -48,6 +48,8 @@ class ParagraphStyle final void SetLocale(std::string locale); + void SetEllipsis(const std::string& string); + txt::TextStyle CreateTextStyle() const; const txt::ParagraphStyle& GetParagraphStyle() const; From df298943720f1492774652df2e5039ebfe57d267 Mon Sep 17 00:00:00 2001 From: Kishan Rathore <34465683+rkishan516@users.noreply.github.com> Date: Fri, 30 May 2025 01:33:21 +0530 Subject: [PATCH 30/66] Feat: Add opaque, isActive, isFirst, popDisposition aspects for ModalRoute (#167324) Feat: Add opaque, isActive, isFirst, popDisposition aspects for ModalRoute fixes: #167058 fixes: #162009 ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --- packages/flutter/lib/src/widgets/routes.dart | 69 +++++++++- .../flutter/test/widgets/routes_test.dart | 129 ++++++++++++++++++ 2 files changed, 195 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index c61dd7a862a64..80c2f371366ef 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -971,6 +971,18 @@ enum _ModalRouteAspect { /// Specifies the aspect corresponding to [ModalRoute.settings]. settings, + + /// Specifies the aspect corresponding to [ModalRoute.isActive]. + isActive, + + /// Specifies the aspect corresponding to [ModalRoute.isFirst]. + isFirst, + + /// Specifies the aspect corresponding to [ModalRoute.opaque]. + opaque, + + /// Specifies the aspect corresponding to [ModalRoute.popDisposition]. + popDisposition, } class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { @@ -979,12 +991,14 @@ class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { required this.canPop, required this.impliesAppBarDismissal, required this.route, + required this.opaque, required super.child, }); final bool isCurrent; final bool canPop; final bool impliesAppBarDismissal; + final bool opaque; final Route route; @override @@ -992,7 +1006,8 @@ class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { return isCurrent != old.isCurrent || canPop != old.canPop || impliesAppBarDismissal != old.impliesAppBarDismissal || - route != old.route; + route != old.route || + opaque != old.opaque; } @override @@ -1021,6 +1036,10 @@ class _ModalScopeStatus extends InheritedModel<_ModalRouteAspect> { _ModalRouteAspect.isCurrent => isCurrent != oldWidget.isCurrent, _ModalRouteAspect.canPop => canPop != oldWidget.canPop, _ModalRouteAspect.settings => route.settings != oldWidget.route.settings, + _ModalRouteAspect.isActive => route.isActive != oldWidget.route.isActive, + _ModalRouteAspect.isFirst => route.isFirst != oldWidget.route.isFirst, + _ModalRouteAspect.opaque => opaque != oldWidget.opaque, + _ModalRouteAspect.popDisposition => route.popDisposition != oldWidget.route.popDisposition, }, ); } @@ -1143,6 +1162,7 @@ class _ModalScopeState extends State<_ModalScope> { route: widget.route, isCurrent: widget.route.isCurrent, // _routeSetState is called if this updates canPop: widget.route.canPop, // _routeSetState is called if this updates + opaque: widget.route.opaque, // _routeSetState is called if this updates impliesAppBarDismissal: widget.route.impliesAppBarDismissal, child: Offstage( offstage: widget.route.offstage, // _routeSetState is called if this updates @@ -1299,11 +1319,54 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute _of(context, _ModalRouteAspect.settings)?.settings; + /// Returns [ModalRoute.isActive] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.isActive] changes. + static bool? isActiveOf(BuildContext context) => + _of(context, _ModalRouteAspect.isActive)?.isActive; + + /// Returns [ModalRoute.isFirst] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.isFirst] changes. + static bool? isFirstOf(BuildContext context) => _of(context, _ModalRouteAspect.isFirst)?.isFirst; + + /// Returns [ModalRoute.opaque] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.opaque] changes. + static bool? opaqueOf(BuildContext context) => _of(context, _ModalRouteAspect.opaque)?.opaque; + + /// Returns [ModalRoute.popDisposition] for the modal route most closely associated + /// with the given context. + /// + /// Returns null if the given context is not associated with a modal route. + /// + /// Calling this method creates a dependency on the [ModalRoute] associated + /// with the given [context]. As a result, the widget corresponding to [context] + /// will be rebuilt whenever the route's [ModalRoute.popDisposition] changes. + static RoutePopDisposition? popDispositionOf(BuildContext context) => + _of(context, _ModalRouteAspect.popDisposition)?.popDisposition; + /// Schedule a call to [buildTransitions]. /// /// Whenever you need to change internal state for a [ModalRoute] object, make diff --git a/packages/flutter/test/widgets/routes_test.dart b/packages/flutter/test/widgets/routes_test.dart index 435ef8492e3ee..4c7afb8c7855b 100644 --- a/packages/flutter/test/widgets/routes_test.dart +++ b/packages/flutter/test/widgets/routes_test.dart @@ -2512,6 +2512,135 @@ void main() { moreOrLessEquals(xLocationIntervalTwelve, epsilon: 0.1), ); }); + + testWidgets('ModalRoute.isFirstOf only rebuilds when first route state changes', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final bool isFirst = ModalRoute.isFirstOf(context) ?? false; + return Text('isFirst: $isFirst'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('isFirst: true'), findsOneWidget); + + // Push a new route - first route should remain first + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Should not rebuild because isFirst hasn't changed + expect(buildCount, 1); + }); + + testWidgets('ModalRoute.isActiveOf only rebuilds when route active state changes', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final bool isActive = ModalRoute.isActiveOf(context) ?? false; + return Text('isActive: $isActive'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('isActive: true'), findsOneWidget); + + // Push a new route - first route should remain active + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Should not rebuild because isActive hasn't changed + expect(buildCount, 1); + }); + + testWidgets('ModalRoute.opaqueOf only rebuilds when route opaque state changes', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final bool isOpaque = ModalRoute.opaqueOf(context) ?? false; + return Text('isOpaque: $isOpaque'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('isOpaque: true'), findsOneWidget); + + // Push a new route - first route should remain opaque + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Should not rebuild because isOpaque hasn't changed + expect(buildCount, 1); + }); + + testWidgets('ModalRoute.popDispositionOf rebuilds when PopEntry affects pop disposition', ( + WidgetTester tester, + ) async { + int buildCount = 0; + final GlobalKey navigator = GlobalKey(); + + Widget buildCounter(BuildContext context) { + buildCount++; + final RoutePopDisposition? popDisposition = ModalRoute.popDispositionOf(context); + return Text('popDisposition: ${popDisposition?.name}'); + } + + await tester.pumpWidget( + MaterialApp(navigatorKey: navigator, home: Builder(builder: buildCounter)), + ); + + expect(buildCount, 1); + expect(find.text('popDisposition: bubble'), findsOneWidget); + + // Change PopScope's canPop to false + await tester.pumpWidget( + MaterialApp( + navigatorKey: navigator, + home: PopScope(canPop: false, child: Builder(builder: buildCounter)), + ), + ); + await tester.pumpAndSettle(); + + // Should rebuild because popDisposition changed to doNotPop + expect(buildCount, 2); + expect(find.text('popDisposition: doNotPop'), findsOneWidget); + + // Push a new route - should change from bubble to pop + navigator.currentState!.push( + MaterialPageRoute(builder: (BuildContext context) => const Text('New Route')), + ); + await tester.pumpAndSettle(); + + // Shouldn't rebuild because popDisposition hasn't changed + expect(buildCount, 2); + }); }); testWidgets('can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { From f182421dd25c76fcb8ff444c19205b85ebaf4af1 Mon Sep 17 00:00:00 2001 From: fewling Date: Fri, 30 May 2025 04:33:26 +0800 Subject: [PATCH 31/66] Add header and footer support to NavigationDrawer (#168005) ## Description This PR attempts to add header and footer for `NavigationDrawer` widget as shown below: ![sample](https://github.com/user-attachments/assets/f3adefe9-7c4e-4169-a72b-d5beffc7b73a) ## Issues are fixed by this PR - #127621 - #135750 (partially) ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/material/navigation_drawer.dart | 23 ++++++++++- .../test/material/navigation_drawer_test.dart | 40 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/navigation_drawer.dart b/packages/flutter/lib/src/material/navigation_drawer.dart index eb3f5ec2edd6f..99932ba48bf7d 100644 --- a/packages/flutter/lib/src/material/navigation_drawer.dart +++ b/packages/flutter/lib/src/material/navigation_drawer.dart @@ -57,6 +57,8 @@ class NavigationDrawer extends StatelessWidget { const NavigationDrawer({ super.key, required this.children, + this.header, + this.footer, this.backgroundColor, this.shadowColor, this.surfaceTintColor, @@ -120,6 +122,16 @@ class NavigationDrawer extends StatelessWidget { /// widgets like headlines and dividers. final List children; + /// A widget to display at the top of the layout. + /// + /// Typically used for titles, navigation bars, or other header content. + final Widget? header; + + /// A widget to display at the bottom of the layout. + /// + /// Typically used for actions, navigation controls, or other footer content. + final Widget? footer; + /// The index into destinations for the current selected /// [NavigationDrawerDestination] or null if no destination is selected. /// @@ -173,7 +185,16 @@ class NavigationDrawer extends StatelessWidget { shadowColor: shadowColor ?? navigationDrawerTheme.shadowColor, surfaceTintColor: surfaceTintColor ?? navigationDrawerTheme.surfaceTintColor, elevation: elevation ?? navigationDrawerTheme.elevation, - child: SafeArea(bottom: false, child: ListView(children: wrappedChildren)), + child: SafeArea( + bottom: false, + child: Column( + children: [ + if (header != null) header!, + Expanded(child: ListView(children: wrappedChildren)), + if (footer != null) footer!, + ], + ), + ), ); } } diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index fde25e676a604..06f217f94a2a8 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -488,6 +488,46 @@ void main() { await tester.pumpAndSettle(); }); + + testWidgets('NavigationDrawer can display header and footer', (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + widgetSetup(tester, 3000, viewHeight: 3000); + final Widget widget = _buildWidget( + scaffoldKey, + NavigationDrawer( + header: const DrawerHeader( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [FlutterLogo(), Text('Header')], + ), + ), + ), + footer: ListTile( + leading: const FlutterLogo(), + title: const Text('Footer'), + trailing: const Icon(Icons.settings), + onTap: () {}, + ), + children: [ + for (int i = 0; i < 10; i++) + NavigationDrawerDestination(icon: const Icon(Icons.home), label: Text('Item $i')), + ], + ), + ); + + await tester.pumpWidget(widget); + scaffoldKey.currentState!.openDrawer(); + await tester.pump(const Duration(seconds: 1)); + + expect(find.byType(DrawerHeader), findsOneWidget); + expect(find.text('Header'), findsOneWidget); + expect(find.byType(FlutterLogo), findsNWidgets(2)); + expect(find.byType(ListTile), findsOneWidget); + expect(find.text('Footer'), findsOneWidget); + expect(find.byIcon(Icons.settings), findsOneWidget); + }); } Widget _buildWidget(GlobalKey scaffoldKey, Widget child, {bool? useMaterial3}) { From 279f19161f8eeb29ba4ea0d88fa11a6833789e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 29 May 2025 13:40:34 -0700 Subject: [PATCH 32/66] Let tests mock the list of feature flags (#169140) This moves the tool's `allFeatures` global to `FeatureFlags.allFeatures`. In the future, this will be used by tests to mock the list of feature flags and replace them with test flags in various states. See: https://github.com/flutter/flutter/pull/168437 Part of: https://github.com/flutter/flutter/issues/167668 ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/commands/config.dart | 10 +++--- packages/flutter_tools/lib/src/features.dart | 32 +++++++++---------- .../lib/src/flutter_features.dart | 2 +- .../lib/src/reporting/unified_analytics.dart | 2 +- .../lib/src/reporting/usage.dart | 2 +- .../commands.shard/hermetic/config_test.dart | 2 +- .../test/general.shard/features_test.dart | 16 ++++++++++ .../general.shard/unified_analytics_test.dart | 5 +-- .../command_output_test.dart | 3 +- packages/flutter_tools/test/src/fakes.dart | 15 +++++++++ 10 files changed, 61 insertions(+), 28 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/config.dart b/packages/flutter_tools/lib/src/commands/config.dart index dac09a2262bf7..97781410796e2 100644 --- a/packages/flutter_tools/lib/src/commands/config.dart +++ b/packages/flutter_tools/lib/src/commands/config.dart @@ -67,7 +67,7 @@ class ConfigCommand extends FlutterCommand { hide: !verboseHelp, help: 'Print config values as json.', ); - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting == null) { continue; @@ -132,7 +132,7 @@ class ConfigCommand extends FlutterCommand { } if (boolArg('clear-features')) { - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting != null) { globals.config.removeValue(configSetting); @@ -188,7 +188,7 @@ class ConfigCommand extends FlutterCommand { _updateConfig('build-dir', buildDir); } - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting == null) { continue; @@ -247,14 +247,14 @@ class ConfigCommand extends FlutterCommand { String get settingsText { final Map featuresByName = {}; final String channel = globals.flutterVersion.channel; - for (final Feature feature in allFeatures) { + for (final Feature feature in featureFlags.allFeatures) { final String? configSetting = feature.configSetting; if (configSetting != null) { featuresByName[configSetting] = feature; } } final Set keys = { - ...allFeatures.map((Feature e) => e.configSetting).whereType(), + ...featureFlags.allFeatures.map((Feature e) => e.configSetting).whereType(), ...globals.config.keys, }; final Iterable settings = keys.map((String key) { diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index d548d2b49e42f..c1c3d4a9458db 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -60,28 +60,28 @@ abstract class FeatureFlags { /// /// Prefer using one of the specific getters above instead of this API. bool isEnabled(Feature feature); -} -/// All current Flutter feature flags. -const List allFeatures = [ - flutterWebFeature, - flutterLinuxDesktopFeature, - flutterMacOSDesktopFeature, - flutterWindowsDesktopFeature, - flutterAndroidFeature, - flutterIOSFeature, - flutterFuchsiaFeature, - flutterCustomDevicesFeature, - cliAnimation, - nativeAssets, - swiftPackageManager, -]; + /// All current Flutter feature flags. + List get allFeatures => const [ + flutterWebFeature, + flutterLinuxDesktopFeature, + flutterMacOSDesktopFeature, + flutterWindowsDesktopFeature, + flutterAndroidFeature, + flutterIOSFeature, + flutterFuchsiaFeature, + flutterCustomDevicesFeature, + cliAnimation, + nativeAssets, + swiftPackageManager, + ]; +} /// All current Flutter feature flags that can be configured. /// /// [Feature.configSetting] is not `null`. Iterable get allConfigurableFeatures => - allFeatures.where((Feature feature) => feature.configSetting != null); + featureFlags.allFeatures.where((Feature feature) => feature.configSetting != null); /// The [Feature] for flutter web. const Feature flutterWebFeature = Feature.fullyEnabled( diff --git a/packages/flutter_tools/lib/src/flutter_features.dart b/packages/flutter_tools/lib/src/flutter_features.dart index a55f54c7afd37..79253c1b26628 100644 --- a/packages/flutter_tools/lib/src/flutter_features.dart +++ b/packages/flutter_tools/lib/src/flutter_features.dart @@ -61,7 +61,7 @@ mixin FlutterFeatureFlagsIsEnabled implements FeatureFlags { bool get isExplicitPackageDependenciesEnabled => true; } -interface class FlutterFeatureFlags with FlutterFeatureFlagsIsEnabled implements FeatureFlags { +interface class FlutterFeatureFlags extends FeatureFlags with FlutterFeatureFlagsIsEnabled { FlutterFeatureFlags({ required FlutterVersion flutterVersion, required FlutterFeaturesConfig featuresConfig, diff --git a/packages/flutter_tools/lib/src/reporting/unified_analytics.dart b/packages/flutter_tools/lib/src/reporting/unified_analytics.dart index 1d490e3552e4b..a21be161beb7c 100644 --- a/packages/flutter_tools/lib/src/reporting/unified_analytics.dart +++ b/packages/flutter_tools/lib/src/reporting/unified_analytics.dart @@ -62,7 +62,7 @@ Analytics getAnalytics({ /// Uses the [Config] object to get enabled features. String? getEnabledFeatures(Config config) { // Create string with all enabled features to send as user property - final Iterable enabledFeatures = allFeatures.where((Feature feature) { + final Iterable enabledFeatures = featureFlags.allFeatures.where((Feature feature) { final String? configSetting = feature.configSetting; return configSetting != null && config.getValue(configSetting) == true; }); diff --git a/packages/flutter_tools/lib/src/reporting/usage.dart b/packages/flutter_tools/lib/src/reporting/usage.dart index 397552a5b7559..bdcbac5db5376 100644 --- a/packages/flutter_tools/lib/src/reporting/usage.dart +++ b/packages/flutter_tools/lib/src/reporting/usage.dart @@ -191,7 +191,7 @@ class _DefaultUsage implements Usage { ); // For each flutter experimental feature, record a session value in a comma // separated list. - final String enabledFeatures = allFeatures + final String enabledFeatures = featureFlags.allFeatures .where((Feature feature) { final String? configSetting = feature.configSetting; return configSetting != null && globals.config.getValue(configSetting) == true; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart index 18745650d532d..2a061d03374f6 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart @@ -54,7 +54,7 @@ void main() { expect( testLogger.statusText, 'All Settings:\n' - '${allFeatures.where((Feature e) => e.configSetting != null).map((Feature e) => ' ${e.configSetting}: (Not set)').join('\n')}' + '${featureFlags.allFeatures.where((Feature e) => e.configSetting != null).map((Feature e) => ' ${e.configSetting}: (Not set)').join('\n')}' '\n\n', ); }); diff --git a/packages/flutter_tools/test/general.shard/features_test.dart b/packages/flutter_tools/test/general.shard/features_test.dart index d8fe50e907dd4..65ed19f611b27 100644 --- a/packages/flutter_tools/test/general.shard/features_test.dart +++ b/packages/flutter_tools/test/general.shard/features_test.dart @@ -124,6 +124,19 @@ void main() { FileSystem: createFsWithPubspec, }, ); + + testUsingContext('Test feature flags match feature flags', () { + final FeatureFlags testFeatureFlags = TestFeatureFlags(); + + expect(featureFlags.allFeatures.length, equals(testFeatureFlags.allFeatures.length)); + + final List featureNames = + featureFlags.allFeatures.map((Feature feature) => feature.name).toList(); + final List testFeatureNames = + testFeatureFlags.allFeatures.map((Feature feature) => feature.name).toList(); + + expect(featureNames, unorderedEquals(testFeatureNames)); + }); }); group('Linux Destkop', () { @@ -441,4 +454,7 @@ final class _TestIsGetterForwarding with FlutterFeatureFlagsIsEnabled { bool isEnabled(Feature feature) { return feature == shouldInvoke; } + + @override + List get allFeatures => throw UnimplementedError(); } diff --git a/packages/flutter_tools/test/general.shard/unified_analytics_test.dart b/packages/flutter_tools/test/general.shard/unified_analytics_test.dart index 0f7195a42a27e..0362b152cc9be 100644 --- a/packages/flutter_tools/test/general.shard/unified_analytics_test.dart +++ b/packages/flutter_tools/test/general.shard/unified_analytics_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_tools/src/reporting/unified_analytics.dart'; import 'package:unified_analytics/unified_analytics.dart'; import '../src/common.dart'; +import '../src/context.dart'; import '../src/fakes.dart'; void main() { @@ -30,12 +31,12 @@ void main() { }); group('Unit testing util:', () { - test('getEnabledFeatures is null', () { + testUsingContext('getEnabledFeatures is null', () { final String? enabledFeatures = getEnabledFeatures(config); expect(enabledFeatures, isNull); }); - testWithoutContext('getEnabledFeatures not null', () { + testUsingContext('getEnabledFeatures not null', () { config.setValue('cli-animations', true); final String? enabledFeatures = getEnabledFeatures(config); diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart index 9c26e18a0f5d7..7b6b6400fc6db 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -9,6 +9,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/features.dart'; import '../src/common.dart'; +import '../src/context.dart'; import 'test_utils.dart'; // This test file does not use [getLocalEngineArguments] because it is testing @@ -58,7 +59,7 @@ void main() { expect(result.stdout, contains('Shutdown hooks complete')); }); - testWithoutContext('flutter config --list contains all features', () async { + testUsingContext('flutter config --list contains all features', () async { final ProcessResult result = await processManager.run([flutterBin, 'config', '--list']); // contains all of the experiments in features.dart diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index fada2a4a5156c..562f541ebc723 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -548,6 +548,21 @@ class TestFeatureFlags implements FeatureFlags { _ => false, }; } + + @override + List get allFeatures => const [ + flutterWebFeature, + flutterLinuxDesktopFeature, + flutterMacOSDesktopFeature, + flutterWindowsDesktopFeature, + flutterAndroidFeature, + flutterIOSFeature, + flutterFuchsiaFeature, + flutterCustomDevicesFeature, + cliAnimation, + nativeAssets, + swiftPackageManager, + ]; } class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils { From e315c070c85aab26bcf684415608ce0b4bb51b02 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 29 May 2025 14:50:20 -0700 Subject: [PATCH 33/66] Clean up references to deprecated onPop method in docs (#169700) onPop is deprecated but was mentioned in the docs. I've put its replacement onPopWithResult in its place. Also, there was one unterminated square bracket that I've fixed. --- .../flutter/lib/src/widgets/navigator_pop_handler.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart index f6d3eeb9c5e71..2333565aba733 100644 --- a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart +++ b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart @@ -10,10 +10,10 @@ import 'pop_scope.dart'; /// Enables the handling of system back gestures. /// /// Typically wraps a nested [Navigator] widget and allows it to handle system -/// back gestures in the [onPop] callback. +/// back gestures in the [onPopWithResult] callback. /// /// The type parameter `` indicates the type of the [Route]'s return value, -/// which is passed to [onPopWithResult. +/// which is passed to [onPopWithResult]. /// /// {@tool dartpad} /// This sample demonstrates how to use this widget to properly handle system @@ -53,8 +53,8 @@ class NavigatorPopHandler extends StatefulWidget { /// The widget to place below this in the widget tree. /// - /// Typically this is a [Navigator] that will handle the pop when [onPop] is - /// called. + /// Typically this is a [Navigator] that will handle the pop when + /// [onPopWithResult] is called. final Widget child; /// Whether this widget's ability to handle system back gestures is enabled or @@ -87,7 +87,7 @@ class NavigatorPopHandler extends StatefulWidget { /// /// For example, a pop is handleable when a [Navigator] in [child] has /// multiple routes on its stack. It's not handleable when it has only a - /// single route, and so [onPop] will not be called. + /// single route, and so [onPopWithResult] will not be called. /// /// Typically this is used to pop the [Navigator] in [child]. See the sample /// code on [NavigatorPopHandler] for a full example of this. From b6b1ae52ab77fc0dbb6d5b4b97f1367ecb945862 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 29 May 2025 14:53:36 -0700 Subject: [PATCH 34/66] Better null-safe implementation of `AssetTransformerEntry`. (#169645) Some small cleanups I had stashed while looking at https://github.com/flutter/flutter/issues/168629. --- .../build_system/tools/asset_transformer.dart | 2 +- .../lib/src/flutter_manifest.dart | 38 ++++++++----------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart b/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart index 96a774c2340d7..9d9fbc35c1b4f 100644 --- a/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart +++ b/packages/flutter_tools/lib/src/build_system/tools/asset_transformer.dart @@ -114,7 +114,7 @@ final class AssetTransformer { final List transformerArguments = [ '--input=${asset.absolute.path}', '--output=${output.absolute.path}', - ...?transformer.args, + ...transformer.args, ]; final List command = [ diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index fdc1b3075f3d2..10132690a021b 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart @@ -965,10 +965,10 @@ final class AssetTransformerEntry { : args = args ?? const []; final String package; - final List? args; + final List args; Map get descriptor { - return {_kPackage: package, if (args != null) _kArgs: args}; + return {_kPackage: package, _kArgs: args}; } static const String _kPackage = 'package'; @@ -1018,30 +1018,22 @@ final class AssetTransformerEntry { if (other is! AssetTransformerEntry) { return false; } - - final bool argsAreEqual = - (() { - if (args == null && other.args == null) { - return true; - } - if (args?.length != other.args?.length) { - return false; - } - - for (int index = 0; index < args!.length; index += 1) { - if (args![index] != other.args![index]) { - return false; - } - } - return true; - })(); - - return package == other.package && argsAreEqual; + if (package != other.package) { + return false; + } + if (args.length != other.args.length) { + return false; + } + for (int index = 0; index < args.length; index += 1) { + if (args[index] != other.args[index]) { + return false; + } + } + return true; } @override - int get hashCode => - Object.hashAll([package.hashCode, args?.map((String e) => e.hashCode)]); + int get hashCode => Object.hash(package, Object.hashAll(args)); @override String toString() { From 7e99b7f8b38248ac452dab758e432f20ba8969df Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 29 May 2025 15:08:29 -0700 Subject: [PATCH 35/66] [Impeller] let drawImage nine use porter duff optimization. (#169611) Fixes https://github.com/flutter/flutter/issues/169492 Currently we apply a color filter nine times for the drawImageNine calls, which is very expensive. We can do the same porterduff optimization we did for flame for drawImage nine by allowing the porter duff shader to specify a strict src rect. ### Before ![flutter_04](https://github.com/user-attachments/assets/006c89ad-14a6-4387-9bfb-f6be357f43d6) ### After ![flutter_03](https://github.com/user-attachments/assets/e058d86e-7f1a-4708-bb40-8746bb9199e4) --- .../flutter/impeller/display_list/canvas.cc | 27 ++++++---- .../entity/contents/atlas_contents.cc | 31 ++++++++--- .../impeller/entity/contents/atlas_contents.h | 12 ++++- .../contents/filters/blend_filter_contents.cc | 11 ++-- .../entity/contents/vertices_contents.cc | 10 ++-- .../shaders/blending/porter_duff_blend.frag | 37 ++++++++----- engine/src/flutter/impeller/tools/malioc.json | 52 +++++++++---------- 7 files changed, 111 insertions(+), 69 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 084db12a81084..065a9372e55d4 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -349,9 +349,7 @@ void Canvas::DrawPaint(const Paint& paint) { // Optimization: if the texture has a color filter that is a simple // porter-duff blend or matrix filter, then instead of performing a save layer // we should swap out the shader for the porter duff blend shader and avoid a -// saveLayer. This can only be done for imageRects without a strict source -// rect, as the porter duff shader does not support this feature. This -// optimization is important for Flame. +// saveLayer. This optimization is important for Flame. bool Canvas::AttemptColorFilterOptimization( const std::shared_ptr& image, Rect source, @@ -359,11 +357,10 @@ bool Canvas::AttemptColorFilterOptimization( const Paint& paint, const SamplerDescriptor& sampler, SourceRectConstraint src_rect_constraint) { - if (src_rect_constraint == SourceRectConstraint::kStrict || // - !paint.color_filter || // - paint.image_filter != nullptr || // - paint.invert_colors || // - paint.mask_blur_descriptor.has_value() || // + if (!paint.color_filter || // + paint.image_filter != nullptr || // + paint.invert_colors || // + paint.mask_blur_descriptor.has_value() || // !IsPipelineBlendOrMatrixFilter(paint.color_filter)) { return false; } @@ -377,7 +374,9 @@ bool Canvas::AttemptColorFilterOptimization( /*destination=*/dest, /*color=*/skia_conversions::ToColor(blend_filter->color()), /*blend_mode=*/blend_filter->mode(), - /*desc=*/sampler); + /*desc=*/sampler, + /*use_strict_src_rect=*/src_rect_constraint == + SourceRectConstraint::kStrict); auto atlas_contents = std::make_shared(); atlas_contents->SetGeometry(&geometry); @@ -390,6 +389,12 @@ bool Canvas::AttemptColorFilterOptimization( AddRenderEntityToCurrentPass(entity); } else { + // src_rect_constraint is only supported in the porter-duff mode + // for now. + if (src_rect_constraint == SourceRectConstraint::kStrict) { + return false; + } + const flutter::DlMatrixColorFilter* matrix_filter = paint.color_filter->asMatrix(); @@ -399,7 +404,9 @@ bool Canvas::AttemptColorFilterOptimization( /*destination=*/dest, /*color=*/Color::Khaki(), // ignored /*blend_mode=*/BlendMode::kSrcOver, // ignored - /*desc=*/sampler); + /*desc=*/sampler, + /*use_strict_src_rect=*/src_rect_constraint == + SourceRectConstraint::kStrict); auto atlas_contents = std::make_shared(); atlas_contents->SetGeometry(&geometry); diff --git a/engine/src/flutter/impeller/entity/contents/atlas_contents.cc b/engine/src/flutter/impeller/entity/contents/atlas_contents.cc index 6bd795a07afd5..581350ba9508b 100644 --- a/engine/src/flutter/impeller/entity/contents/atlas_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/atlas_contents.cc @@ -23,13 +23,15 @@ DrawImageRectAtlasGeometry::DrawImageRectAtlasGeometry( const Rect& destination, const Color& color, BlendMode blend_mode, - const SamplerDescriptor& desc) + const SamplerDescriptor& desc, + bool use_strict_src_rect) : texture_(std::move(texture)), source_(source), destination_(destination), color_(color), blend_mode_(blend_mode), - desc_(desc) {} + desc_(desc), + use_strict_src_rect_(use_strict_src_rect) {} DrawImageRectAtlasGeometry::~DrawImageRectAtlasGeometry() = default; @@ -123,6 +125,13 @@ bool DrawImageRectAtlasGeometry::ShouldInvertBlendMode() const { return false; } +std::optional DrawImageRectAtlasGeometry::GetStrictSrcRect() const { + if (use_strict_src_rect_) { + return source_; + } + return std::nullopt; +} + //// AtlasContents::AtlasContents() = default; @@ -215,12 +224,18 @@ bool AtlasContents::Render(const ContentContext& renderer, frame_info.texture_sampler_y_coord_scale = geometry_->GetAtlas()->GetYCoordScale(); - frag_info.output_alpha = alpha_; - frag_info.input_alpha = 1.0; - - // These values are ignored on platforms that natively support decal. - frag_info.tmx = static_cast(Entity::TileMode::kDecal); - frag_info.tmy = static_cast(Entity::TileMode::kDecal); + frag_info.input_alpha_output_alpha_tmx_tmy = + Vector4(1.0, alpha_, static_cast(Entity::TileMode::kDecal), + static_cast(Entity::TileMode::kDecal)); + if (auto rect = geometry_->GetStrictSrcRect(); rect.has_value()) { + Rect src_rect = rect.value(); + frag_info.source_rect = + Vector4(src_rect.GetX(), src_rect.GetY(), src_rect.GetBottom(), + src_rect.GetRight()); + frag_info.use_strict_source_rect = 1.0; + } else { + frag_info.use_strict_source_rect = 0.0; + } FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); diff --git a/engine/src/flutter/impeller/entity/contents/atlas_contents.h b/engine/src/flutter/impeller/entity/contents/atlas_contents.h index 978ee0796d1aa..c56c46bca4bb0 100644 --- a/engine/src/flutter/impeller/entity/contents/atlas_contents.h +++ b/engine/src/flutter/impeller/entity/contents/atlas_contents.h @@ -39,6 +39,12 @@ class AtlasGeometry { virtual BlendMode GetBlendMode() const = 0; virtual bool ShouldInvertBlendMode() const { return true; } + + /// @brief The source rect of the draw if a strict source rect should + /// be applied, or nullopt. + /// + /// See also `Canvas::AttemptColorFilterOptimization` + virtual std::optional GetStrictSrcRect() const { return std::nullopt; } }; /// @brief An atlas geometry that adapts for drawImageRect. @@ -49,7 +55,8 @@ class DrawImageRectAtlasGeometry : public AtlasGeometry { const Rect& destination, const Color& color, BlendMode blend_mode, - const SamplerDescriptor& desc); + const SamplerDescriptor& desc, + bool use_strict_src_rect = false); ~DrawImageRectAtlasGeometry(); @@ -71,6 +78,8 @@ class DrawImageRectAtlasGeometry : public AtlasGeometry { bool ShouldInvertBlendMode() const override; + std::optional GetStrictSrcRect() const override; + private: const std::shared_ptr texture_; const Rect source_; @@ -78,6 +87,7 @@ class DrawImageRectAtlasGeometry : public AtlasGeometry { const Color color_; const BlendMode blend_mode_; const SamplerDescriptor desc_; + const bool use_strict_src_rect_; }; class AtlasContents final : public Contents { diff --git a/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc b/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc index f9196a68a679e..3d0fb91551251 100644 --- a/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/filters/blend_filter_contents.cc @@ -471,11 +471,12 @@ std::optional BlendFilterContents::CreateForegroundPorterDuffBlend( frame_info.texture_sampler_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - frag_info.input_alpha = - absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes - ? dst_snapshot->opacity * alpha.value_or(1.0) - : 1.0; - frag_info.output_alpha = 1.0; + frag_info.input_alpha_output_alpha_tmx_tmy = + Vector4(absorb_opacity == ColorFilterContents::AbsorbOpacity::kYes + ? dst_snapshot->opacity * alpha.value_or(1.0) + : 1.0, + 1, 0, 0); + frag_info.use_strict_source_rect = 0.0; FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); VS::BindFrameInfo(pass, host_buffer.EmplaceUniform(frame_info)); diff --git a/engine/src/flutter/impeller/entity/contents/vertices_contents.cc b/engine/src/flutter/impeller/entity/contents/vertices_contents.cc index 1e0d06d631460..13e98ce0f6b0c 100644 --- a/engine/src/flutter/impeller/entity/contents/vertices_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/vertices_contents.cc @@ -164,12 +164,10 @@ bool VerticesSimpleBlendContents::Render(const ContentContext& renderer, frame_info.texture_sampler_y_coord_scale = texture->GetYCoordScale(); frame_info.mvp = geometry_result.transform; - frag_info.output_alpha = alpha_; - frag_info.input_alpha = 1.0; - - // These values are ignored if the platform supports native decal mode. - frag_info.tmx = static_cast(tile_mode_x_); - frag_info.tmy = static_cast(tile_mode_y_); + frag_info.input_alpha_output_alpha_tmx_tmy = + Vector4(1, alpha_, static_cast(tile_mode_x_), + static_cast(tile_mode_y_)); + frag_info.use_strict_source_rect = 0.0; auto& host_buffer = renderer.GetTransientsBuffer(); FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info)); diff --git a/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag b/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag index d7eb34caf5547..50fa645645c88 100644 --- a/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag +++ b/engine/src/flutter/impeller/entity/shaders/blending/porter_duff_blend.frag @@ -20,35 +20,46 @@ layout(constant_id = 5) const float dst_coeff_src_color = 1.0; uniform f16sampler2D texture_sampler_dst; uniform FragInfo { - float16_t input_alpha; - float16_t output_alpha; - float tmx; - float tmy; + // packed input, output alpha and x/y tilemodes. + vec4 input_alpha_output_alpha_tmx_tmy; + vec4 source_rect; + // When value is non-zero, uses texture coordinates clamped by `source_rect`. + float use_strict_source_rect; } frag_info; +float input_alpha = frag_info.input_alpha_output_alpha_tmx_tmy.x; +float output_alpha = frag_info.input_alpha_output_alpha_tmx_tmy.y; +float tile_mode_x = frag_info.input_alpha_output_alpha_tmx_tmy.z; +float tile_mode_y = frag_info.input_alpha_output_alpha_tmx_tmy.w; + in vec2 v_texture_coords; in f16vec4 v_color; out vec4 frag_color; -f16vec4 Sample(f16sampler2D texture_sampler, - vec2 texture_coords, - float tmx, - float tmy) { +f16vec4 Sample(f16sampler2D texture_sampler, vec2 texture_coords) { if (supports_decal > 0.0) { return texture(texture_sampler, texture_coords); } - return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tmx, tmy); + return IPHalfSampleWithTileMode(texture_sampler, texture_coords, tile_mode_x, + tile_mode_y); } void main() { - f16vec4 dst = Sample(texture_sampler_dst, v_texture_coords, frag_info.tmx, - frag_info.tmy) * - frag_info.input_alpha; + vec2 texture_coords = + mix(v_texture_coords, + vec2(clamp(v_texture_coords.x, frag_info.source_rect.x, + frag_info.source_rect.z), + clamp(v_texture_coords.y, frag_info.source_rect.y, + frag_info.source_rect.w)), + frag_info.use_strict_source_rect); + + f16vec4 dst = + Sample(texture_sampler_dst, texture_coords) * float16_t(input_alpha); f16vec4 src = v_color; frag_color = f16vec4(src * (src_coeff + dst.a * src_coeff_dst_alpha) + dst * (dst_coeff + src.a * dst_coeff_src_alpha + src * dst_coeff_src_color)); - frag_color *= frag_info.output_alpha; + frag_color *= output_alpha; } diff --git a/engine/src/flutter/impeller/tools/malioc.json b/engine/src/flutter/impeller/tools/malioc.json index c4b266e34a034..3d518ec7367cd 100644 --- a/engine/src/flutter/impeller/tools/malioc.json +++ b/engine/src/flutter/impeller/tools/malioc.json @@ -5161,16 +5161,16 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 71, + "fp16_arithmetic": 60, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ "varying" ], "longest_path_cycles": [ - 0.21875, - 0.21875, - 0.03125, + 0.28125, + 0.28125, + 0.078125, 0.0, 0.0, 0.5, @@ -5189,9 +5189,9 @@ "varying" ], "shortest_path_cycles": [ - 0.21875, - 0.21875, - 0.0, + 0.28125, + 0.28125, + 0.046875, 0.0, 0.0, 0.5, @@ -5201,9 +5201,9 @@ "varying" ], "total_cycles": [ - 0.21875, - 0.21875, - 0.03125, + 0.28125, + 0.28125, + 0.078125, 0.0, 0.0, 0.5, @@ -5212,7 +5212,7 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 4, + "uniform_registers_used": 6, "work_registers_used": 20 } } @@ -5230,7 +5230,7 @@ "arithmetic" ], "longest_path_cycles": [ - 1.3200000524520874, + 2.309999942779541, 1.0, 1.0 ], @@ -5243,7 +5243,7 @@ "arithmetic" ], "shortest_path_cycles": [ - 1.3200000524520874, + 2.309999942779541, 1.0, 1.0 ], @@ -5251,7 +5251,7 @@ "arithmetic" ], "total_cycles": [ - 1.6666666269302368, + 2.6666667461395264, 1.0, 1.0 ] @@ -9014,16 +9014,16 @@ "uses_late_zs_update": false, "variants": { "Main": { - "fp16_arithmetic": 100, + "fp16_arithmetic": 60, "has_stack_spilling": false, "performance": { "longest_path_bound_pipelines": [ "varying" ], "longest_path_cycles": [ - 0.1875, - 0.1875, - 0.0, + 0.25, + 0.25, + 0.0625, 0.0, 0.0, 0.5, @@ -9042,9 +9042,9 @@ "varying" ], "shortest_path_cycles": [ - 0.1875, - 0.1875, - 0.0, + 0.25, + 0.25, + 0.0625, 0.0, 0.0, 0.5, @@ -9054,9 +9054,9 @@ "varying" ], "total_cycles": [ - 0.1875, - 0.1875, - 0.0, + 0.25, + 0.25, + 0.0625, 0.0, 0.0, 0.5, @@ -9065,8 +9065,8 @@ }, "stack_spill_bytes": 0, "thread_occupancy": 100, - "uniform_registers_used": 6, - "work_registers_used": 8 + "uniform_registers_used": 10, + "work_registers_used": 9 } } } From cfd7c9cbfa74dbf4315dc8c1213f73c218ac953e Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 29 May 2025 16:31:00 -0700 Subject: [PATCH 36/66] Mark `Linux web_tool_tests` as `bringup` due to being 10%+ flaky (#169716) See https://github.com/flutter/flutter/issues/169574. --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index f4aedb4e11836..5213230dc5157 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2246,6 +2246,7 @@ targets: - name: Linux web_tool_tests recipe: flutter/flutter_drone + bringup: true # Flaky https://github.com/flutter/flutter/issues/169574 timeout: 90 # https://github.com/flutter/flutter/issues/169634 properties: dependencies: >- From 27787515e97437dc38df800f729f6a3c1e61cd6d Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Thu, 29 May 2025 17:10:01 -0700 Subject: [PATCH 37/66] Merge changelog from 3.32.1. (#169713) This just updates the changelog from the 3.32.1 stable hotfix release. --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5182d10ee9f58..fd56e6aa980b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,14 @@ docs/releases/Hotfix-Documentation-Best-Practices.md ## Flutter 3.32 Changes ### [3.32.1](https://github.com/flutter/flutter/releases/tag/3.32.1) + +- [flutter/156793](https://github.com/flutter/flutter/issues/156793) - Fixes flaky crash when targeting web applications via IDEs using the DAP. +- [flutter/168849](https://github.com/flutter/flutter/issues/168849) - Fixes an issue rendering wide gamut images. +- [flutter/168846](https://github.com/flutter/flutter/issues/168846) - Fixes an issue displaying the wrong icons in the widget inspector for some apps. +- [flutter/167011](https://github.com/flutter/flutter/pull/167011) - Fixes Flutter Android builds for apps which use plugins with old Android Gradle Plugin versions. +- [flutter/169101](https://github.com/flutter/flutter/issues/169101) - Reduces the cost of running the (sometimes flaky) Linux fuchsia_test on release branches. +- [flutter/169318](https://github.com/flutter/flutter/issues/169318) - Fixed a bug where the flutter tool crash reporting did not include what plugins were being used by the current project. +- [flutter/169160](https://github.com/flutter/flutter/issues/169160) Fixed a bug where `appFlavor` is null after hot restarts or during `flutter test`. - [flutter/167011](https://github.com/flutter/flutter/pull/167011) [Android] Fix regression in NDK version checking for projects with old AGP versions. - [flutter/168847](https://github.com/flutter/flutter/pull/168847) [Widget Inspector] Fix missing cupertino icon in on-device inspector. From 4cc47e8d52ad96a9c70d2eef839665d8c858d50e Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 29 May 2025 17:10:02 -0700 Subject: [PATCH 38/66] IOSSystemContextMenuItem.toString to Diagnosticable (#169705) The IOSSystemContextMenuItem should mixin Diagnosticable instead of overriding toString. Fixes https://github.com/flutter/flutter/issues/169696 --- .../lib/src/widgets/system_context_menu.dart | 22 ++++++++------ .../widgets/system_context_menu_test.dart | 30 +++++++++++++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/system_context_menu.dart b/packages/flutter/lib/src/widgets/system_context_menu.dart index 2c97d9deecbc6..44b88996a1b05 100644 --- a/packages/flutter/lib/src/widgets/system_context_menu.dart +++ b/packages/flutter/lib/src/widgets/system_context_menu.dart @@ -5,6 +5,7 @@ /// @docImport 'package:flutter/material.dart'; library; +import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -320,7 +321,7 @@ final class IOSSystemContextMenuItemSelectAll extends IOSSystemContextMenuItem { /// context menu. /// * [IOSSystemContextMenuItemDataLookUp], which specifies the data to be sent /// to the platform for this same button. -final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { +final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem with Diagnosticable { /// Creates an instance of [IOSSystemContextMenuItemLookUp]. const IOSSystemContextMenuItemLookUp({this.title}); @@ -333,8 +334,9 @@ final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { } @override - String toString() { - return 'IOSSystemContextMenuItemLookUp(title: $title)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('title', title)); } } @@ -355,7 +357,7 @@ final class IOSSystemContextMenuItemLookUp extends IOSSystemContextMenuItem { /// context menu. /// * [IOSSystemContextMenuItemDataSearchWeb], which specifies the data to be /// sent to the platform for this same button. -final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { +final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem with Diagnosticable { /// Creates an instance of [IOSSystemContextMenuItemSearchWeb]. const IOSSystemContextMenuItemSearchWeb({this.title}); @@ -370,8 +372,9 @@ final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { } @override - String toString() { - return 'IOSSystemContextMenuItemSearchWeb(title: $title)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('title', title)); } } @@ -392,7 +395,7 @@ final class IOSSystemContextMenuItemSearchWeb extends IOSSystemContextMenuItem { /// context menu. /// * [IOSSystemContextMenuItemDataShare], which specifies the data to be sent /// to the platform for this same button. -final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem { +final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem with Diagnosticable { /// Creates an instance of [IOSSystemContextMenuItemShare]. const IOSSystemContextMenuItemShare({this.title}); @@ -405,8 +408,9 @@ final class IOSSystemContextMenuItemShare extends IOSSystemContextMenuItem { } @override - String toString() { - return 'IOSSystemContextMenuItemShare(title: $title)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(StringProperty('title', title)); } } diff --git a/packages/flutter/test/widgets/system_context_menu_test.dart b/packages/flutter/test/widgets/system_context_menu_test.dart index 9cd53a9f4e205..7ebadd0d686ae 100644 --- a/packages/flutter/test/widgets/system_context_menu_test.dart +++ b/packages/flutter/test/widgets/system_context_menu_test.dart @@ -698,4 +698,34 @@ void main() { ); }, ); + + // Regression test for https://github.com/flutter/flutter/issues/169696. + test('IOSSystemContextMenuItemLookUp debugFillProperties', () { + const String title = 'my title'; + const IOSSystemContextMenuItemLookUp item = IOSSystemContextMenuItemLookUp(title: title); + final List diagnosticsNodes = item.toDiagnosticsNode().getProperties(); + expect(diagnosticsNodes, hasLength(1)); + expect(diagnosticsNodes.first.name, 'title'); + expect(diagnosticsNodes.first.value, title); + }); + + // Regression test for https://github.com/flutter/flutter/issues/169696. + test('IOSSystemContextMenuItemSearchWeb debugFillProperties', () { + const String title = 'my title'; + const IOSSystemContextMenuItemSearchWeb item = IOSSystemContextMenuItemSearchWeb(title: title); + final List diagnosticsNodes = item.toDiagnosticsNode().getProperties(); + expect(diagnosticsNodes, hasLength(1)); + expect(diagnosticsNodes.first.name, 'title'); + expect(diagnosticsNodes.first.value, title); + }); + + // Regression test for https://github.com/flutter/flutter/issues/169696. + test('IOSSystemContextMenuItemShare debugFillProperties', () { + const String title = 'my title'; + const IOSSystemContextMenuItemShare item = IOSSystemContextMenuItemShare(title: title); + final List diagnosticsNodes = item.toDiagnosticsNode().getProperties(); + expect(diagnosticsNodes, hasLength(1)); + expect(diagnosticsNodes.first.name, 'title'); + expect(diagnosticsNodes.first.value, title); + }); } From 538cf22b635888fc7df0a424fd7b55c9b01edf41 Mon Sep 17 00:00:00 2001 From: LouiseHsu Date: Thu, 29 May 2025 17:10:04 -0700 Subject: [PATCH 39/66] Add missing localization generation for widgets (#169695) Adds missing localization generation for widget translations I ran into this issue when I was trying to generate files for https://github.com/flutter/flutter/pull/169150/files, and found out the files were being generated for cupertino and material but not widgets. ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --- dev/tools/localization/bin/gen_missing_localizations.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tools/localization/bin/gen_missing_localizations.dart b/dev/tools/localization/bin/gen_missing_localizations.dart index 8a23fe2dd1089..50a82be813070 100644 --- a/dev/tools/localization/bin/gen_missing_localizations.dart +++ b/dev/tools/localization/bin/gen_missing_localizations.dart @@ -42,6 +42,7 @@ Future main(List rawArgs) async { ); updateMissingResources(localizationPath, 'material', removeUndefined: removeUndefined); updateMissingResources(localizationPath, 'cupertino', removeUndefined: removeUndefined); + updateMissingResources(localizationPath, 'widgets', removeUndefined: removeUndefined); } Map loadBundle(File file) { From 1677233f4ced5d364f18dc8db7954ed7927609d7 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 29 May 2025 17:13:53 -0700 Subject: [PATCH 40/66] Don't show SystemContextMenu for SelectableText (#169238) Goes back to using the Flutter-drawn context menu for SelectableText. Currently, SystemContextMenu requires an active text input connection to work. This snuck in because SelectableText is based on EditableText. Fixes https://github.com/flutter/flutter/issues/169001 --- .../flutter/lib/src/material/selectable_text.dart | 3 --- .../flutter/test/widgets/selectable_text_test.dart | 13 ++++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index 00f5cdab52831..77d5cd8895d81 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -447,9 +447,6 @@ class SelectableText extends StatefulWidget { BuildContext context, EditableTextState editableTextState, ) { - if (defaultTargetPlatform == TargetPlatform.iOS && SystemContextMenu.isSupported(context)) { - return SystemContextMenu.editableText(editableTextState: editableTextState); - } return AdaptiveTextSelectionToolbar.editableText(editableTextState: editableTextState); } diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 8e440a986e956..1c754e853144a 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -5582,8 +5582,9 @@ void main() { }); group('context menu', () { + // Regression test for https://github.com/flutter/flutter/issues/169001. testWidgets( - 'iOS uses the system context menu by default if supported', + 'iOS does not use the system context menu by default even when supported', (WidgetTester tester) async { tester.platformDispatcher.supportsShowingSystemContextMenu = true; addTearDown(() { @@ -5591,20 +5592,18 @@ void main() { tester.view.reset(); }); - final TextEditingController controller = TextEditingController(text: 'one two three'); - addTearDown(controller.dispose); await tester.pumpWidget( // Don't wrap with the global View so that the change to // platformDispatcher is read. wrapWithView: false, View( view: tester.view, - child: MaterialApp(home: Material(child: TextField(controller: controller))), + child: const MaterialApp(home: Material(child: SelectableText('one two three'))), ), ); // No context menu shown. - expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing); + expect(find.byType(CupertinoTextSelectionToolbar), findsNothing); expect(find.byType(SystemContextMenu), findsNothing); // Double tap to select the first word and show the menu. @@ -5613,8 +5612,8 @@ void main() { await tester.tapAt(textOffsetToPosition(tester, 1)); await tester.pump(SelectionOverlay.fadeDuration); - expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing); - expect(find.byType(SystemContextMenu), findsOneWidget); + expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget); + expect(find.byType(SystemContextMenu), findsNothing); }, skip: kIsWeb, // [intended] on web the browser handles the context menu. variant: TargetPlatformVariant.only(TargetPlatform.iOS), From e8706558cde02b529ce6a688393dd3323c1cd20b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 29 May 2025 20:13:55 -0400 Subject: [PATCH 41/66] Roll Skia from 191ef95dbe54 to f34be67e8a6b (3 revisions) (#169697) https://skia.googlesource.com/skia.git/+log/191ef95dbe54..f34be67e8a6b 2025-05-29 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-29 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 58febb14bdad to d2a2ceb52656 (4 revisions) 2025-05-29 kjlubick@google.com Make PDF and XPS devices provide a CPU recorder If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC codefu@google.com,kjlubick@google.com,nicolettep@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 2764503e828c4..581521cf5f1c2 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '191ef95dbe5483104ef6aaf8842b77fc97af8ae3', + 'skia_revision': 'f34be67e8a6b20a6f0f93fe2280954e7a367389a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/engine/src/flutter/ci/licenses_golden/licenses_skia b/engine/src/flutter/ci/licenses_golden/licenses_skia index f86bffb6d2515..c284db73a72f3 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_skia +++ b/engine/src/flutter/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 5aeb0da65bd13e6fe657b800e4bfc052 +Signature: bd667b6ca0efec22759648aee7aa8daa ==================================================================================================== LIBRARY: etc1 From 033b32123f46bad96d83067847e5cbd28982a83b Mon Sep 17 00:00:00 2001 From: "John \"codefu\" McDole" Date: Thu, 29 May 2025 17:16:48 -0700 Subject: [PATCH 42/66] feat: experimental workflow for Linux tool-tests-general (#169706) Demonstrates running Linux tool-tests-general running on workflows. Can be run locally using ACT: `gh act --workflows ".github/workflows/tool-test-general.yml" --secret-file "" --var-file "" --input-file "" --eventpath ""` - except this works only in VSCode since tty isn't attached. --- .github/workflows/tool-test-general.yml | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/tool-test-general.yml diff --git a/.github/workflows/tool-test-general.yml b/.github/workflows/tool-test-general.yml new file mode 100644 index 0000000000000..72d93fb124fc5 --- /dev/null +++ b/.github/workflows/tool-test-general.yml @@ -0,0 +1,56 @@ +name: Tool tests general - experiment + +on: + pull_request: + branches: [master] + paths: + - 'dev/**' + - 'packages/flutter_tools/**' + - 'bin/**' + - '.ci.yaml' + - 'engine/**' + - 'DEPS' + push: + branches: [main] + +jobs: + Linux_tool-tests-general: + permissions: + contents: read + + runs-on: ubuntu-latest + + steps: + # The following step is only run LOCALLY - Github runners have everything on them + - name: Set up our JDK environment + if: ${{ env.ACT }} + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 + with: + java-version: '21' + distribution: 'temurin' + + # The following step is only run LOCALLY - Github runners have everything on them + - name: Setup Android SDK + if: ${{ env.ACT }} + uses: amyu/setup-android@v4 + with: + sdk-version: 36 + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Path Update + run: | + echo "$PWD/bin" >> "$GITHUB_PATH" + + - name: Flutter Doctor + run: | + flutter doctor + + - name: Get packages + run: | + flutter update-packages + + - name: Tool Test + run: | + SHARD=tool_tests SUBSHARD=general dart --enable-asserts dev/bots/test.dart From 3b87537bbef6a0cdf8c2248f082b50a23ce0a3ac Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 29 May 2025 21:22:36 -0400 Subject: [PATCH 43/66] Roll Fuchsia Linux SDK from WvRLeTv2ocKsPOdrq... to 0CZI-EGv7NDSolQsj... (#169717) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter Please CC codefu@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 581521cf5f1c2..4a1f5199c852d 100644 --- a/DEPS +++ b/DEPS @@ -813,7 +813,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'WvRLeTv2ocKsPOdrq6vLJD4yrP7nK7ElT9ieuFnvumUC' + 'version': '0CZI-EGv7NDSolQsjzps1riuFJt2Ii5FXpy1OVM0kd0C' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia index d83405a7f276d..87d3950d77415 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia +++ b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 14930a85cd4de0b2742abfacf64f042b +Signature: b89a628353fc10e0a377c365e69f3cb4 ==================================================================================================== LIBRARY: fuchsia_sdk From 351718d10bc0ad485132856a27f7e56efe011bb6 Mon Sep 17 00:00:00 2001 From: "John \"codefu\" McDole" Date: Thu, 29 May 2025 20:08:34 -0700 Subject: [PATCH 44/66] fix: update experiment to use different setup (#169728) Use android-actions/setup-android even if its more verbose. --- .github/workflows/tool-test-general.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tool-test-general.yml b/.github/workflows/tool-test-general.yml index 72d93fb124fc5..d5ac61e463f07 100644 --- a/.github/workflows/tool-test-general.yml +++ b/.github/workflows/tool-test-general.yml @@ -4,6 +4,7 @@ on: pull_request: branches: [master] paths: + - '.github/workflows/tool-test-general.yml' - 'dev/**' - 'packages/flutter_tools/**' - 'bin/**' @@ -32,9 +33,15 @@ jobs: # The following step is only run LOCALLY - Github runners have everything on them - name: Setup Android SDK if: ${{ env.ACT }} - uses: amyu/setup-android@v4 + uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 with: - sdk-version: 36 + cmdline-tools-version: 13114758 + + # The following step is only run LOCALLY - Github runners have everything on them + - name: install android + if: ${{ env.ACT }} + run: | + sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0" - name: Checkout code uses: actions/checkout@v4 From 92879427fc87c8fb705c7d1ffeead5900d1eda67 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 29 May 2025 21:26:24 -0700 Subject: [PATCH 45/66] Update `Experimental-Branch.md` (#169721) It's no longer a "bit of a hack", it's just a permanent hack ;) (We look for branches with recent commits instead) --- docs/infra/Experimental-Branch.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/infra/Experimental-Branch.md b/docs/infra/Experimental-Branch.md index c86b2e564eb93..56466ac27db1b 100644 --- a/docs/infra/Experimental-Branch.md +++ b/docs/infra/Experimental-Branch.md @@ -58,6 +58,3 @@ asynchronously (typically a few minutes, though may take longer when postsubmit queues are under load): ![Example](https://github.com/user-attachments/assets/077094b6-5f7e-4e1b-952c-2a3d1abf6f8f) - -To enable a branch for "Run all tasks", reach out to `team-infra`. It's a [bit -of a hack](https://github.com/flutter/cocoon/blob/249ffc063ddd43aec681c776a2953d5c26f294a3/app_dart/lib/src/request_handlers/scheduler/batch_backfiller.dart#L64-L72) at the moment. From 8132e1828561c54894c96c2c67c20a10ee404115 Mon Sep 17 00:00:00 2001 From: stuartmorgan-g Date: Fri, 30 May 2025 03:35:39 -0700 Subject: [PATCH 46/66] Remove discontinued packages from issue template (#169666) These six packages have been discontinued: https://github.com/flutter/flutter/issues/162960 --- .github/ISSUE_TEMPLATE/08_first_party_packages.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/08_first_party_packages.yml b/.github/ISSUE_TEMPLATE/08_first_party_packages.yml index dc8e3f7c74d8d..027928d244a98 100644 --- a/.github/ISSUE_TEMPLATE/08_first_party_packages.yml +++ b/.github/ISSUE_TEMPLATE/08_first_party_packages.yml @@ -31,14 +31,10 @@ body: - animations - camera - cross_file - - css_colors - espresso - extension_google_sign_in_as_googleapis_auth - file_selector - - flutter_adaptive_scaffold - - flutter_image - flutter_lints - - flutter_markdown - flutter_migrate - flutter_plugin_android_lifecycle - flutter_svg @@ -52,11 +48,9 @@ body: - image_picker - in_app_purchase - interactive_media_ads - - ios_platform_images - local_auth - metrics_center - multicast_dns - - palette_generator - path_parsing - path_provider - pigeon From 0b02682934ef90384f22c65c8d0e9ba2452432c9 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Fri, 30 May 2025 09:31:13 -0700 Subject: [PATCH 47/66] Roll expat to 8e49998f (#169707) This matches the version currently used by Skia. Fixes https://github.com/flutter/flutter/issues/169620 --- DEPS | 2 +- .../expat/expat_config/expat_config.h | 1 + engine/src/flutter/ci/licenses.sh | 2 +- .../flutter/ci/licenses_golden/excluded_files | 6 +- .../ci/licenses_golden/licenses_flutter | 124 ++++++++++++++---- 5 files changed, 110 insertions(+), 25 deletions(-) diff --git a/DEPS b/DEPS index 4a1f5199c852d..b2ac0c3d686cc 100644 --- a/DEPS +++ b/DEPS @@ -480,7 +480,7 @@ deps = { }, 'engine/src/flutter/third_party/expat': - Var('chromium_git') + '/external/github.com/libexpat/libexpat.git' + '@' + '654d2de0da85662fcc7644a7acd7c2dd2cfb21f0', + Var('chromium_git') + '/external/github.com/libexpat/libexpat.git' + '@' + '8e49998f003d693213b538ef765814c7d21abada', 'engine/src/flutter/third_party/freetype2': Var('flutter_git') + '/third_party/freetype2' + '@' + 'bfc3453fdc85d87b45c896f68bf2e49ebdaeef0a', diff --git a/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h b/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h index d02d0f6005c0e..770a7759bc75f 100644 --- a/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h +++ b/engine/src/flutter/build/secondary/flutter/third_party/expat/expat_config/expat_config.h @@ -11,4 +11,5 @@ #define STDC_HEADERS 1 #define XML_CONTEXT_BYTES 1024 #define XML_DTD 1 +#define XML_GE 1 #define XML_NS 1 diff --git a/engine/src/flutter/ci/licenses.sh b/engine/src/flutter/ci/licenses.sh index 67f1290f2b3ae..a50e4e54b9f3b 100755 --- a/engine/src/flutter/ci/licenses.sh +++ b/engine/src/flutter/ci/licenses.sh @@ -191,7 +191,7 @@ function verify_licenses() ( local actualLicenseCount actualLicenseCount="$(tail -n 1 flutter/ci/licenses_golden/licenses_flutter | tr -dc '0-9')" - local expectedLicenseCount=846 + local expectedLicenseCount=848 if [[ $actualLicenseCount -ne $expectedLicenseCount ]]; then echo "=============================== ERROR ===============================" diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files index 6d40f111216d7..d6c6f639e005d 100644 --- a/engine/src/flutter/ci/licenses_golden/excluded_files +++ b/engine/src/flutter/ci/licenses_golden/excluded_files @@ -1730,7 +1730,7 @@ ../../../flutter/third_party/expat/.mailmap ../../../flutter/third_party/expat/Brewfile ../../../flutter/third_party/expat/README.md -../../../flutter/third_party/expat/appveyor.yml +../../../flutter/third_party/expat/SECURITY.md ../../../flutter/third_party/expat/expat/.clang-format ../../../flutter/third_party/expat/expat/.gitignore ../../../flutter/third_party/expat/expat/AUTHORS @@ -1748,6 +1748,8 @@ ../../../flutter/third_party/expat/expat/conftools/ax-append-link-flags.m4 ../../../flutter/third_party/expat/expat/conftools/ax-check-compile-flag.m4 ../../../flutter/third_party/expat/expat/conftools/ax-check-link-flag.m4 +../../../flutter/third_party/expat/expat/conftools/ax-cxx-compile-stdcxx-11.m4 +../../../flutter/third_party/expat/expat/conftools/ax-cxx-compile-stdcxx.m4 ../../../flutter/third_party/expat/expat/conftools/ax-require-defined.m4 ../../../flutter/third_party/expat/expat/conftools/expat.m4 ../../../flutter/third_party/expat/expat/conftools/expatcfg-compiler-supports-visibility.m4 @@ -1759,12 +1761,14 @@ ../../../flutter/third_party/expat/expat/gennmtab/.gitignore ../../../flutter/third_party/expat/expat/lib/.gitignore ../../../flutter/third_party/expat/expat/lib/libexpat.def.cmake +../../../flutter/third_party/expat/expat/m4/.gitignore ../../../flutter/third_party/expat/expat/memory-sanitizer-blacklist.txt ../../../flutter/third_party/expat/expat/tests ../../../flutter/third_party/expat/expat/win32/.gitignore ../../../flutter/third_party/expat/expat/win32/MANIFEST.txt ../../../flutter/third_party/expat/expat/win32/README.txt ../../../flutter/third_party/expat/expat/win32/expat.iss +../../../flutter/third_party/expat/expat/win32/version.rc.cmake ../../../flutter/third_party/expat/expat/xmlwf/.gitignore ../../../flutter/third_party/expat/expat/xmlwf/xmlwf_helpgen.py ../../../flutter/third_party/expat/testdata diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 5af61b2dc25e4..a983a503b8b46 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -1281,8 +1281,6 @@ ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutte ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/cpu_features/src/src/stack_line_reader.c ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/cpu_features/src/src/string_view.c ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/cpu_features/src/src/utils/list_cpu_features.c -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parse_fuzzer.c -ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parsebuffer_fuzzer.c ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/flatbuffers/conan/test_package/test_package.cpp ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/flatbuffers/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java ORIGIN: http://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/flatbuffers/grpc/src/compiler/java_generator.cc @@ -4101,6 +4099,8 @@ ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutt ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/boringssl/src/tool/tool.cc ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/boringssl/src/tool/transport_common.cc ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/boringssl/src/tool/transport_common.h +ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parse_fuzzer.c +ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/expat/expat/fuzz/xml_parsebuffer_fuzzer.c ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/wuffs/release/c/wuffs-v0.2.c ORIGIN: https://www.apache.org/licenses/LICENSE-2.0 referenced by ../../../flutter/third_party/wuffs/release/c/wuffs-v0.3.c TYPE: LicenseType.apache @@ -42335,11 +42335,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2000-2005 Fred L. Drake, Jr. Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Cristian Rodríguez Copyright (c) 2016 Thomas Beutlich Copyright (c) 2017 Rhodri James Copyright (c) 2022 Thijs Schreijer +Copyright (c) 2023 Hanno Böck +Copyright (c) 2023 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -42376,7 +42379,7 @@ Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie Copyright (c) 2016 Eric Rahm -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Gaurav Copyright (c) 2016 Thomas Beutlich Copyright (c) 2016 Gustavo Grieco @@ -42395,10 +42398,15 @@ Copyright (c) 2018 Mariusz Zaborski Copyright (c) 2019 David Loffredo Copyright (c) 2019-2020 Ben Wagner Copyright (c) 2019 Vadim Zeitlin -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton Copyright (c) 2022 Jann Horn +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Owain Davies +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024-2025 Berkay Eren Ürün +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -42469,7 +42477,7 @@ Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Don Lewis Copyright (c) 2017 Rhodri James @@ -42477,8 +42485,10 @@ Copyright (c) 2017 Alexander Bluhm Copyright (c) 2017 Benbuck Nason Copyright (c) 2017 José Gutiérrez de la Concha Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Hanno Böck Licensed under the MIT license: @@ -42513,13 +42523,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2004-2009 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo Copyright (c) 2020 Joe Orton Copyright (c) 2020 Kleber Tarcísio Copyright (c) 2021 Tim Bray Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride Licensed under the MIT license: @@ -42556,6 +42567,8 @@ Copyright (c) 2002-2009 Karl Waclawek Copyright (c) 2016-2017 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2017 Franek Korta +Copyright (c) 2022 Sean McBride +Copyright (c) 2025 Hanno Böck Licensed under the MIT license: @@ -42589,7 +42602,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2002-2005 Karl Waclawek -Copyright (c) 2016-2017 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2017 Rhodri James Licensed under the MIT license: @@ -42664,7 +42677,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2005 Karl Waclawek -Copyright (c) 2016-2019 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Licensed under the MIT license: @@ -42725,11 +42738,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== LIBRARY: expat -ORIGIN: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c ORIGIN: ../../../flutter/third_party/expat/expat/xmlwf/codepage.h ORIGIN: ../../../flutter/third_party/expat/expat/xmlwf/filemap.h TYPE: LicenseType.mit -FILE: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c FILE: ../../../flutter/third_party/expat/expat/xmlwf/codepage.h FILE: ../../../flutter/third_party/expat/expat/xmlwf/filemap.h ---------------------------------------------------------------------------------------------------- @@ -42794,6 +42805,39 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== +==================================================================================================== +LIBRARY: expat +ORIGIN: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c +TYPE: LicenseType.mit +FILE: ../../../flutter/third_party/expat/expat/gennmtab/gennmtab.c +---------------------------------------------------------------------------------------------------- +Copyright (c) 1997-2000 Thai Open Source Software Center Ltd +Copyright (c) 2000 Clark Cooper +Copyright (c) 2002 Fred L. Drake, Jr. +Copyright (c) 2016-2024 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +==================================================================================================== + ==================================================================================================== LIBRARY: expat ORIGIN: ../../../flutter/third_party/expat/expat/lib/asciitab.h @@ -42880,10 +42924,10 @@ Copyright (c) 2002 Greg Stein Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Licensed under the MIT license: @@ -42917,7 +42961,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Karl Waclawek Copyright (c) 2002 Fred L. Drake, Jr. -Copyright (c) 2017 Sebastian Pipping +Copyright (c) 2017-2024 Sebastian Pipping Licensed under the MIT license: @@ -42952,10 +42996,11 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2004-2006 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -43312,10 +43357,9 @@ ORIGIN: ../../../flutter/third_party/expat/expat/COPYING TYPE: LicenseType.mit FILE: ../../../flutter/third_party/expat/expat/expat.pc.in FILE: ../../../flutter/third_party/expat/expat/lib/siphash.h -FILE: ../../../flutter/third_party/expat/expat/win32/version.rc ---------------------------------------------------------------------------------------------------- Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -43456,7 +43500,8 @@ FILE: ../../../flutter/third_party/expat/expat/lib/winconfig.h Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Greg Stein Copyright (c) 2005 Karl Waclawek -Copyright (c) 2017-2021 Sebastian Pipping +Copyright (c) 2017-2023 Sebastian Pipping +Copyright (c) 2023 Orgad Shaneh Licensed under the MIT license: @@ -44098,9 +44143,11 @@ FILE: ../../../flutter/third_party/expat/expat/lib/internal.h Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -48532,6 +48579,39 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==================================================================================================== +==================================================================================================== +LIBRARY: expat +ORIGIN: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.cpp +ORIGIN: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.proto +TYPE: LicenseType.mit +FILE: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.cpp +FILE: ../../../flutter/third_party/expat/expat/fuzz/xml_lpm_fuzzer.proto +---------------------------------------------------------------------------------------------------- +Copyright (c) 2022 Mark Brand +Copyright (c) 2025 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +==================================================================================================== + ==================================================================================================== LIBRARY: pkg ORIGIN: ../../../flutter/third_party/pkg/coverage/benchmark/many_isolates.dart + ../../../flutter/third_party/pkg/coverage/LICENSE @@ -79089,4 +79169,4 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. ==================================================================================================== -Total license count: 846 +Total license count: 848 From 088d1bd62a2197a7683484c870a18c3db06318d4 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 30 May 2025 09:52:23 -0700 Subject: [PATCH 48/66] Switch to Linux orchestrators for Windows releasers. (#168941) Towards https://github.com/flutter/flutter/issues/168934. /cc @reidbaker as release engineer /cc @zanderso (we talked about this offline) --- engine/src/flutter/.ci.yaml | 40 ++----------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/engine/src/flutter/.ci.yaml b/engine/src/flutter/.ci.yaml index 4d0cd70f09d6f..9a2cfdbca36b3 100644 --- a/engine/src/flutter/.ci.yaml +++ b/engine/src/flutter/.ci.yaml @@ -503,24 +503,6 @@ targets: - cpu=x86 - name: Linux windows_android_aot_engine - recipe: engine_v2/engine_v2 - timeout: 120 - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # https://github.com/flutter/flutter/issues/168934 - bringup: true - properties: - add_recipes_cq: "true" - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # release_build: "true" - config_name: windows_host_engine - # Do not remove(https://github.com/flutter/flutter/issues/144644) - # Scheduler will fail to get the platform - drone_dimensions: - - os=Linux - - # TODO(matanlurey): Remove and use Linux windows_host_engine. - # https://github.com/flutter/flutter/issues/168934 - - name: Windows windows_android_aot_engine recipe: engine_v2/engine_v2 timeout: 120 properties: @@ -529,28 +511,10 @@ targets: config_name: windows_android_aot_engine # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform - drone_dimensions: - - os=Windows - - - name: Linux windows_host_engine - recipe: engine_v2/engine_v2 - timeout: 120 - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # https://github.com/flutter/flutter/issues/168934 - bringup: true - properties: - add_recipes_cq: "true" - # TODO(matanlurey): Remove bringup: true and add release_build: true. - # release_build: "true" - config_name: windows_host_engine - # Do not remove(https://github.com/flutter/flutter/issues/144644) - # Scheduler will fail to get the platform drone_dimensions: - os=Linux - # TODO(matanlurey): Remove and use Linux windows_host_engine. - # https://github.com/flutter/flutter/issues/168934 - - name: Windows windows_host_engine + - name: Linux windows_host_engine recipe: engine_v2/engine_v2 timeout: 120 properties: @@ -560,7 +524,7 @@ targets: # Do not remove(https://github.com/flutter/flutter/issues/144644) # Scheduler will fail to get the platform drone_dimensions: - - os=Windows + - os=Linux - name: Windows windows_host_engine_test recipe: engine_v2/engine_v2 From d8baa77b38461e7061e06e72c6bf50d64d302b8c Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Fri, 30 May 2025 11:10:53 -0700 Subject: [PATCH 49/66] Revert "fix: update experiment to use different setup (#169728)" and "feat: experimental workflow for Linux tool-tests-general (#169706)" (#169770) The Linux_tool-tests-general check is causing errors on PRs such as Dart->engine rolls (example: https://github.com/flutter/flutter/pull/169763) --- .github/workflows/tool-test-general.yml | 63 ------------------------- 1 file changed, 63 deletions(-) delete mode 100644 .github/workflows/tool-test-general.yml diff --git a/.github/workflows/tool-test-general.yml b/.github/workflows/tool-test-general.yml deleted file mode 100644 index d5ac61e463f07..0000000000000 --- a/.github/workflows/tool-test-general.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Tool tests general - experiment - -on: - pull_request: - branches: [master] - paths: - - '.github/workflows/tool-test-general.yml' - - 'dev/**' - - 'packages/flutter_tools/**' - - 'bin/**' - - '.ci.yaml' - - 'engine/**' - - 'DEPS' - push: - branches: [main] - -jobs: - Linux_tool-tests-general: - permissions: - contents: read - - runs-on: ubuntu-latest - - steps: - # The following step is only run LOCALLY - Github runners have everything on them - - name: Set up our JDK environment - if: ${{ env.ACT }} - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 - with: - java-version: '21' - distribution: 'temurin' - - # The following step is only run LOCALLY - Github runners have everything on them - - name: Setup Android SDK - if: ${{ env.ACT }} - uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 - with: - cmdline-tools-version: 13114758 - - # The following step is only run LOCALLY - Github runners have everything on them - - name: install android - if: ${{ env.ACT }} - run: | - sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0" - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Path Update - run: | - echo "$PWD/bin" >> "$GITHUB_PATH" - - - name: Flutter Doctor - run: | - flutter doctor - - - name: Get packages - run: | - flutter update-packages - - - name: Tool Test - run: | - SHARD=tool_tests SUBSHARD=general dart --enable-asserts dev/bots/test.dart From 40f1695bef096b60a935e2be8882c718d16a6040 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 30 May 2025 16:01:13 -0400 Subject: [PATCH 50/66] Roll Skia from f34be67e8a6b to 815ec432f549 (14 revisions) (#169779) https://skia.googlesource.com/skia.git/+log/f34be67e8a6b..815ec432f549 2025-05-30 bungeman@google.com [gn] Allow libpng and rust png to build together 2025-05-30 michaelludwig@google.com [graphite] Fix unclamped matrix color filters with negative values 2025-05-30 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from d3140371858b to af59becc8906 (3 revisions) 2025-05-30 mike@reedtribe.org Temp work-around for graphite-dawn-mali crasher 2025-05-30 michaelludwig@google.com [graphite] Use float for colorspace xform parameters 2025-05-30 mike@reedtribe.org Use SkSpan in the public API 2025-05-30 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial). 2025-05-30 kjlubick@google.com Reland "[rust png] Make `SkTypeface_fontations.cpp` agnostic to PNG decoder" 2025-05-30 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from d2a2ceb52656 to d3140371858b (9 revisions) 2025-05-30 kjlubick@google.com Make CodeSize.+NoPatch ignore symlinks that don't exist 2025-05-30 skia-autoroll@skia-public.iam.gserviceaccount.com Roll ANGLE from e7118451f513 to 20b08f95e5b3 (9 revisions) 2025-05-30 skia-autoroll@skia-public.iam.gserviceaccount.com Roll Dawn from f53bc591dafd to 91043600f711 (25 revisions) 2025-05-29 sam@gentoo.org skcms: support two attributes with GCC 2025-05-29 robertphillips@google.com [graphite] Add Precompile RE_LinearEffect PaintOptions If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC codefu@google.com,kjlubick@google.com,nicolettep@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- .../flutter/ci/licenses_golden/licenses_skia | 5 +- .../flutter/sky/packages/sky_engine/LICENSE | 103 +++++++++++++++--- 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/DEPS b/DEPS index b2ac0c3d686cc..3001c2ad97018 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'f34be67e8a6b20a6f0f93fe2280954e7a367389a', + 'skia_revision': '815ec432f549bf585c5848f3b4a8aa64e74c3d31', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/engine/src/flutter/ci/licenses_golden/licenses_skia b/engine/src/flutter/ci/licenses_golden/licenses_skia index c284db73a72f3..5c9b55ab79bbe 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_skia +++ b/engine/src/flutter/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: bd667b6ca0efec22759648aee7aa8daa +Signature: d69598d1cd47b0bfdcdbb227eb182e8f ==================================================================================================== LIBRARY: etc1 @@ -434,6 +434,7 @@ FILE: ../../../flutter/third_party/skia/modules/pathkit/perf/pathops.bench.js FILE: ../../../flutter/third_party/skia/modules/pathkit/perf/perfReporter.js FILE: ../../../flutter/third_party/skia/modules/skparagraph/test.html FILE: ../../../flutter/third_party/skia/package-lock.json +FILE: ../../../flutter/third_party/skia/relnotes/fontconfig.md FILE: ../../../flutter/third_party/skia/src/gpu/gpu_workaround_list.txt FILE: ../../../flutter/third_party/skia/src/ports/fontations/Cargo.toml FILE: ../../../flutter/third_party/skia/src/sksl/generated/sksl_compute.minified.sksl @@ -9926,6 +9927,7 @@ ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/Precompile ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/ports/SkFontMgr_fontconfig_freetype.cpp + ../../../flutter/third_party/skia/LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/third_party/skia/gm/hdr_pip_blur.cpp FILE: ../../../flutter/third_party/skia/include/core/SkCPUContext.h @@ -9958,6 +9960,7 @@ FILE: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/PrecompileIm FILE: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.cpp FILE: ../../../flutter/third_party/skia/src/gpu/graphite/precompile/SerializationUtils.h FILE: ../../../flutter/third_party/skia/src/gpu/graphite/vk/precompile/VulkanPrecompileShader.cpp +FILE: ../../../flutter/third_party/skia/src/ports/SkFontMgr_fontconfig_freetype.cpp ---------------------------------------------------------------------------------------------------- Copyright 2025 Google LLC diff --git a/engine/src/flutter/sky/packages/sky_engine/LICENSE b/engine/src/flutter/sky/packages/sky_engine/LICENSE index 930b44d807888..370ec38280723 100644 --- a/engine/src/flutter/sky/packages/sky_engine/LICENSE +++ b/engine/src/flutter/sky/packages/sky_engine/LICENSE @@ -17140,11 +17140,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2000-2005 Fred L. Drake, Jr. Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Cristian Rodríguez Copyright (c) 2016 Thomas Beutlich Copyright (c) 2017 Rhodri James Copyright (c) 2022 Thijs Schreijer +Copyright (c) 2023 Hanno Böck +Copyright (c) 2023 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -17176,7 +17179,7 @@ Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie Copyright (c) 2016 Eric Rahm -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2016 Gaurav Copyright (c) 2016 Thomas Beutlich Copyright (c) 2016 Gustavo Grieco @@ -17195,10 +17198,15 @@ Copyright (c) 2018 Mariusz Zaborski Copyright (c) 2019 David Loffredo Copyright (c) 2019-2020 Ben Wagner Copyright (c) 2019 Vadim Zeitlin -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Samanta Navarro Copyright (c) 2022 Jeffrey Walton Copyright (c) 2022 Jann Horn +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Owain Davies +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024-2025 Berkay Eren Ürün +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -17259,7 +17267,7 @@ Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2016 Pascal Cuoq Copyright (c) 2016 Don Lewis Copyright (c) 2017 Rhodri James @@ -17267,8 +17275,10 @@ Copyright (c) 2017 Alexander Bluhm Copyright (c) 2017 Benbuck Nason Copyright (c) 2017 José Gutiérrez de la Concha Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride +Copyright (c) 2023 Hanno Böck Licensed under the MIT license: @@ -17298,13 +17308,14 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2001-2003 Fred L. Drake, Jr. Copyright (c) 2004-2009 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo Copyright (c) 2020 Joe Orton Copyright (c) 2020 Kleber Tarcísio Copyright (c) 2021 Tim Bray Copyright (c) 2022 Martin Ettl +Copyright (c) 2022 Sean McBride Licensed under the MIT license: @@ -17336,6 +17347,8 @@ Copyright (c) 2002-2009 Karl Waclawek Copyright (c) 2016-2017 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2017 Franek Korta +Copyright (c) 2022 Sean McBride +Copyright (c) 2025 Hanno Böck Licensed under the MIT license: @@ -17364,7 +17377,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2002-2005 Karl Waclawek -Copyright (c) 2016-2017 Sebastian Pipping +Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2017 Rhodri James Licensed under the MIT license: @@ -17429,7 +17442,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2005 Karl Waclawek -Copyright (c) 2016-2019 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Licensed under the MIT license: @@ -17541,6 +17554,34 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- expat +Copyright (c) 1997-2000 Thai Open Source Software Center Ltd +Copyright (c) 2000 Clark Cooper +Copyright (c) 2002 Fred L. Drake, Jr. +Copyright (c) 2016-2024 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- +expat + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Fred L. Drake, Jr. @@ -17605,10 +17646,10 @@ Copyright (c) 2002 Greg Stein Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2005-2009 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na Licensed under the MIT license: @@ -17637,7 +17678,7 @@ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Karl Waclawek Copyright (c) 2002 Fred L. Drake, Jr. -Copyright (c) 2017 Sebastian Pipping +Copyright (c) 2017-2024 Sebastian Pipping Licensed under the MIT license: @@ -17667,10 +17708,11 @@ Copyright (c) 2000 Clark Cooper Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2004-2006 Karl Waclawek Copyright (c) 2005-2007 Steven Solie -Copyright (c) 2016-2021 Sebastian Pipping +Copyright (c) 2016-2023 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo -Copyright (c) 2021 Dong-hee Na +Copyright (c) 2021 Donghee Na +Copyright (c) 2024 Hanno Böck Licensed under the MIT license: @@ -17970,7 +18012,7 @@ authorization of the copyright holder. expat Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -18091,7 +18133,8 @@ expat Copyright (c) 2000 Clark Cooper Copyright (c) 2002 Greg Stein Copyright (c) 2005 Karl Waclawek -Copyright (c) 2017-2021 Sebastian Pipping +Copyright (c) 2017-2023 Sebastian Pipping +Copyright (c) 2023 Orgad Shaneh Licensed under the MIT license: @@ -18617,9 +18660,11 @@ expat Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein -Copyright (c) 2016-2022 Sebastian Pipping +Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo +Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow +Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: @@ -22519,6 +22564,32 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- +expat + +Copyright (c) 2022 Mark Brand +Copyright (c) 2025 Sebastian Pipping + +Licensed under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. +-------------------------------------------------------------------------------- pkg Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file From 3d8fa621c1394a5bc22525676a41bd3a2a4b0ce5 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 30 May 2025 13:57:40 -0700 Subject: [PATCH 51/66] [Reland3] Implements UISceneDelegate dynamically w/ FlutterLaunchEngine (#169276) (#169365) ## **BREAKING CHANGE** Adopting Apple's UISceneDelegate protocol shifts the initialization order of apps. For the common cases we've made sure they will work without change. The one case that will require a change is any app that in `-[UIApplicateDelegate didFinishLaunchingWithOptions:]` assumes that `UIApplicationDelegate.window.rootViewController` is a `FlutterViewController` instance. Users should follow the [migration guide](https://docs.google.com/document/d/16WsqYbANmhupw-gxGPQPZ9B3yz1YBIviS-N1UyIQNSE/edit?tab=t.0#heading=h.txry2otwqko3) to update that usage. ## Changes since revert It's been rebased onto the FlutterPluginRegistrant PR which was used for migration. The dynamic selection of the UISceneDelegate has been removed, instead there is a flutter tool migration to the Info.plist. ## Description fixes: https://github.com/flutter/flutter/issues/167267 design doc: https://docs.google.com/document/d/1ZfcQOs-UKRa9jsFG84-MTFeibZTLKCvPQLxF2eskx44/edit?tab=t.0 relands https://github.com/flutter/flutter/pull/168396 relands https://github.com/flutter/flutter/pull/168914 relands https://github.com/flutter/flutter/pull/169276 ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. --- .../channels/ios/Runner/AppDelegate.m | 21 +++-- .../ios/Runner.xcodeproj/project.pbxproj | 24 ++++- .../ios/Runner/AppDelegate.h | 3 +- .../ios/Runner/AppDelegate.m | 68 -------------- .../ios/Runner/Base.lproj/Main.storyboard | 17 ++-- .../ios/Runner/TextureViewController.h | 8 ++ .../ios/Runner/TextureViewController.m | 75 +++++++++++++++ .../ci/licenses_golden/licenses_flutter | 12 +++ engine/src/flutter/engine.code-workspace | 31 ++++++ .../shell/platform/darwin/ios/BUILD.gn | 6 ++ .../darwin/ios/framework/Headers/Flutter.h | 1 + .../framework/Headers/FlutterAppDelegate.h | 3 +- .../framework/Headers/FlutterSceneDelegate.h | 23 +++++ .../framework/Source/FlutterAppDelegate.mm | 13 ++- .../Source/FlutterAppDelegateTest.mm | 15 +++ .../Source/FlutterAppDelegate_Internal.h | 16 ++++ .../framework/Source/FlutterLaunchEngine.h | 40 ++++++++ .../framework/Source/FlutterLaunchEngine.m | 52 ++++++++++ .../Source/FlutterLaunchEngineTest.mm | 26 +++++ .../framework/Source/FlutterSceneDelegate.m | 32 +++++++ .../framework/Source/FlutterViewController.mm | 40 ++++++-- .../Source/FlutterViewControllerTest.mm | 29 ++++++ .../ios/IosUnitTests/App/AppDelegate.h | 6 ++ .../ios/IosUnitTests/App/AppDelegate.m | 5 + .../ios/IosUnitTests/App/Flutter.storyboard | 33 +++++++ .../IosUnitTests.xcodeproj/project.pbxproj | 6 ++ .../vscode_workspace/engine-workspace.yaml | 15 +++ .../platform_channel/ios/Runner/AppDelegate.m | 17 ++-- .../xcshareddata/xcschemes/Runner.xcscheme | 3 + .../ios/Runner/AppDelegate.swift | 18 ++-- packages/flutter_tools/lib/src/ios/mac.dart | 2 + .../migrations/uiscenedelegate_migration.dart | 94 +++++++++++++++++++ .../app/ios.tmpl/Runner/Info.plist.tmpl | 21 +++++ .../Runner.tmpl/Info.plist.tmpl | 21 +++++ .../ios/ios_project_migration_test.dart | 54 +++++++++++ 35 files changed, 732 insertions(+), 118 deletions(-) create mode 100644 dev/integration_tests/external_textures/ios/Runner/TextureViewController.h create mode 100644 dev/integration_tests/external_textures/ios/Runner/TextureViewController.m create mode 100644 engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h create mode 100644 engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h create mode 100644 engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h create mode 100644 engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m create mode 100644 engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm create mode 100644 engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m create mode 100644 engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard create mode 100644 packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart diff --git a/dev/integration_tests/channels/ios/Runner/AppDelegate.m b/dev/integration_tests/channels/ios/Runner/AppDelegate.m index 8fc53c3005ce7..86f5f91b9b64a 100644 --- a/dev/integration_tests/channels/ios/Runner/AppDelegate.m +++ b/dev/integration_tests/channels/ios/Runner/AppDelegate.m @@ -86,38 +86,39 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. - FlutterViewController *flutterController = - (FlutterViewController *)self.window.rootViewController; - + // This integration test still uses the old way of registering platform + // channels to test backwards compatibility after the UISceneDelegate + // migration. + id registrar = [self registrarForPlugin:@"platform-channel-test"]; ExtendedReaderWriter* extendedReaderWriter = [ExtendedReaderWriter new]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"binary-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterBinaryCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"string-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStringCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"json-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterJSONMessageCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"std-msg" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter]]]; [self setupMethodCallSuccessHandshakeOnChannel: [FlutterMethodChannel methodChannelWithName:@"json-method" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterJSONMethodCodec sharedInstance]]]; [self setupMethodCallSuccessHandshakeOnChannel: [FlutterMethodChannel methodChannelWithName:@"std-method" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStandardMethodCodec codecWithReaderWriter:extendedReaderWriter]]]; [[FlutterBasicMessageChannel messageChannelWithName:@"std-echo" - binaryMessenger:flutterController + binaryMessenger:registrar.messenger codec:[FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter]] setMessageHandler:^(id message, FlutterReply reply) { diff --git a/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj b/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj index 6b7d64dbab365..330127f6d3ec3 100644 --- a/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj +++ b/dev/integration_tests/external_textures/ios/Runner.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0D569A532DDF895D00F24F69 /* TextureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D569A522DDF895D00F24F69 /* TextureViewController.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; @@ -28,6 +29,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D569A522DDF895D00F24F69 /* TextureViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TextureViewController.m; sourceTree = ""; }; + 0D569A542DDF896B00F24F69 /* TextureViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextureViewController.h; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -89,6 +92,8 @@ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 97C146F11CF9000F007C117D /* Supporting Files */, + 0D569A522DDF895D00F24F69 /* TextureViewController.m */, + 0D569A542DDF896B00F24F69 /* TextureViewController.h */, ); path = Runner; sourceTree = ""; @@ -210,6 +215,7 @@ files = ( 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 97C146F31CF9000F007C117D /* main.m in Sources */, + 0D569A532DDF895D00F24F69 /* TextureViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -281,9 +287,13 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.flutter.externalUi; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -382,9 +392,13 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.flutter.externalUi; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -395,9 +409,13 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.flutter.externalUi; PRODUCT_NAME = "$(TARGET_NAME)"; }; diff --git a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h index 4734b3eb65fd9..78655f963b90c 100644 --- a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h +++ b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.h @@ -5,6 +5,5 @@ #import #import -@interface AppDelegate : FlutterAppDelegate - +@interface AppDelegate : FlutterAppDelegate @end diff --git a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m index 7ad7dee967c99..0c732ec7e16ab 100644 --- a/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m +++ b/dev/integration_tests/external_textures/ios/Runner/AppDelegate.m @@ -4,73 +4,5 @@ #import "AppDelegate.h" -@interface AppDelegate () - @property (atomic) uint64_t textureId; - @property (atomic) int framesProduced; - @property (atomic) int framesConsumed; - @property (atomic) int lastFrameConsumed; - @property (atomic) double startTime; - @property (atomic) double endTime; - @property (atomic) double frameRate; - @property (atomic) double frameStartTime; - @property (atomic) NSTimer* timer; - - - (void)tick:(NSTimer*)timer; -@end - @implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - FlutterViewController* flutterController = - (FlutterViewController*)self.window.rootViewController; - FlutterMethodChannel* channel = - [FlutterMethodChannel methodChannelWithName:@"texture" - binaryMessenger:flutterController]; - [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { - if ([@"start" isEqualToString:call.method]) { - _framesProduced = 0; - _framesConsumed = 0; - _frameRate = 1.0 / [(NSNumber*) call.arguments intValue]; - _timer = [NSTimer scheduledTimerWithTimeInterval:_frameRate - target:self - selector:@selector(tick:) - userInfo:nil - repeats:YES]; - _startTime = [[NSDate date] timeIntervalSince1970]; - result(nil); - } else if ([@"stop" isEqualToString:call.method]) { - [_timer invalidate]; - _endTime = [[NSDate date] timeIntervalSince1970]; - result(nil); - } else if ([@"getProducedFrameRate" isEqualToString:call.method]) { - result(@(_framesProduced / (_endTime - _startTime))); - } else if ([@"getConsumedFrameRate" isEqualToString:call.method]) { - result(@(_framesConsumed / (_endTime - _startTime))); - } else { - result(FlutterMethodNotImplemented); - } - }]; - _textureId = [flutterController registerTexture:self]; - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -- (void)tick:(NSTimer*)timer { - FlutterViewController* flutterController = - (FlutterViewController*)self.window.rootViewController; - [flutterController textureFrameAvailable:_textureId]; - _frameStartTime = [[NSDate date] timeIntervalSince1970]; - // We just pretend to be producing a frame. - _framesProduced++; -} - -- (CVPixelBufferRef)copyPixelBuffer { - double now = [[NSDate date] timeIntervalSince1970]; - if (now < _frameStartTime - || _frameStartTime + _frameRate < now - || _framesProduced == _lastFrameConsumed) return nil; - _framesConsumed++; - _lastFrameConsumed = _framesProduced; - // We just pretend to be handing over the produced frame to the consumer. - return nil; -} @end diff --git a/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard b/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard index f3c28516fb38e..5f7cd2ca2e66d 100644 --- a/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard +++ b/dev/integration_tests/external_textures/ios/Runner/Base.lproj/Main.storyboard @@ -1,26 +1,29 @@ - - + + + - + + - + - + - + - + + diff --git a/dev/integration_tests/external_textures/ios/Runner/TextureViewController.h b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.h new file mode 100644 index 0000000000000..cb8eceffa033a --- /dev/null +++ b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.h @@ -0,0 +1,8 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import + +@interface TextureViewController : FlutterViewController +@end diff --git a/dev/integration_tests/external_textures/ios/Runner/TextureViewController.m b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.m new file mode 100644 index 0000000000000..32f0ef3e05ffb --- /dev/null +++ b/dev/integration_tests/external_textures/ios/Runner/TextureViewController.m @@ -0,0 +1,75 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "TextureViewController.h" +#import "AppDelegate.h" + +@interface TextureViewController () +@property (nonatomic, assign) uint64_t textureId; +@property (nonatomic, assign) int framesProduced; +@property (nonatomic, assign) int framesConsumed; +@property (nonatomic, assign) int lastFrameConsumed; +@property (nonatomic, assign) double startTime; +@property (nonatomic, assign) double endTime; +@property (nonatomic, assign) double frameRate; +@property (nonatomic, assign) double frameStartTime; +@property (nonatomic, strong) NSTimer* timer; +- (void)tick:(NSTimer*)timer; +@end + +@implementation TextureViewController + +- (void)awakeFromNib { + [super awakeFromNib]; + + FlutterMethodChannel* channel = + [FlutterMethodChannel methodChannelWithName:@"texture" + binaryMessenger:self.binaryMessenger]; + [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { + if ([@"start" isEqualToString:call.method]) { + _framesProduced = 0; + _framesConsumed = 0; + _frameRate = 1.0 / [(NSNumber*) call.arguments intValue]; + _timer = [NSTimer scheduledTimerWithTimeInterval:_frameRate + target:self + selector:@selector(tick:) + userInfo:nil + repeats:YES]; + _startTime = [[NSDate date] timeIntervalSince1970]; + result(nil); + } else if ([@"stop" isEqualToString:call.method]) { + [_timer invalidate]; + _endTime = [[NSDate date] timeIntervalSince1970]; + result(nil); + } else if ([@"getProducedFrameRate" isEqualToString:call.method]) { + result(@(_framesProduced / (_endTime - _startTime))); + } else if ([@"getConsumedFrameRate" isEqualToString:call.method]) { + result(@(_framesConsumed / (_endTime - _startTime))); + } else { + result(FlutterMethodNotImplemented); + } + }]; + + _textureId = [self registerTexture:self]; +} + +- (void)tick:(NSTimer*)timer { + [self textureFrameAvailable:_textureId]; + _frameStartTime = [[NSDate date] timeIntervalSince1970]; + // We just pretend to be producing a frame. + _framesProduced++; +} + +- (CVPixelBufferRef)copyPixelBuffer { + double now = [[NSDate date] timeIntervalSince1970]; + if (now < _frameStartTime + || _frameStartTime + _frameRate < now + || _framesProduced == _lastFrameConsumed) return nil; + _framesConsumed++; + _lastFrameConsumed = _framesProduced; + // We just pretend to be handing over the produced frame to the consumer. + return nil; +} + +@end diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index a983a503b8b46..32e185519c50d 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -52858,12 +52858,14 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterHead ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/ConnectionCollection.swift + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/ConnectionCollectionTest.swift + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FakeUIPressProxy.swift + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h + ../../../flutter/LICENSE @@ -52894,6 +52896,9 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeySe ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayerTest.mm + ../../../flutter/LICENSE @@ -52913,6 +52918,7 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlugi ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPluginTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h + ../../../flutter/LICENSE @@ -55888,6 +55894,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterHeadle FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Info.plist FILE: ../../../flutter/shell/platform/darwin/ios/framework/PrivacyInfo.xcprivacy @@ -55896,6 +55903,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/ConnectionColl FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FakeUIPressProxy.swift FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h @@ -55926,6 +55934,9 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeySeco FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManagerTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayerTest.mm @@ -55945,6 +55956,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginA FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterRestorationPluginTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h diff --git a/engine/src/flutter/engine.code-workspace b/engine/src/flutter/engine.code-workspace index 544677d98bfed..0d8f5d22f0680 100644 --- a/engine/src/flutter/engine.code-workspace +++ b/engine/src/flutter/engine.code-workspace @@ -425,6 +425,37 @@ "ios_debug_unopt" ] }, + { + "type": "shell", + "command": "./flutter/bin/et", + "options": { + "cwd": "${workspaceFolder}/.." + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "shared", + "clear": true + }, + "group": { + "kind": "build" + }, + "label": "ios_debug_sim_unopt_arm64", + "args": [ + "build", + "-c", + "host_debug_unopt_arm64", + "&&", + "./flutter/bin/et", + "build", + "-c", + "ios_debug_sim_unopt_arm64" + ] + }, { "type": "shell", "command": "./flutter/bin/et", diff --git a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn index d2297ee1ee1fe..32f7ec124a135 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn +++ b/engine/src/flutter/shell/platform/darwin/ios/BUILD.gn @@ -34,6 +34,7 @@ _flutter_framework_headers = [ "framework/Headers/FlutterPlatformViews.h", "framework/Headers/FlutterPlugin.h", "framework/Headers/FlutterPluginAppLifeCycleDelegate.h", + "framework/Headers/FlutterSceneDelegate.h", "framework/Headers/FlutterViewController.h", ] @@ -75,6 +76,7 @@ source_set("flutter_framework_source") { sources = [ "framework/Source/FlutterAppDelegate.mm", + "framework/Source/FlutterAppDelegate_Internal.h", "framework/Source/FlutterCallbackCache.mm", "framework/Source/FlutterCallbackCache_Internal.h", "framework/Source/FlutterChannelKeyResponder.h", @@ -93,6 +95,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterKeySecondaryResponder.h", "framework/Source/FlutterKeyboardManager.h", "framework/Source/FlutterKeyboardManager.mm", + "framework/Source/FlutterLaunchEngine.h", + "framework/Source/FlutterLaunchEngine.m", "framework/Source/FlutterMetalLayer.h", "framework/Source/FlutterMetalLayer.mm", "framework/Source/FlutterOverlayView.h", @@ -106,6 +110,7 @@ source_set("flutter_framework_source") { "framework/Source/FlutterPluginAppLifeCycleDelegate.mm", "framework/Source/FlutterRestorationPlugin.h", "framework/Source/FlutterRestorationPlugin.mm", + "framework/Source/FlutterSceneDelegate.m", "framework/Source/FlutterSemanticsScrollView.h", "framework/Source/FlutterSemanticsScrollView.mm", "framework/Source/FlutterSharedApplication.h", @@ -250,6 +255,7 @@ if (enable_ios_unittests) { "framework/Source/FlutterFakeKeyEvents.h", "framework/Source/FlutterFakeKeyEvents.mm", "framework/Source/FlutterKeyboardManagerTest.mm", + "framework/Source/FlutterLaunchEngineTest.mm", "framework/Source/FlutterMetalLayerTest.mm", "framework/Source/FlutterPlatformPluginTest.mm", "framework/Source/FlutterPlatformViewsTest.mm", diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h index 705dfcb028d2a..624cf09bc99ba 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h @@ -18,6 +18,7 @@ #import "FlutterPlatformViews.h" #import "FlutterPlugin.h" #import "FlutterPluginAppLifeCycleDelegate.h" +#import "FlutterSceneDelegate.h" #import "FlutterTexture.h" #import "FlutterViewController.h" diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h index 126fb00bc6a9a..fce4fd33a4a83 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h @@ -38,7 +38,8 @@ FLUTTER_DARWIN_EXPORT * * This was introduced to help users migrate code from the FlutterAppDelegate * when UISceneDelegate was adopted. Using - * FlutterViewController.pluginRegistrant should be preferred. + * FlutterViewController.pluginRegistrant should be preferred since it doesn't + * rely on the FlutterAppDelegate. */ @property(nonatomic, strong, nullable) NSObject* pluginRegistrant; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h new file mode 100644 index 0000000000000..27f768355ecd7 --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The UISceneDelegate used by Flutter by default. + * + * This class is typically specified as the UISceneDelegate in the Info.plist. + */ +@interface FlutterSceneDelegate : NSObject +@property(nonatomic, strong, nullable) UIWindow* window; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm index e15a0a059fc0f..f1845fbca63ba 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm @@ -9,6 +9,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" @@ -26,6 +27,7 @@ @interface FlutterAppDelegate () { } @property(nonatomic, copy) FlutterViewController* (^rootFlutterViewControllerGetter)(void); @property(nonatomic, strong) FlutterPluginAppLifeCycleDelegate* lifeCycleDelegate; +@property(nonatomic, strong) FlutterLaunchEngine* launchEngine; @end @implementation FlutterAppDelegate @@ -33,10 +35,15 @@ @implementation FlutterAppDelegate - (instancetype)init { if (self = [super init]) { _lifeCycleDelegate = [[FlutterPluginAppLifeCycleDelegate alloc] init]; + _launchEngine = [[FlutterLaunchEngine alloc] init]; } return self; } +- (nullable FlutterEngine*)takeLaunchEngine { + return [self.launchEngine takeEngine]; +} + - (BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions { return [self.lifeCycleDelegate application:application @@ -256,7 +263,7 @@ - (void)setPluginRegistrant:(NSObject*)pluginRegistrant if (flutterRootViewController) { return [[flutterRootViewController pluginRegistry] registrarForPlugin:pluginKey]; } - return nil; + return [self.launchEngine.engine registrarForPlugin:pluginKey]; } - (BOOL)hasPlugin:(NSString*)pluginKey { @@ -264,7 +271,7 @@ - (BOOL)hasPlugin:(NSString*)pluginKey { if (flutterRootViewController) { return [[flutterRootViewController pluginRegistry] hasPlugin:pluginKey]; } - return false; + return [self.launchEngine.engine hasPlugin:pluginKey]; } - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey { @@ -272,7 +279,7 @@ - (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey { if (flutterRootViewController) { return [[flutterRootViewController pluginRegistry] valuePublishedByPlugin:pluginKey]; } - return nil; + return [self.launchEngine.engine valuePublishedByPlugin:pluginKey]; } #pragma mark - Selectors handling diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm index 184c1c6010df6..7088b18f35bd4 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegateTest.mm @@ -8,6 +8,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Test.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h" @@ -154,6 +155,20 @@ - (void)testReleasesWindowOnDealloc { XCTAssertNil(weakWindow); } +- (void)testGrabLaunchEngine { + // Clear out the mocking of the root view controller. + [self.mockMainBundle stopMocking]; + self.appDelegate.rootFlutterViewControllerGetter = nil; + // Working with plugins forces the creation of an engine. + XCTAssertFalse([self.appDelegate hasPlugin:@"hello"]); + XCTAssertNotNil([self.appDelegate takeLaunchEngine]); + XCTAssertNil([self.appDelegate takeLaunchEngine]); +} + +- (void)testGrabLaunchEngineWithoutPlugins { + XCTAssertNil([self.appDelegate takeLaunchEngine]); +} + #pragma mark - Deep linking - (void)testUniversalLinkPushRouteInformation { diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h new file mode 100644 index 0000000000000..b90796d7514aa --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERAPPDELEGATE_INTERNAL_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERAPPDELEGATE_INTERNAL_H_ + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h" + +@interface FlutterAppDelegate () + +- (nullable FlutterEngine*)takeLaunchEngine; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERAPPDELEGATE_INTERNAL_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h new file mode 100644 index 0000000000000..5a054f4719422 --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERLAUNCHENGINE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERLAUNCHENGINE_H_ + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" + +/** + * A lazy container for an engine that will only dispense one engine. + * + * This is used to hold an engine for plugin registration when the + * GeneratedPluginRegistrant is called on a FlutterAppDelegate before the first + * FlutterViewController is set up. This is the typical flow after the + * UISceneDelegate migration. + * + * The launch engine is intended to work only with first FlutterViewController + * instantiated with a NIB since that is the only FlutterEngine that registers + * plugins through the FlutterAppDelegate. + */ +@interface FlutterLaunchEngine : NSObject + +/** + * Accessor for the launch engine. + * + * Getting this may allocate an engine. + */ +@property(nonatomic, strong, nullable, readonly) FlutterEngine* engine; + +/** + * Take ownership of the launch engine. + * + * After this is called `self.engine` and `takeEngine` will always return nil. + */ +- (nullable FlutterEngine*)takeEngine; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERLAUNCHENGINE_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m new file mode 100644 index 0000000000000..6dbb6a0b93311 --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.m @@ -0,0 +1,52 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" + +@interface FlutterLaunchEngine () { + BOOL _didTakeEngine; + FlutterEngine* _engine; +} +@end + +@implementation FlutterLaunchEngine + +- (instancetype)init { + self = [super init]; + if (self) { + self->_didTakeEngine = NO; + } + return self; +} + +- (FlutterEngine*)engine { + if (!_didTakeEngine && !_engine) { + // `allowHeadlessExecution` is set to `YES` since that has always been the + // default behavior. Technically, someone could have set it to `NO` in their + // nib and it would be ignored here. There is no documented usage of this + // though. + // `restorationEnabled` is set to `YES` since a FlutterViewController + // without restoration will have a nil restorationIdentifier leading no + // restoration data being saved. So, it is safe to turn this on in the event + // that someone does not want it. + _engine = [[FlutterEngine alloc] initWithName:@"io.flutter" + project:[[FlutterDartProject alloc] init] + allowHeadlessExecution:YES + restorationEnabled:YES]; + // Run engine with default values like initialRoute. Specifying these in + // the FlutterViewController was not supported so it's safe to use the + // defaults. + [_engine run]; + } + return _engine; +} + +- (nullable FlutterEngine*)takeEngine { + FlutterEngine* result = _engine; + _engine = nil; + _didTakeEngine = YES; + return result; +} + +@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm new file mode 100644 index 0000000000000..e3a28edac0daa --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngineTest.mm @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import +#import +#import +#import + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" + +FLUTTER_ASSERT_ARC; + +@interface FlutterLaunchEngineTest : XCTestCase +@end + +@implementation FlutterLaunchEngineTest + +- (void)testSimple { + FlutterLaunchEngine* launchEngine = [[FlutterLaunchEngine alloc] init]; + XCTAssertTrue(launchEngine.engine); + XCTAssertTrue([launchEngine takeEngine]); + XCTAssertFalse(launchEngine.engine); +} + +@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m new file mode 100644 index 0000000000000..64a1774ef46dc --- /dev/null +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterSceneDelegate.m @@ -0,0 +1,32 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterSceneDelegate.h" + +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h" + +FLUTTER_ASSERT_ARC + +@implementation FlutterSceneDelegate + +- (void)scene:(UIScene*)scene + willConnectToSession:(UISceneSession*)session + options:(UISceneConnectionOptions*)connectionOptions { + NSObject* appDelegate = FlutterSharedApplication.application.delegate; + if (appDelegate.window.rootViewController) { + NSLog(@"WARNING - The UIApplicationDelegate is setting up the UIWindow and " + @"UIWindow.rootViewController at launch. This was deprecated after the " + @"UISceneDelegate adoption. Setup logic should be moved to a UISceneDelegate."); + // If this is not nil we are running into a case where someone is manually + // performing root view controller setup in the UIApplicationDelegate. + UIWindowScene* windowScene = (UIWindowScene*)scene; + self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; + self.window.rootViewController = appDelegate.window.rootViewController; + appDelegate.window = self.window; + [self.window makeKeyAndVisible]; + } +} + +@end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 71aca23a4074e..d0b377d6419c0 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -17,11 +17,13 @@ #include "flutter/shell/common/thread_host.h" #import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h" #import "flutter/shell/platform/darwin/common/framework/Source/FlutterBinaryMessengerRelay.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterChannelKeyResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEmbedderKeyResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyPrimaryResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterLaunchEngine.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSharedApplication.h" @@ -258,15 +260,33 @@ - (instancetype)init { - (void)sharedSetupWithProject:(nullable FlutterDartProject*)project initialRoute:(nullable NSString*)initialRoute { - // Need the project to get settings for the view. Initializing it here means - // the Engine class won't initialize it later. - if (!project) { - project = [[FlutterDartProject alloc] init]; - } - FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"io.flutter" - project:project - allowHeadlessExecution:self.engineAllowHeadlessExecution - restorationEnabled:self.restorationIdentifier != nil]; + id appDelegate = FlutterSharedApplication.application.delegate; + FlutterEngine* engine; + if ([appDelegate respondsToSelector:@selector(takeLaunchEngine)]) { + if (self.nibName) { + // Only grab the launch engine if it was created with a nib. + // FlutterViewControllers created from nibs can't specify their initial + // routes so it's safe to take it. + engine = [appDelegate takeLaunchEngine]; + } else { + // If we registered plugins with a FlutterAppDelegate without a xib, throw + // away the engine that was registered through the FlutterAppDelegate. + // That's not a valid usage of the API. + [appDelegate takeLaunchEngine]; + } + } + if (!engine) { + // Need the project to get settings for the view. Initializing it here means + // the Engine class won't initialize it later. + if (!project) { + project = [[FlutterDartProject alloc] init]; + } + + engine = [[FlutterEngine alloc] initWithName:@"io.flutter" + project:project + allowHeadlessExecution:self.engineAllowHeadlessExecution + restorationEnabled:self.restorationIdentifier != nil]; + } if (!engine) { return; } @@ -275,7 +295,7 @@ - (void)sharedSetupWithProject:(nullable FlutterDartProject*)project _engine = engine; _flutterView = [[FlutterView alloc] initWithDelegate:_engine opaque:_viewOpaque - enableWideGamut:project.isWideGamutEnabled]; + enableWideGamut:engine.project.isWideGamutEnabled]; [_engine createShell:nil libraryURI:nil initialRoute:initialRoute]; _engineNeedsLaunch = YES; _ongoingTouches = [[NSMutableSet alloc] init]; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index ac92f4bddef0c..9fa890faf2084 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -13,6 +13,7 @@ #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterHourFormat.h" #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEmbedderKeyResponder.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterFakeKeyEvents.h" @@ -119,6 +120,10 @@ @interface FlutterEmbedderKeyResponder (Tests) @property(nonatomic, copy, readonly) FlutterSendKeyEvent sendEvent; @end +@interface NSObject (Tests) +@property(nonatomic, strong) FlutterEngine* mockLaunchEngine; +@end + @interface FlutterViewController (Tests) @property(nonatomic, assign) double targetViewInsetBottom; @@ -2490,4 +2495,28 @@ - (void)testAppDelegatePluginRegistrant { OCMVerify([mockRegistrant registerWithRegistry:viewController]); } +- (void)testGrabLaunchEngine { + id appDelegate = [[UIApplication sharedApplication] delegate]; + XCTAssertTrue([appDelegate respondsToSelector:@selector(setMockLaunchEngine:)]); + [appDelegate setMockLaunchEngine:self.mockEngine]; + UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"Flutter" bundle:nil]; + XCTAssertTrue(storyboard); + FlutterViewController* viewController = + (FlutterViewController*)[storyboard instantiateInitialViewController]; + XCTAssertTrue(viewController); + XCTAssertTrue([viewController isKindOfClass:[FlutterViewController class]]); + XCTAssertEqual(viewController.engine, self.mockEngine); + [appDelegate setMockLaunchEngine:nil]; +} + +- (void)testDoesntGrabLaunchEngine { + id appDelegate = [[UIApplication sharedApplication] delegate]; + XCTAssertTrue([appDelegate respondsToSelector:@selector(setMockLaunchEngine:)]); + [appDelegate setMockLaunchEngine:self.mockEngine]; + FlutterViewController* flutterViewController = [[FlutterViewController alloc] init]; + XCTAssertNotNil(flutterViewController.engine); + XCTAssertNotEqual(flutterViewController.engine, self.mockEngine); + [appDelegate setMockLaunchEngine:nil]; +} + @end diff --git a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h index 530b65ecb9a5d..fc05d29e64d89 100644 --- a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h +++ b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.h @@ -7,6 +7,7 @@ #import +@class FlutterEngine; @protocol FlutterPluginRegistrant; @interface AppDelegate : UIResponder @@ -16,6 +17,11 @@ // A mirror of the FlutterAppDelegate API for integration testing. @property(nonatomic, strong, nullable) NSObject* pluginRegistrant; +/** The FlutterEngine that will be served by `takeLaunchEngine`. */ +@property(nonatomic, strong, nullable) FlutterEngine* mockLaunchEngine; + +- (nullable FlutterEngine*)takeLaunchEngine; + @end #endif // FLUTTER_TESTING_IOS_IOSUNITTESTS_APP_APPDELEGATE_H_ diff --git a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m index 9e22f24ef0b8a..5d468d47102ca 100644 --- a/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m +++ b/engine/src/flutter/testing/ios/IosUnitTests/App/AppDelegate.m @@ -30,4 +30,9 @@ - (void)applicationDidBecomeActive:(UIApplication*)application { - (void)applicationWillTerminate:(UIApplication*)application { } +- (FlutterEngine*)takeLaunchEngine { + // This is just served up for tests and doesn't actually take ownership. + return _mockLaunchEngine; +} + @end diff --git a/engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard b/engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard new file mode 100644 index 0000000000000..a6eaed8523310 --- /dev/null +++ b/engine/src/flutter/testing/ios/IosUnitTests/App/Flutter.storyboard @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj b/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj index 1bec57693f4b1..0b593d58ad1d2 100644 --- a/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj +++ b/engine/src/flutter/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 0D1CE5D8233430F400E5D880 /* FlutterChannelsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D1CE5D7233430F400E5D880 /* FlutterChannelsTest.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + 0D48E9ED2DCE7B16005474A1 /* Flutter.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */; }; + 0D48E9EE2DCE7B16005474A1 /* Flutter.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */; }; 0D6AB6B622BB05E100EEE540 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6AB6B522BB05E100EEE540 /* AppDelegate.m */; }; 0D6AB6B922BB05E100EEE540 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D6AB6B822BB05E100EEE540 /* ViewController.m */; }; 0D6AB6BC22BB05E100EEE540 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0D6AB6BA22BB05E100EEE540 /* Main.storyboard */; }; @@ -55,6 +57,7 @@ 0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterPluginAppLifeCycleDelegateTest.mm; sourceTree = ""; }; 0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest.mm; sourceTree = ""; }; 0D1CE5D7233430F400E5D880 /* FlutterChannelsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterChannelsTest.m; sourceTree = ""; }; + 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Flutter.storyboard; sourceTree = ""; }; 0D6AB6B122BB05E100EEE540 /* IosUnitTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IosUnitTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D6AB6B422BB05E100EEE540 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 0D6AB6B522BB05E100EEE540 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -162,6 +165,7 @@ 0D6AB6BF22BB05E200EEE540 /* LaunchScreen.storyboard */, 0D6AB6C222BB05E200EEE540 /* Info.plist */, 0D6AB6C322BB05E200EEE540 /* main.m */, + 0D48E9EC2DCE7B16005474A1 /* Flutter.storyboard */, ); path = App; sourceTree = ""; @@ -270,6 +274,7 @@ 0D6AB6C122BB05E200EEE540 /* LaunchScreen.storyboard in Resources */, 0D6AB6BE22BB05E200EEE540 /* Assets.xcassets in Resources */, 0D6AB6BC22BB05E100EEE540 /* Main.storyboard in Resources */, + 0D48E9ED2DCE7B16005474A1 /* Flutter.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -277,6 +282,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0D48E9EE2DCE7B16005474A1 /* Flutter.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml b/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml index 57c837ef67753..86291b0b96502 100644 --- a/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml +++ b/engine/src/flutter/tools/vscode_workspace/engine-workspace.yaml @@ -118,6 +118,10 @@ settings: '*.ipp': cpp csetjmp: cpp cfenv: cpp + execution: cpp + print: cpp + source_location: cpp + syncstream: cpp C_Cpp.default.includePath: - ${default} - ${workspaceFolder}/.. @@ -252,6 +256,17 @@ tasks: - build - -c - ios_debug_unopt + - <<: *et-task + label: ios_debug_sim_unopt_arm64 + args: + - build + - -c + - host_debug_unopt_arm64 + - "&&" + - *et-cmd + - build + - -c + - ios_debug_sim_unopt_arm64 - <<: *et-task label: android_debug_unopt_arm64 args: diff --git a/examples/platform_channel/ios/Runner/AppDelegate.m b/examples/platform_channel/ios/Runner/AppDelegate.m index 31512fc8c7847..c4f7970665166 100644 --- a/examples/platform_channel/ios/Runner/AppDelegate.m +++ b/examples/platform_channel/ios/Runner/AppDelegate.m @@ -6,19 +6,25 @@ #import #import "GeneratedPluginRegistrant.h" +@interface AppDelegate () +@end + @implementation AppDelegate { FlutterEventSink _eventSink; } - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; - FlutterViewController* controller = - (FlutterViewController*)self.window.rootViewController; + self.pluginRegistrant = self; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} +- (void)registerWithRegistry:(NSObject*)registry { + [GeneratedPluginRegistrant registerWithRegistry:registry]; + NSObject* registrar = [registry registrarForPlugin:@"samples.flutter.io"]; FlutterMethodChannel* batteryChannel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.io/battery" - binaryMessenger:controller]; + binaryMessenger:registrar.messenger]; __weak typeof(self) weakSelf = self; [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { @@ -38,9 +44,8 @@ - (BOOL)application:(UIApplication*)application FlutterEventChannel* chargingChannel = [FlutterEventChannel eventChannelWithName:@"samples.flutter.io/charging" - binaryMessenger:controller]; + binaryMessenger:registrar.messenger]; [chargingChannel setStreamHandler:self]; - return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (int)getBatteryLevel { diff --git a/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e67b2808af02f..fc5ae0316042f 100644 --- a/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/examples/platform_channel_swift/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -45,11 +46,13 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/examples/platform_channel_swift/ios/Runner/AppDelegate.swift b/examples/platform_channel_swift/ios/Runner/AppDelegate.swift index 83b04716f9158..a7c5865f6aaaf 100644 --- a/examples/platform_channel_swift/ios/Runner/AppDelegate.swift +++ b/examples/platform_channel_swift/ios/Runner/AppDelegate.swift @@ -20,18 +20,21 @@ enum MyFlutterErrorCode { } @main -@objc class AppDelegate: FlutterAppDelegate, FlutterStreamHandler { +@objc class AppDelegate: FlutterAppDelegate, FlutterStreamHandler, FlutterPluginRegistrant { private var eventSink: FlutterEventSink? override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - GeneratedPluginRegistrant.register(with: self) - guard let controller = window?.rootViewController as? FlutterViewController else { - fatalError("rootViewController is not type FlutterViewController") - } + pluginRegistrant = self + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func register(with registry: FlutterPluginRegistry) { + GeneratedPluginRegistrant.register(with: registry) + let registrar = registry.registrar(forPlugin: "battery") let batteryChannel = FlutterMethodChannel(name: ChannelName.battery, - binaryMessenger: controller.binaryMessenger) + binaryMessenger: registrar!.messenger()) batteryChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in guard call.method == "getBatteryLevel" else { @@ -42,9 +45,8 @@ enum MyFlutterErrorCode { }) let chargingChannel = FlutterEventChannel(name: ChannelName.charging, - binaryMessenger: controller.binaryMessenger) + binaryMessenger: registrar!.messenger()) chargingChannel.setStreamHandler(self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func receiveBatteryLevel(result: FlutterResult) { diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index e4f98f203b4fe..aa7b70bdd1de8 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -42,6 +42,7 @@ import 'migrations/project_build_location_migration.dart'; import 'migrations/remove_bitcode_migration.dart'; import 'migrations/remove_framework_link_and_embedding_migration.dart'; import 'migrations/uiapplicationmain_deprecation_migration.dart'; +import 'migrations/uiscenedelegate_migration.dart'; import 'migrations/xcode_build_system_migration.dart'; import 'xcode_build_settings.dart'; import 'xcodeproj.dart'; @@ -152,6 +153,7 @@ Future buildXcodeProject({ IOSDeploymentTargetMigration(app.project, globals.logger), XcodeProjectObjectVersionMigration(app.project, globals.logger), HostAppInfoPlistMigration(app.project, globals.logger), + UISceneDelegateMigration(app.project, globals.logger), XcodeScriptBuildPhaseMigration(app.project, globals.logger), RemoveBitcodeMigration(app.project, globals.logger), XcodeThinBinaryBuildPhaseInputPathsMigration(app.project, globals.logger), diff --git a/packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart b/packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart new file mode 100644 index 0000000000000..0aa9a86934782 --- /dev/null +++ b/packages/flutter_tools/lib/src/ios/migrations/uiscenedelegate_migration.dart @@ -0,0 +1,94 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart' show visibleForTesting; +import 'package:xml/xml.dart'; + +import '../../base/file_system.dart'; +import '../../base/project_migrator.dart'; +import '../../xcode_project.dart'; + +const String _manifestKey = 'UIApplicationSceneManifest'; +const String _storyboardKey = 'UIMainStoryboardFile'; + +String _addition(String storyboard) => ''' +UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + $storyboard + + + + +'''; + +/// Update Info.plist. +class UISceneDelegateMigration extends ProjectMigrator { + UISceneDelegateMigration(IosProject project, super.logger) + : _infoPlist = project.defaultHostInfoPlist; + + final File _infoPlist; + + @override + Future migrate() async { + if (!_infoPlist.existsSync()) { + logger.printTrace('Info.plist not found, skipping host app Info.plist migration.'); + return; + } + + processFileLines(_infoPlist); + } + + @visibleForTesting + static Map extractPlistDict(XmlElement dict) { + final Map keyValues = {}; + String? key; + for (final XmlElement child in dict.childElements) { + if (key != null) { + keyValues[key] = child; + key = null; + } else { + key = child.innerText; + } + } + return keyValues; + } + + @override + String migrateFileContents(String fileContents) { + try { + final XmlDocument read = XmlDocument.parse(fileContents); + final XmlElement readPlist = read.childElements.first; + final XmlElement readDict = readPlist.childElements.first; + final Map keyValues = extractPlistDict(readDict); + + if (!keyValues.containsKey(_manifestKey)) { + if (keyValues.containsKey(_storyboardKey)) { + final String storyboard = keyValues[_storyboardKey]!.innerText; + final String xmlAddition = _addition(storyboard); + final XmlDocumentFragment fragment = XmlDocumentFragment.parse(xmlAddition); + for (final XmlNode node in fragment.children) { + readDict.children.add(node.copy()); + } + } + } + return '${read.toXmlString(pretty: true)}\n'; + } on Exception catch (_) { + return fileContents; + } + } +} diff --git a/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl b/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl index bb6ce2f4c44a4..71c25ff83afdb 100644 --- a/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl +++ b/packages/flutter_tools/templates/app/ios.tmpl/Runner/Info.plist.tmpl @@ -45,5 +45,26 @@ UIApplicationSupportsIndirectInputEvents + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + diff --git a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl index a4388efddd1b1..fdd4b92c6ea56 100644 --- a/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl +++ b/packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl @@ -45,5 +45,26 @@ UIApplicationSupportsIndirectInputEvents + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + diff --git a/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart index 1ccdae1b2270e..99992c236fa56 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart @@ -14,6 +14,7 @@ import 'package:flutter_tools/src/ios/migrations/project_build_location_migratio import 'package:flutter_tools/src/ios/migrations/remove_bitcode_migration.dart'; import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart'; import 'package:flutter_tools/src/ios/migrations/uiapplicationmain_deprecation_migration.dart'; +import 'package:flutter_tools/src/ios/migrations/uiscenedelegate_migration.dart'; import 'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/migrations/cocoapods_script_symlink.dart'; @@ -869,6 +870,59 @@ platform :ios, '13.0' expect(testLogger.statusText, isEmpty); }); + testWithoutContext('UISceneDelegate migration', () async { + const String xmlString = ''' + + + + + MyKey + MyValue + UIMainStoryboardFile + Main + + +'''; + infoPlistFile.writeAsStringSync(xmlString); + + final UISceneDelegateMigration migration = UISceneDelegateMigration(project, testLogger); + await migration.migrate(); + + expect(infoPlistFile.readAsStringSync(), ''' + + + + + MyKey + MyValue + UIMainStoryboardFile + Main + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + + + +'''); + }); + testWithoutContext('info.plist is migrated', () async { const String infoPlistFileContent = ''' From 11bf180af0bd2b03ccbec636249250dbd10384f9 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Fri, 30 May 2025 14:05:18 -0700 Subject: [PATCH 52/66] Remove legacy platforms in `.ci.yaml` with 0 usages. (#169783) --- .ci.yaml | 66 ++++++++++++-------------------------------------------- 1 file changed, 14 insertions(+), 52 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 5213230dc5157..51d0f4ac24f11 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -26,6 +26,7 @@ platform_properties: cores: "8" device_type: none ignore_flakiness: "true" + linux: properties: dependencies: >- @@ -35,6 +36,7 @@ platform_properties: os: Ubuntu cores: "8" device_type: none + # The current android emulator config names can be found here: # https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/android/avd/proto # You may use those names for the android_virtual_device version. You may find the @@ -58,6 +60,7 @@ platform_properties: cores: "8" device_type: none kvm: "1" + # linux_android_emu_unstable is intended to be how flutter-android proves the stability # of new combinations of dependencies. linux_android_emu_unstable: @@ -77,6 +80,7 @@ platform_properties: cores: "8" device_type: none kvm: "1" + linux_build_test: properties: dependencies: >- @@ -88,16 +92,6 @@ platform_properties: os: Ubuntu cores: "8" device_type: none - linux_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "open_jdk", "version": "version:21"}, - {"dependency": "curl", "version": "version:7.64.0"} - ] - os: Linux - device_type: "msm8952" linux_pixel_7pro: properties: @@ -148,6 +142,7 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_arm64: properties: contexts: >- @@ -165,6 +160,7 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_benchmark: properties: contexts: >- @@ -184,6 +180,7 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_x64: properties: contexts: >- @@ -201,6 +198,7 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_build_test: properties: contexts: >- @@ -219,27 +217,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Mac-14|Mac-15.5 - cpu: x86 - device_type: "msm8952" - mac_arm64_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Mac-14|Mac-15.5 - cpu: arm64 - device_type: "msm8952" mac_mokey: properties: @@ -252,6 +229,7 @@ platform_properties: os: Mac-14|Mac-15.5 cpu: x86 device_type: "mokey" + mac_arm64_mokey: properties: dependencies: >- @@ -263,16 +241,6 @@ platform_properties: cpu: arm64 device_type: "mokey" - mac_pixel_7pro: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Mac-14|Mac-15.5 - cpu: x86 - device_type: "Pixel 7 Pro" mac_ios: properties: contexts: >- @@ -290,6 +258,7 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_x64_ios: properties: contexts: >- @@ -308,6 +277,7 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_arm64_ios: properties: contexts: >- @@ -326,26 +296,18 @@ platform_properties: { "sdk_version": "16c5032a" } + windows: properties: os: Windows-10 device_type: none + windows_arm64: properties: - # The arch can be removed after https://github.com/flutter/flutter/issues/135722. arch: arm os: Windows cpu: arm64 - windows_android: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:36v1"}, - {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, - {"dependency": "open_jdk", "version": "version:21"} - ] - os: Windows-10 - device_type: "msm8952" + windows_mokey: properties: dependencies: >- From 291a689a100097e8d3499278fb1d4bb6d698362e Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 30 May 2025 14:14:51 -0700 Subject: [PATCH 53/66] [Impeller] document reverse-y requirement for ImageFilter.shader (#169761) Otherwise things are upside down. --- engine/src/flutter/lib/ui/painting.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/engine/src/flutter/lib/ui/painting.dart b/engine/src/flutter/lib/ui/painting.dart index 4390a0c8d75d0..29b38973652e9 100644 --- a/engine/src/flutter/lib/ui/painting.dart +++ b/engine/src/flutter/lib/ui/painting.dart @@ -4242,6 +4242,10 @@ abstract class ImageFilter { /// also be at least one sampler2D uniform, the first of which will be set by /// the engine to contain the filter input. /// + /// When Impeller uses the OpenGL(ES) backend, the y-axis direction is + /// reversed. Custom fragment shaders must invert the y-axis on + /// GLES or they will render upside-down. + /// /// For example, the following is a valid fragment shader that can be used /// with this API. Note that the uniform names are not required to have any /// particular value. @@ -4257,7 +4261,12 @@ abstract class ImageFilter { /// out vec4 frag_color; /// /// void main() { - /// frag_color = texture(u_texture_input, FlutterFragCoord().xy / u_size) * u_time; + /// vec2 uv = FlutterFragCoord().xy / u_size; + /// // Reverse y axis for OpenGL backend. + /// #ifdef IMPELLER_TARGET_OPENGLES + /// uv.y = 1.0 - uv.y + /// #endif + /// frag_color = texture(u_texture_input, uv) * u_time; /// /// } /// From 19460811e2df38cb6b32a312af09e5792e49d624 Mon Sep 17 00:00:00 2001 From: "John \"codefu\" McDole" Date: Fri, 30 May 2025 14:39:02 -0700 Subject: [PATCH 54/66] feat: experimental tool tests workflow (attempt 2) (#169768) - remote repo: set upstream and get tags (flutter tool reqs) - pull request to flutter: checkout the PR, not the merge commit - local runs: update utils.dart to safely call terminal width Now `act -W .github/workflows/tool-test-general.yml` works locally on the command line. Future improvements: - Offer another way to set the "version" rather than tags; this causes a longer checkout time. - Multi-proc the tests and use as many cores as possible? - Solve for packages downloading? 3.5 minutes isn't terrible. --- .github/workflows/tool-test-general.yml | 93 +++++++++++++++++++++++++ dev/bots/utils.dart | 14 +++- 2 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/tool-test-general.yml diff --git a/.github/workflows/tool-test-general.yml b/.github/workflows/tool-test-general.yml new file mode 100644 index 0000000000000..898061327b0ff --- /dev/null +++ b/.github/workflows/tool-test-general.yml @@ -0,0 +1,93 @@ +name: Tool tests general - experiment + +on: + pull_request: + branches: [master] + paths: + - '.github/workflows/tool-test-general.yml' + - 'dev/**' + - 'packages/flutter_tools/**' + - 'bin/**' + - '.ci.yaml' + - 'engine/**' + - 'DEPS' + push: + branches: [master] + +jobs: + Linux_tool-tests-general: + permissions: + contents: read + + runs-on: ubuntu-latest + + steps: + # Real checkout on github actions for pull requests + - name: Checkout code (non-act pull_request) + uses: actions/checkout@v4 + if: github.event_name == 'pull_request' && !env.ACT + with: + fetch-depth: 0 + fetch-tags: true + # Checkout the PR; not the merge commit - we need to describe tags + ref: ${{ github.event.pull_request.head.sha }} + + # Real checkout on github actions for post submit + - name: Checkout code (non-act push) + uses: actions/checkout@v4 + if: github.event_name == 'push' && !env.ACT + with: + fetch-depth: 0 + fetch-tags: true + # Checkout the PR; not the merge commit - we need to describe tags + ref: ${{ github.event.pull_request.head.sha }} + + # Fake checkout if running locally + - name: Checkout code (act local) + uses: actions/checkout@v4 + if: env.ACT + + # If this is a branch / pr NOT on fluter/flutter, set the remote upstream + # so the flutter tool can figure out the version + - name: Set upstream (if not flutter/flutter) + if: github.repository != 'flutter/flutter' && !env.ACT + run: | + git remote add upstream https://github.com/flutter/flutter.git + git fetch --all --tags + + # If running locally; install the JDK - Github runners have everything on them + - name: Set up our JDK environment + if: env.ACT + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 + with: + java-version: '21' + distribution: 'temurin' + + # If running locally; install Android SDK tools - Github runners have everything on them + - name: Setup Android SDK + if: env.ACT + uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 + with: + cmdline-tools-version: 13114758 + + # If running locally; install Android SDK - Github runners have everything on them + - name: install android + if: env.ACT + run: | + sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0" + + - name: Add `flutter` to the PATH + run: | + echo "$PWD/bin" >> "$GITHUB_PATH" + + - name: Flutter Doctor + run: | + flutter doctor + + - name: update-packages + run: | + flutter update-packages + + - name: Tool Test + run: | + SHARD=tool_tests SUBSHARD=general dart --enable-asserts dev/bots/test.dart diff --git a/dev/bots/utils.dart b/dev/bots/utils.dart index 45033ca39886e..75d66f70344dd 100644 --- a/dev/bots/utils.dart +++ b/dev/bots/utils.dart @@ -107,9 +107,17 @@ const int kCSIIntermediateRangeEnd = 0x2F; const int kCSIFinalRangeStart = 0x40; const int kCSIFinalRangeEnd = 0x7E; +int get terminalColumns { + try { + return stdout.terminalColumns; + } catch (e) { + return 40; + } +} + String get redLine { if (hasColor) { - return '$red${'━' * stdout.terminalColumns}$reset'; + return '$red${'━' * terminalColumns}$reset'; } return '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'; } @@ -168,7 +176,7 @@ void foundError(List messages) { assert(messages.isNotEmpty); // Make the error message easy to notice in the logs by // wrapping it in a red box. - final int width = math.max(15, (hasColor ? stdout.terminalColumns : 80) - 1); + final int width = math.max(15, (hasColor ? terminalColumns : 80) - 1); final String title = 'ERROR #${_errorMessages.length + 1}'; print('$red╔═╡$bold$title$reset$red╞═${"═" * (width - 4 - title.length)}'); for (final String message in messages.expand((String line) => line.split('\n'))) { @@ -258,7 +266,7 @@ void _printQuietly(Object? message) { final int start = line.lastIndexOf(_lineBreak) + 1; int index = start; int length = 0; - while (index < line.length && length < stdout.terminalColumns) { + while (index < line.length && length < terminalColumns) { if (line.codeUnitAt(index) == kESC) { // 0x1B index += 1; From 6dd881448953448e000cd42ff795114a6e8c5f60 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 30 May 2025 14:52:42 -0700 Subject: [PATCH 55/66] [Impeller] disable vivante from using impeller gles/vulkan. (#169760) Fixes https://github.com/flutter/flutter/issues/167850 --- .../backend/gles/capabilities_gles.cc | 25 +------------------ .../shell/platform/android/flutter_main.cc | 19 +++++++++++++- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc index c824a16be8504..0aa7cefde5ab8 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/capabilities_gles.cc @@ -7,31 +7,8 @@ #include "impeller/core/formats.h" #include "impeller/renderer/backend/gles/proc_table_gles.h" -#ifdef FML_OS_ANDROID -#include -#endif // FML_OS_ANDROID - namespace impeller { -namespace { -// Workaround for crashes in Vivante GL driver on Android. -// -// See: -// * https://github.com/flutter/flutter/issues/167850 -// * http://crbug.com/141785 -#ifdef FML_OS_ANDROID -bool IsVivante() { - char product_model[PROP_VALUE_MAX]; - __system_property_get("ro.hardware.egl", product_model); - return strcmp(product_model, "VIVANTE") == 0; -} -#else -bool IsVivante() { - return false; -} -#endif // FML_OS_ANDROID -} // namespace - // https://registry.khronos.org/OpenGL/extensions/EXT/EXT_shader_framebuffer_fetch.txt static const constexpr char* kFramebufferFetchExt = "GL_EXT_shader_framebuffer_fetch"; @@ -147,7 +124,7 @@ CapabilitiesGLES::CapabilitiesGLES(const ProcTableGLES& gl) { supports_decal_sampler_address_mode_ = true; } - if (desc->HasExtension(kMultisampledRenderToTextureExt) && !IsVivante()) { + if (desc->HasExtension(kMultisampledRenderToTextureExt)) { supports_implicit_msaa_ = true; if (desc->HasExtension(kMultisampledRenderToTexture2Ext)) { diff --git a/engine/src/flutter/shell/platform/android/flutter_main.cc b/engine/src/flutter/shell/platform/android/flutter_main.cc index 4e56c418372a4..96e9d78cc973a 100644 --- a/engine/src/flutter/shell/platform/android/flutter_main.cc +++ b/engine/src/flutter/shell/platform/android/flutter_main.cc @@ -45,6 +45,23 @@ namespace { fml::jni::ScopedJavaGlobalRef* g_flutter_jni_class = nullptr; +// Workaround for crashes in Vivante GL driver on Android. +// +// See: +// * https://github.com/flutter/flutter/issues/167850 +// * http://crbug.com/141785 +#ifdef FML_OS_ANDROID +bool IsVivante() { + char product_model[PROP_VALUE_MAX]; + __system_property_get("ro.hardware.egl", product_model); + return strcmp(product_model, "VIVANTE") == 0; +} +#else +bool IsVivante() { + return false; +} +#endif // FML_OS_ANDROID + } // anonymous namespace FlutterMain::FlutterMain(const flutter::Settings& settings, @@ -274,7 +291,7 @@ AndroidRenderingAPI FlutterMain::SelectedRenderingAPI( #endif if (settings.enable_impeller && - api_level >= kMinimumAndroidApiLevelForImpeller) { + api_level >= kMinimumAndroidApiLevelForImpeller && !IsVivante()) { return AndroidRenderingAPI::kImpellerAutoselect; } From 3c28bb7a2437dea488ecdeb42ce2ed0e864a0aab Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 30 May 2025 14:57:30 -0700 Subject: [PATCH 56/66] Removes elevation and thickness from semantics r2 (#169382) same as https://github.com/flutter/flutter/pull/168703, but previous pr seems bugged github ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../src/flutter/lib/ui/fixtures/ui_test.dart | 4 - engine/src/flutter/lib/ui/semantics.dart | 18 -- .../flutter/lib/ui/semantics/semantics_node.h | 2 - .../ui/semantics/semantics_update_builder.cc | 4 - .../ui/semantics/semantics_update_builder.h | 2 - .../src/flutter/lib/web_ui/lib/semantics.dart | 4 - .../lib/src/engine/semantics/semantics.dart | 8 - .../test/engine/semantics/semantics_test.dart | 4 - .../engine/semantics/semantics_tester.dart | 4 - .../platform/common/accessibility_bridge.cc | 2 - .../platform/common/accessibility_bridge.h | 2 - .../embedder/embedder_semantics_update.cc | 8 +- .../platform/embedder/fixtures/main.dart | 12 - .../fuchsia/flutter/accessibility_bridge.cc | 2 - .../shell/platform/windows/fixtures/main.dart | 2 - .../lib/src/locale_initialization.dart | 4 - .../flutter/lib/src/rendering/object.dart | 59 ++-- .../flutter/lib/src/rendering/proxy_box.dart | 6 - .../flutter/lib/src/semantics/semantics.dart | 165 ---------- .../material/bottom_navigation_bar_test.dart | 46 ++- .../test/material/bottom_sheet_test.dart | 24 +- packages/flutter/test/material/card_test.dart | 29 +- .../semantics/semantics_elevation_test.dart | 284 ------------------ .../test/semantics/semantics_test.dart | 4 - .../test/semantics/semantics_update_test.dart | 2 - .../test/widgets/semantics_tester.dart | 37 --- .../slivers_appbar_floating_pinned_test.dart | 2 - packages/flutter_test/lib/src/matchers.dart | 20 -- packages/flutter_test/test/matchers_test.dart | 12 - 29 files changed, 58 insertions(+), 714 deletions(-) delete mode 100644 packages/flutter/test/semantics/semantics_elevation_test.dart diff --git a/engine/src/flutter/lib/ui/fixtures/ui_test.dart b/engine/src/flutter/lib/ui/fixtures/ui_test.dart index fc920d608e7b0..0b3273db91d09 100644 --- a/engine/src/flutter/lib/ui/fixtures/ui_test.dart +++ b/engine/src/flutter/lib/ui/fixtures/ui_test.dart @@ -213,8 +213,6 @@ void sendSemanticsUpdate() { scrollExtentMax: 0, scrollExtentMin: 0, rect: Rect.fromLTRB(0, 0, 10, 10), - elevation: 0, - thickness: 0, identifier: identifier, label: label, labelAttributes: labelAttributes, @@ -267,8 +265,6 @@ void sendSemanticsUpdateWithRole() { scrollExtentMax: 0, scrollExtentMin: 0, rect: Rect.fromLTRB(0, 0, 10, 10), - elevation: 0, - thickness: 0, identifier: "identifier", label: "label", labelAttributes: const [], diff --git a/engine/src/flutter/lib/ui/semantics.dart b/engine/src/flutter/lib/ui/semantics.dart index eeb6d9037721f..e137003903319 100644 --- a/engine/src/flutter/lib/ui/semantics.dart +++ b/engine/src/flutter/lib/ui/semantics.dart @@ -1633,14 +1633,6 @@ abstract class SemanticsUpdateBuilder { /// The `transform` is a matrix that maps this node's coordinate system into /// its parent's coordinate system. /// - /// The `elevation` describes the distance in z-direction between this node - /// and the `elevation` of the parent. - /// - /// The `thickness` describes how much space this node occupies in the - /// z-direction starting at `elevation`. Basically, in the z-direction the - /// node starts at `elevation` above the parent and ends at `elevation` + - /// `thickness` above the parent. - /// /// The `headingLevel` describes that this node is a heading and the hierarchy /// level this node represents as a heading. A value of 0 indicates that this /// node is not a heading. A value of 1 or greater indicates that this node is @@ -1680,8 +1672,6 @@ abstract class SemanticsUpdateBuilder { required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, @@ -1759,8 +1749,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, @@ -1809,8 +1797,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 rect.top, rect.right, rect.bottom, - elevation, - thickness, identifier, label, labelAttributes, @@ -1857,8 +1843,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 Double, Double, Double, - Double, - Double, Handle, Handle, Handle, @@ -1902,8 +1886,6 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 double top, double right, double bottom, - double elevation, - double thickness, String? identifier, String label, List labelAttributes, diff --git a/engine/src/flutter/lib/ui/semantics/semantics_node.h b/engine/src/flutter/lib/ui/semantics/semantics_node.h index f1f410cbb0c97..b4454eafbd749 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_node.h +++ b/engine/src/flutter/lib/ui/semantics/semantics_node.h @@ -170,8 +170,6 @@ struct SemanticsNode { double scrollPosition = std::nan(""); double scrollExtentMax = std::nan(""); double scrollExtentMin = std::nan(""); - double elevation = 0.0; - double thickness = 0.0; std::string identifier; std::string label; StringAttributes labelAttributes; diff --git a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc index f7bb621ed2175..8e4ba6884f8fc 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc +++ b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.cc @@ -74,8 +74,6 @@ void SemanticsUpdateBuilder::updateNode( double top, double right, double bottom, - double elevation, - double thickness, std::string identifier, std::string label, const std::vector& labelAttributes, @@ -118,8 +116,6 @@ void SemanticsUpdateBuilder::updateNode( node.scrollExtentMin = scrollExtentMin; node.rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), SafeNarrow(bottom)); - node.elevation = elevation; - node.thickness = thickness; node.identifier = std::move(identifier); node.label = std::move(label); pushStringAttributes(node.labelAttributes, labelAttributes); diff --git a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h index 88139bcdcde3c..bbb3c3fb3c4a5 100644 --- a/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h +++ b/engine/src/flutter/lib/ui/semantics/semantics_update_builder.h @@ -47,8 +47,6 @@ class SemanticsUpdateBuilder double top, double right, double bottom, - double elevation, - double thickness, std::string identifier, std::string label, const std::vector& labelAttributes, diff --git a/engine/src/flutter/lib/web_ui/lib/semantics.dart b/engine/src/flutter/lib/web_ui/lib/semantics.dart index 26ca9e708506c..7a8474574592c 100644 --- a/engine/src/flutter/lib/web_ui/lib/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/semantics.dart @@ -683,8 +683,6 @@ class SemanticsUpdateBuilder { required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, @@ -742,8 +740,6 @@ class SemanticsUpdateBuilder { tooltip: tooltip, textDirection: textDirection, transform: engine.toMatrix32(transform), - elevation: elevation, - thickness: thickness, childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart index 825c96f8aa942..d571e631c888d 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -237,8 +237,6 @@ class SemanticsNodeUpdate { this.tooltip, this.textDirection, required this.transform, - required this.elevation, - required this.thickness, required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, @@ -343,12 +341,6 @@ class SemanticsNodeUpdate { /// See [ui.SemanticsUpdateBuilder.updateNode]. final Int32List additionalActions; - /// See [ui.SemanticsUpdateBuilder.updateNode]. - final double elevation; - - /// See [ui.SemanticsUpdateBuilder.updateNode]. - final double thickness; - /// See [ui.SemanticsUpdateBuilder.updateNode]. final int headingLevel; diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart index fe7099c0f452f..a6671c15d4a10 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -4996,8 +4996,6 @@ void updateNode( double scrollPosition = 0.0, double scrollExtentMax = 0.0, double scrollExtentMin = 0.0, - double elevation = 0.0, - double thickness = 0.0, ui.Rect rect = ui.Rect.zero, String identifier = '', String label = '', @@ -5041,8 +5039,6 @@ void updateNode( scrollPosition: scrollPosition, scrollExtentMax: scrollExtentMax, scrollExtentMin: scrollExtentMin, - elevation: elevation, - thickness: thickness, rect: rect, identifier: identifier, label: label, diff --git a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart index 24e742249b78d..266dce45845db 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_tester.dart @@ -98,8 +98,6 @@ class SemanticsTester { double? scrollPosition, double? scrollExtentMax, double? scrollExtentMin, - double? elevation, - double? thickness, ui.Rect? rect, String? identifier, String? label, @@ -336,8 +334,6 @@ class SemanticsTester { decreasedValueAttributes: decreasedValueAttributes ?? const [], tooltip: tooltip ?? '', transform: transform != null ? toMatrix32(transform) : Matrix4.identity().storage, - elevation: elevation ?? 0, - thickness: thickness ?? 0, childrenInTraversalOrder: childIds, childrenInHitTestOrder: childIds, additionalActions: additionalActions ?? Int32List(0), diff --git a/engine/src/flutter/shell/platform/common/accessibility_bridge.cc b/engine/src/flutter/shell/platform/common/accessibility_bridge.cc index 1913a580c509e..b471da88178e0 100644 --- a/engine/src/flutter/shell/platform/common/accessibility_bridge.cc +++ b/engine/src/flutter/shell/platform/common/accessibility_bridge.cc @@ -596,8 +596,6 @@ AccessibilityBridge::FromFlutterSemanticsNode( result.scroll_position = flutter_node.scroll_position; result.scroll_extent_max = flutter_node.scroll_extent_max; result.scroll_extent_min = flutter_node.scroll_extent_min; - result.elevation = flutter_node.elevation; - result.thickness = flutter_node.thickness; if (flutter_node.label) { result.label = std::string(flutter_node.label); } diff --git a/engine/src/flutter/shell/platform/common/accessibility_bridge.h b/engine/src/flutter/shell/platform/common/accessibility_bridge.h index 8126c1ce7b65a..6b6f575837927 100644 --- a/engine/src/flutter/shell/platform/common/accessibility_bridge.h +++ b/engine/src/flutter/shell/platform/common/accessibility_bridge.h @@ -170,8 +170,6 @@ class AccessibilityBridge double scroll_position; double scroll_extent_max; double scroll_extent_min; - double elevation; - double thickness; std::string label; std::string hint; std::string value; diff --git a/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc b/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc index 76f4d32680eaa..6376d49eedb62 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_semantics_update.cc @@ -150,8 +150,8 @@ void EmbedderSemanticsUpdate::AddNode(const SemanticsNode& node) { node.scrollPosition, node.scrollExtentMax, node.scrollExtentMin, - node.elevation, - node.thickness, + 0.0, + 0.0, node.label.c_str(), node.hint.c_str(), node.value.c_str(), @@ -251,8 +251,8 @@ void EmbedderSemanticsUpdate2::AddNode(const SemanticsNode& node) { node.scrollPosition, node.scrollExtentMax, node.scrollExtentMin, - node.elevation, - node.thickness, + 0.0, + 0.0, node.label.c_str(), node.hint.c_str(), node.value.c_str(), diff --git a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart index c83292dc23d60..027923df8e599 100644 --- a/engine/src/flutter/shell/platform/embedder/fixtures/main.dart +++ b/engine/src/flutter/shell/platform/embedder/fixtures/main.dart @@ -185,8 +185,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -220,8 +218,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -259,8 +255,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -295,8 +289,6 @@ Future a11y_main() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -368,8 +360,6 @@ Future a11y_string_attributes() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: "It's a number", hintAttributes: [ LocaleStringAttribute( @@ -1683,8 +1673,6 @@ Future a11y_main_multi_view() async { scrollPosition: 0.0, scrollExtentMax: 0.0, scrollExtentMin: 0.0, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc index e7c9ecf825a06..e67ce3264e211 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/accessibility_bridge.cc @@ -279,10 +279,8 @@ fuchsia::ui::gfx::BoundingBox AccessibilityBridge::GetNodeLocation( fuchsia::ui::gfx::BoundingBox box; box.min.x = node.rect.fLeft; box.min.y = node.rect.fTop; - box.min.z = static_cast(node.elevation); box.max.x = node.rect.fRight; box.max.y = node.rect.fBottom; - box.max.z = static_cast(node.thickness); return box; } diff --git a/engine/src/flutter/shell/platform/windows/fixtures/main.dart b/engine/src/flutter/shell/platform/windows/fixtures/main.dart index a9d341cee0539..b811fab5b03b8 100644 --- a/engine/src/flutter/shell/platform/windows/fixtures/main.dart +++ b/engine/src/flutter/shell/platform/windows/fixtures/main.dart @@ -446,8 +446,6 @@ Future sendSemanticsTreeInfo() async { scrollExtentMax: 0, scrollExtentMin: 0, rect: const ui.Rect.fromLTRB(0, 0, 10, 10), - elevation: 0, - thickness: 0, identifier: 'identifier', label: 'label', labelAttributes: const [], diff --git a/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart b/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart index c482f49d32c3d..bbee88f0c8cd7 100644 --- a/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart +++ b/engine/src/flutter/testing/ios_scenario_app/lib/src/locale_initialization.dart @@ -61,8 +61,6 @@ class LocaleInitialization extends Scenario { scrollExtentMax: 0.0, scrollExtentMin: 0.0, transform: Matrix4.identity().storage, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', @@ -123,8 +121,6 @@ class LocaleInitialization extends Scenario { scrollExtentMax: 0.0, scrollExtentMin: 0.0, transform: Matrix4.identity().storage, - elevation: 0.0, - thickness: 0.0, hint: '', hintAttributes: [], value: '', diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 9e560d4532ff8..63abf78de6124 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -4872,19 +4872,19 @@ typedef _MergeUpAndSiblingMergeGroups = /// Merge all fragments from [mergeUp] and decide which [_RenderObjectSemantics] /// should form a node, i.e. [shouldFormSemanticsNode] is true. Stores the /// [_RenderObjectSemantics] that should form a node with elevation adjustments -/// into [_childrenAndElevationAdjustments]. +/// into [_children]. /// -/// At this point, walking the [_childrenAndElevationAdjustments] forms a tree +/// At this point, walking the [_children] forms a tree /// that exactly resemble the resulting semantics node tree. /// /// ### Phase 3 /// -/// Walks the [_childrenAndElevationAdjustments] and calculate their +/// Walks the [_children] and calculate their /// [_SemanticsGeometry] based on renderObject relationship. /// /// ### Phase 4 /// -/// Walks the [_childrenAndElevationAdjustments] and produce semantics node for +/// Walks the [_children] and produce semantics node for /// each [_RenderObjectSemantics] plus the sibling nodes. /// /// Phase 2, 3, 4 each depends on previous step to finished updating the the @@ -4899,7 +4899,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM bool _hasSiblingConflict = false; bool? _blocksPreviousSibling; - double elevationAdjustment = 0.0; + // TODO(chunhtai): Figure out what to do when incomplete fragments are asked // to form a semantics node. // @@ -4936,10 +4936,9 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Fragments that will merge up to parent rendering object semantics. final List<_SemanticsFragment> mergeUp = <_SemanticsFragment>[]; - /// A map that record immediate child [_RenderObjectSemantics]s that will form - /// semantics nodes with their elevation adjustments. - final Map<_RenderObjectSemantics, double> _childrenAndElevationAdjustments = - <_RenderObjectSemantics, double>{}; + /// A list to store immediate child [_RenderObjectSemantics]s that will form + /// semantics nodes. + final List<_RenderObjectSemantics> _children = <_RenderObjectSemantics>[]; /// Merge groups that will form additional sibling nodes. final List> siblingMergeGroups = >[]; @@ -5056,7 +5055,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Updates the [parentData] for the [_RenderObjectSemantics]s in the /// rendering subtree and forms a [_RenderObjectSemantics] tree where children - /// are stored in [_childrenAndElevationAdjustments]. + /// are stored in [_children]. /// /// This method does the the phase 1 and 2 of the four phases documented on /// [_RenderObjectSemantics]. @@ -5072,7 +5071,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Merge all fragments from [mergeUp] and decide which [_RenderObjectSemantics] /// should form a node. i.e. [shouldFormSemanticsNode] is true. Stores the /// [_RenderObjectSemantics] that should form a node with elevation adjustments - /// into [_childrenAndElevationAdjustments]. + /// into [_children]. void updateChildren() { assert(parentData != null || isRoot, 'parent data can only be null for root rendering object'); configProvider.reset(); @@ -5106,7 +5105,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM siblingMergeGroups.addAll(result.$2); // Construct tree for nodes that will form semantics nodes. - _childrenAndElevationAdjustments.clear(); + _children.clear(); if (contributesToSemanticsTree) { _marksConflictsInMergeGroup(mergeUp, isMergeUp: true); siblingMergeGroups.forEach(_marksConflictsInMergeGroup); @@ -5126,16 +5125,9 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM in result.$1.whereType<_RenderObjectSemantics>()) { assert(childSemantics.contributesToSemanticsTree); if (childSemantics.shouldFormSemanticsNode) { - _childrenAndElevationAdjustments[childSemantics] = 0.0; + _children.add(childSemantics); } else { - final Map<_RenderObjectSemantics, double> passUpChildren = - childSemantics._childrenAndElevationAdjustments; - for (final _RenderObjectSemantics passUpChild in passUpChildren.keys) { - final double passUpElevationAdjustment = - passUpChildren[passUpChild]! + childSemantics.configProvider.original.elevation; - _childrenAndElevationAdjustments[passUpChild] = passUpElevationAdjustment; - passUpChild.elevationAdjustment = passUpElevationAdjustment; - } + _children.addAll(childSemantics._children); siblingMergeGroups.addAll(childSemantics.siblingMergeGroups); } } @@ -5315,7 +5307,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM } /// Updates the [geometry] for this [_RenderObjectSemantics]s and its subtree - /// in [_childrenAndElevationAdjustments]. + /// in [_children]. /// /// This method does the the phase 3 of the four phases documented on /// [_RenderObjectSemantics]. @@ -5336,7 +5328,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM void _updateChildGeometry() { assert(geometry != null); - for (final _RenderObjectSemantics child in _childrenAndElevationAdjustments.keys) { + for (final _RenderObjectSemantics child in _children) { final _SemanticsGeometry childGeometry = _SemanticsGeometry.computeChildGeometry( parentPaintClipRect: geometry!.paintClipRect, parentSemanticsClipRect: geometry!.semanticsClipRect, @@ -5385,7 +5377,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM // update for semantics nodes generated in this render object semantics. // // Therefore, we only need to update the subtree. - _buildSemanticsSubtree(usedSemanticsIds: {}, elevationAdjustment: 0.0); + _buildSemanticsSubtree(usedSemanticsIds: {}); } } @@ -5435,11 +5427,10 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Builds the semantics subtree under the [cachedSemanticsNode]. void _buildSemanticsSubtree({ required Set usedSemanticsIds, - required double elevationAdjustment, List? semanticsNodes, }) { final List children = []; - for (final _RenderObjectSemantics child in _childrenAndElevationAdjustments.keys) { + for (final _RenderObjectSemantics child in _children) { assert(child.shouldFormSemanticsNode); // Cached semantics node may be part of sibling merging group prior // to this update. In this case, the semantics node may continue to @@ -5474,11 +5465,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM _updateSemanticsNodeGeometry(); _mergeSiblingGroup(usedSemanticsIds); - _buildSemanticsSubtree( - semanticsNodes: semanticsNodes, - usedSemanticsIds: usedSemanticsIds, - elevationAdjustment: elevationAdjustment, - ); + _buildSemanticsSubtree(semanticsNodes: semanticsNodes, usedSemanticsIds: usedSemanticsIds); } SemanticsNode _createSemanticsNode() { @@ -5556,12 +5543,6 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM void _updateSemanticsNodeGeometry() { final SemanticsNode node = cachedSemanticsNode!; final _SemanticsGeometry nodeGeometry = geometry!; - node.elevationAdjustment = elevationAdjustment; - if (elevationAdjustment != 0.0) { - configProvider.updateConfig((SemanticsConfiguration config) { - config.elevation = configProvider.original.elevation + elevationAdjustment; - }); - } final bool isSemanticsHidden = configProvider.original.isHidden || (!(parentData?.mergeIntoParent ?? false) && nodeGeometry.hidden); @@ -5661,7 +5642,6 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM node._semantics.geometry = null; node._semantics.parentData = null; node._semantics._blocksPreviousSibling = null; - node._semantics.elevationAdjustment = 0.0; // Since this node is a semantics boundary, the produced sibling nodes will // be attached to the parent semantics boundary. Thus, these sibling nodes // will not be carried to the next loop. @@ -5737,7 +5717,6 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM /// Removes any cache stored in this object as if it is newly created. void clear() { built = false; - elevationAdjustment = 0.0; cachedSemanticsNode = null; parentData = null; geometry = null; @@ -5745,7 +5724,7 @@ class _RenderObjectSemantics extends _SemanticsFragment with DiagnosticableTreeM _containsIncompleteFragment = false; mergeUp.clear(); siblingMergeGroups.clear(); - _childrenAndElevationAdjustments.clear(); + _children.clear(); semanticsNodes.clear(); configProvider.clear(); } diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 9e927b9df3e27..a16bdad8113e9 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -2048,12 +2048,6 @@ abstract class _RenderPhysicalModelBase extends _RenderCustomClip { markNeedsPaint(); } - @override - void describeSemanticsConfiguration(SemanticsConfiguration config) { - super.describeSemanticsConfiguration(config); - config.elevation = elevation; - } - @override void debugFillProperties(DiagnosticPropertiesBuilder description) { super.debugFillProperties(description); diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index 7c36ae164991f..3c62c1c2157e7 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -724,8 +724,6 @@ class SemanticsData with Diagnosticable { required this.tooltip, required this.textDirection, required this.rect, - required this.elevation, - required this.thickness, required this.textSelection, required this.scrollIndex, required this.scrollChildCount, @@ -980,21 +978,6 @@ class SemanticsData with Diagnosticable { /// parent). final Matrix4? transform; - /// The elevation of this node relative to the parent semantics node. - /// - /// See also: - /// - /// * [SemanticsConfiguration.elevation] for a detailed discussion regarding - /// elevation and semantics. - final double elevation; - - /// The extent of this node along the z-axis beyond its [elevation] - /// - /// See also: - /// - /// * [SemanticsConfiguration.thickness] for a more detailed definition. - final double thickness; - /// The identifiers for the custom semantics actions and standard action /// overrides for this node. /// @@ -1037,8 +1020,6 @@ class SemanticsData with Diagnosticable { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('rect', rect, showName: false)); properties.add(TransformProperty('transform', transform, showName: false, defaultValue: null)); - properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0)); - properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0)); final List actionSummary = [ for (final SemanticsAction action in SemanticsAction.values) if ((actions & action.index) != 0) action.name, @@ -1119,8 +1100,6 @@ class SemanticsData with Diagnosticable { other.maxValueLength == maxValueLength && other.currentValueLength == currentValueLength && other.transform == transform && - other.elevation == elevation && - other.thickness == thickness && other.headingLevel == headingLevel && other.linkUrl == linkUrl && other.role == role && @@ -1155,8 +1134,6 @@ class SemanticsData with Diagnosticable { maxValueLength, currentValueLength, transform, - elevation, - thickness, headingLevel, linkUrl, customSemanticsActionIds == null ? null : Object.hashAll(customSemanticsActionIds!), @@ -2373,27 +2350,6 @@ class SemanticsNode with DiagnosticableTreeMixin { /// If this rect is null [parentSemanticsClipRect] also has to be null. Rect? parentPaintClipRect; - /// The elevation adjustment that the parent imposes on this node. - /// - /// The [elevation] property is relative to the elevation of the parent - /// [SemanticsNode]. However, as [SemanticsConfiguration]s from various - /// ascending [RenderObject]s are merged into each other to form that - /// [SemanticsNode] the parent’s elevation may change. This requires an - /// adjustment of the child’s relative elevation which is represented by this - /// value. - /// - /// The value is rarely accessed directly. Instead, for most use cases the - /// [elevation] value should be used, which includes this adjustment. - /// - /// See also: - /// - /// * [elevation], the actual elevation of this [SemanticsNode]. - @Deprecated( - 'This was a cache for internal calculations and is no longer needed. ' - 'This feature was deprecated after v3.29.0-0.0.pre.', - ) - double? elevationAdjustment; - /// The index of this node within the parent's list of semantic children. /// /// This includes all semantic nodes, not just those currently in the @@ -2802,8 +2758,6 @@ class SemanticsNode with DiagnosticableTreeMixin { bool _isDifferentFromCurrentSemanticAnnotation(SemanticsConfiguration config) { return _attributedLabel != config.attributedLabel || _attributedHint != config.attributedHint || - _elevation != config.elevation || - _thickness != config.thickness || _attributedValue != config.attributedValue || _attributedIncreasedValue != config.attributedIncreasedValue || _attributedDecreasedValue != config.attributedDecreasedValue || @@ -2964,75 +2918,6 @@ class SemanticsNode with DiagnosticableTreeMixin { String get tooltip => _tooltip; String _tooltip = _kEmptyConfig.tooltip; - /// The elevation along the z-axis at which the [rect] of this [SemanticsNode] - /// is located above its parent. - /// - /// The value is relative to the parent's [elevation]. The sum of the - /// [elevation]s of all ancestor node plus this value determines the absolute - /// elevation of this [SemanticsNode]. - /// - /// See also: - /// - /// * [thickness], which describes how much space in z-direction this - /// [SemanticsNode] occupies starting at this [elevation]. - /// * [elevationAdjustment], which has been used to calculate this value. - @Deprecated( - 'This was a feature added for 3D rendering, but the feature was deprecated. ' - 'This feature was deprecated after v3.29.0-0.0.pre.', - ) - double get elevation => _elevation; - double _elevation = _kEmptyConfig.elevation; - - /// Describes how much space the [SemanticsNode] takes up along the z-axis. - /// - /// A [SemanticsNode] represents multiple [RenderObject]s, which can be - /// located at various elevations in 3D. The [thickness] is the difference - /// between the absolute elevations of the lowest and highest [RenderObject] - /// represented by this [SemanticsNode]. In other words, the thickness - /// describes how high the box is that this [SemanticsNode] occupies in three - /// dimensional space. The two other dimensions are defined by [rect]. - /// - /// {@tool snippet} - /// The following code stacks three [PhysicalModel]s on top of each other - /// separated by non-zero elevations. - /// - /// [PhysicalModel] C is elevated 10.0 above [PhysicalModel] B, which in turn - /// is elevated 5.0 above [PhysicalModel] A. The side view of this - /// constellation looks as follows: - /// - /// ![A diagram illustrating the elevations of three PhysicalModels and their - /// corresponding SemanticsNodes.](https://flutter.github.io/assets-for-api-docs/assets/semantics/SemanticsNode.thickness.png) - /// - /// In this example the [RenderObject]s for [PhysicalModel] C and B share one - /// [SemanticsNode] Y. Given the elevations of those [RenderObject]s, this - /// [SemanticsNode] has a [thickness] of 10.0 and an elevation of 5.0 over - /// its parent [SemanticsNode] X. - /// ```dart - /// PhysicalModel( // A - /// color: Colors.amber, - /// child: Semantics( - /// explicitChildNodes: true, - /// child: const PhysicalModel( // B - /// color: Colors.brown, - /// elevation: 5.0, - /// child: PhysicalModel( // C - /// color: Colors.cyan, - /// elevation: 10.0, - /// child: Placeholder(), - /// ), - /// ), - /// ), - /// ) - /// ``` - /// {@end-tool} - /// - /// See also: - /// - /// * [elevation], which describes the elevation of the box defined by - /// [thickness] and [rect] relative to the parent of this [SemanticsNode]. - double get thickness => _thickness; - double _thickness = _kEmptyConfig.thickness; - /// Provides hint values which override the default hints on supported /// platforms. SemanticsHintOverrides? get hintOverrides => _hintOverrides; @@ -3229,8 +3114,6 @@ class SemanticsNode with DiagnosticableTreeMixin { _attributedHint = config.attributedHint; _tooltip = config.tooltip; _hintOverrides = config.hintOverrides; - _elevation = config.elevation; - _thickness = config.thickness; _flags = config._flags; _textDirection = config.textDirection; _sortKey = config.sortKey; @@ -3304,8 +3187,6 @@ class SemanticsNode with DiagnosticableTreeMixin { int? maxValueLength = _maxValueLength; int? currentValueLength = _currentValueLength; int headingLevel = _headingLevel; - final double elevation = _elevation; - double thickness = _thickness; Uri? linkUrl = _linkUrl; SemanticsRole role = _role; Set? controlsNodes = _controlsNodes; @@ -3410,8 +3291,6 @@ class SemanticsNode with DiagnosticableTreeMixin { otherTextDirection: node._textDirection, ); - thickness = math.max(thickness, node._thickness + node._elevation); - if (controlsNodes == null) { controlsNodes = node._controlsNodes; } else if (node._controlsNodes != null) { @@ -3446,8 +3325,6 @@ class SemanticsNode with DiagnosticableTreeMixin { textDirection: textDirection, rect: rect, transform: transform, - elevation: elevation, - thickness: thickness, tags: mergedTags, textSelection: textSelection, scrollChildCount: scrollChildCount, @@ -3542,8 +3419,6 @@ class SemanticsNode with DiagnosticableTreeMixin { scrollExtentMax: data.scrollExtentMax ?? double.nan, scrollExtentMin: data.scrollExtentMin ?? double.nan, transform: data.transform?.storage ?? _kIdentityTransform, - elevation: data.elevation, - thickness: data.thickness, childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: customSemanticsActionIds ?? _kEmptyCustomSemanticsActionsList, @@ -3741,8 +3616,6 @@ class SemanticsNode with DiagnosticableTreeMixin { properties.add(DoubleProperty('scrollPosition', scrollPosition, defaultValue: null)); properties.add(DoubleProperty('scrollExtentMax', scrollExtentMax, defaultValue: null)); properties.add(IntProperty('indexInParent', indexInParent, defaultValue: null)); - properties.add(DoubleProperty('elevation', elevation, defaultValue: 0.0)); - properties.add(DoubleProperty('thickness', thickness, defaultValue: 0.0)); properties.add(IntProperty('headingLevel', _headingLevel, defaultValue: 0)); if (_inputType != SemanticsInputType.none) { properties.add(EnumProperty('inputType', _inputType)); @@ -5302,40 +5175,6 @@ class SemanticsConfiguration { _hasBeenAnnotated = true; } - /// The elevation in z-direction at which the owning [RenderObject] is - /// located relative to its parent. - @Deprecated( - 'This was a feature added for 3D rendering, but the feature was deprecated. ' - 'This feature was deprecated after v3.29.0-0.0.pre.', - ) - double get elevation => _elevation; - double _elevation = 0.0; - set elevation(double value) { - assert(value >= 0.0); - if (value == _elevation) { - return; - } - _elevation = value; - _hasBeenAnnotated = true; - } - - /// The extend that the owning [RenderObject] occupies in z-direction starting - /// at [elevation]. - /// - /// It's extremely rare to set this value directly. Instead, it is calculated - /// implicitly when other [SemanticsConfiguration]s are merged into this one - /// via [absorb]. - double get thickness => _thickness; - double _thickness = 0.0; - set thickness(double value) { - assert(value >= 0.0); - if (value == _thickness) { - return; - } - _thickness = value; - _hasBeenAnnotated = true; - } - /// Whether the semantics node is the root of a subtree for which values /// should be announced. /// @@ -5927,8 +5766,6 @@ class SemanticsConfiguration { _tooltip = child._tooltip; } - _thickness = math.max(_thickness, child._thickness + child._elevation); - if (_controlsNodes == null) { _controlsNodes = child._controlsNodes; } else if (child._controlsNodes != null) { @@ -5965,8 +5802,6 @@ class SemanticsConfiguration { .._attributedHint = _attributedHint .._hintOverrides = _hintOverrides .._tooltip = _tooltip - .._elevation = _elevation - .._thickness = _thickness .._flags = _flags .._tagsForChildren = _tagsForChildren .._textSelection = _textSelection diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index fb4a8c4c192ed..f61208979fd44 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -2538,35 +2538,25 @@ void main() { flags: [SemanticsFlag.scopesRoute], children: [ TestSemantics( - children: [ - TestSemantics( - flags: [ - SemanticsFlag.isButton, - SemanticsFlag.isFocusable, - SemanticsFlag.hasSelectedState, - SemanticsFlag.isSelected, - ], - actions: [ - SemanticsAction.tap, - SemanticsAction.focus, - ], - label: 'A\nTab 1 of 2', - textDirection: TextDirection.ltr, - ), - TestSemantics( - flags: [ - SemanticsFlag.isButton, - SemanticsFlag.isFocusable, - SemanticsFlag.hasSelectedState, - ], - actions: [ - SemanticsAction.tap, - SemanticsAction.focus, - ], - label: 'B\nTab 2 of 2', - textDirection: TextDirection.ltr, - ), + flags: [ + SemanticsFlag.isButton, + SemanticsFlag.isFocusable, + SemanticsFlag.hasSelectedState, + SemanticsFlag.isSelected, ], + actions: [SemanticsAction.tap, SemanticsAction.focus], + label: 'A\nTab 1 of 2', + textDirection: TextDirection.ltr, + ), + TestSemantics( + flags: [ + SemanticsFlag.isButton, + SemanticsFlag.isFocusable, + SemanticsFlag.hasSelectedState, + ], + actions: [SemanticsAction.tap, SemanticsAction.focus], + label: 'B\nTab 2 of 2', + textDirection: TextDirection.ltr, ), ], ), diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index 3a4dad84a7c7c..b462b07b64749 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -1100,16 +1100,9 @@ void main() { flags: [SemanticsFlag.scopesRoute, SemanticsFlag.namesRoute], children: [ TestSemantics( + flags: [SemanticsFlag.hasImplicitScrolling], children: [ - TestSemantics( - flags: [SemanticsFlag.hasImplicitScrolling], - children: [ - TestSemantics( - label: 'BottomSheet', - textDirection: TextDirection.ltr, - ), - ], - ), + TestSemantics(label: 'BottomSheet', textDirection: TextDirection.ltr), ], ), ], @@ -1174,17 +1167,12 @@ void main() { flags: [SemanticsFlag.scopesRoute, SemanticsFlag.namesRoute], children: [ TestSemantics( - label: 'BottomSheet', + flags: [SemanticsFlag.isButton], + actions: [SemanticsAction.tap], + label: 'Dismiss', textDirection: TextDirection.ltr, - children: [ - TestSemantics( - flags: [SemanticsFlag.isButton], - actions: [SemanticsAction.tap], - label: 'Dismiss', - textDirection: TextDirection.ltr, - ), - ], ), + TestSemantics(label: 'BottomSheet', textDirection: TextDirection.ltr), ], ), ], diff --git a/packages/flutter/test/material/card_test.dart b/packages/flutter/test/material/card_test.dart index d049d87d049c2..770e2cc4ba6ef 100644 --- a/packages/flutter/test/material/card_test.dart +++ b/packages/flutter/test/material/card_test.dart @@ -101,25 +101,18 @@ void main() { hasSemantics( TestSemantics.root( children: [ + TestSemantics(id: 1, label: 'I am text!', textDirection: TextDirection.ltr), + TestSemantics(id: 2, label: 'Moar text!!1', textDirection: TextDirection.ltr), TestSemantics( - id: 1, - elevation: 1.0, - thickness: 0.0, - children: [ - TestSemantics(id: 2, label: 'I am text!', textDirection: TextDirection.ltr), - TestSemantics(id: 3, label: 'Moar text!!1', textDirection: TextDirection.ltr), - TestSemantics( - id: 4, - label: 'Button', - textDirection: TextDirection.ltr, - actions: [SemanticsAction.tap, SemanticsAction.focus], - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isButton, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - ], - ), + id: 3, + label: 'Button', + textDirection: TextDirection.ltr, + actions: [SemanticsAction.tap, SemanticsAction.focus], + flags: [ + SemanticsFlag.hasEnabledState, + SemanticsFlag.isButton, + SemanticsFlag.isEnabled, + SemanticsFlag.isFocusable, ], ), ], diff --git a/packages/flutter/test/semantics/semantics_elevation_test.dart b/packages/flutter/test/semantics/semantics_elevation_test.dart deleted file mode 100644 index e6a3a86fd2bc5..0000000000000 --- a/packages/flutter/test/semantics/semantics_elevation_test.dart +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../widgets/semantics_tester.dart'; - -void main() { - testWidgets('SemanticsNodes overlapping in z', (WidgetTester tester) async { - // Cards are semantic boundaries that always own their own SemanticNode, - // PhysicalModels merge their semantics information into parent. - // - // Side view of the widget tree: - // - // Card('abs. elevation: 30') --------------- - // | 8 ----------- Card('abs. elevation 25') - // Card('abs. elevation: 22') --------------- | - // | 7 | - // PhysicalModel('abs. elevation: 15') --------------- | 15 - // | 5 | - // --------------------------------------- Card('abs. elevation: 10') - // | 10 - // | - // --------------------------------------- 'ground' - final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget( - const MaterialApp( - home: Column( - children: [ - Text('ground'), - Card( - elevation: 10.0, - child: Column( - children: [ - Text('absolute elevation: 10'), - PhysicalModel( - elevation: 5.0, - color: Colors.black, - child: Column( - children: [ - Text('absolute elevation: 15'), - Card( - elevation: 7.0, - child: Column( - children: [ - Text('absolute elevation: 22'), - Card(elevation: 8.0, child: Text('absolute elevation: 30')), - ], - ), - ), - ], - ), - ), - Card(elevation: 15.0, child: Text('absolute elevation: 25')), - ], - ), - ), - ], - ), - ), - ); - - final SemanticsNode ground = tester.getSemantics(find.text('ground')); - expect(ground.thickness, 0.0); - expect(ground.elevation, 0.0); - expect(ground.label, 'ground'); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('absolute elevation: 10')); - final SemanticsNode elevation15 = tester.getSemantics(find.text('absolute elevation: 15')); - expect(elevation10, same(elevation15)); // configs got merged into each other. - expect(elevation10.thickness, 15.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'absolute elevation: 10\nabsolute elevation: 15'); - - final SemanticsNode elevation22 = tester.getSemantics(find.text('absolute elevation: 22')); - expect(elevation22.thickness, 7.0); - expect(elevation22.elevation, 15.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation25 = tester.getSemantics(find.text('absolute elevation: 25')); - expect(elevation25.thickness, 15.0); - expect(elevation25.elevation, 10.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation30 = tester.getSemantics(find.text('absolute elevation: 30')); - expect(elevation30.thickness, 8.0); - expect(elevation30.elevation, 7.0); - expect(elevation30.label, 'absolute elevation: 30'); - - semantics.dispose(); - }); - - testWidgets('SemanticsNodes overlapping in z with switched children', ( - WidgetTester tester, - ) async { - // Same as 'SemanticsNodes overlapping in z', but the order of children - // is reversed - - final SemanticsTester semantics = SemanticsTester(tester); - await tester.pumpWidget( - const MaterialApp( - home: Column( - children: [ - Text('ground'), - Card( - elevation: 10.0, - child: Column( - children: [ - Card(elevation: 15.0, child: Text('absolute elevation: 25')), - PhysicalModel( - elevation: 5.0, - color: Colors.black, - child: Column( - children: [ - Text('absolute elevation: 15'), - Card( - elevation: 7.0, - child: Column( - children: [ - Text('absolute elevation: 22'), - Card(elevation: 8.0, child: Text('absolute elevation: 30')), - ], - ), - ), - ], - ), - ), - Text('absolute elevation: 10'), - ], - ), - ), - ], - ), - ), - ); - - final SemanticsNode ground = tester.getSemantics(find.text('ground')); - expect(ground.thickness, 0.0); - expect(ground.elevation, 0.0); - expect(ground.label, 'ground'); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('absolute elevation: 10')); - final SemanticsNode elevation15 = tester.getSemantics(find.text('absolute elevation: 15')); - expect(elevation10, same(elevation15)); // configs got merged into each other. - expect(elevation10.thickness, 15.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'absolute elevation: 15\nabsolute elevation: 10'); - - final SemanticsNode elevation22 = tester.getSemantics(find.text('absolute elevation: 22')); - expect(elevation22.thickness, 7.0); - expect(elevation22.elevation, 15.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation25 = tester.getSemantics(find.text('absolute elevation: 25')); - expect(elevation25.thickness, 15.0); - expect(elevation25.elevation, 10.0); - expect(elevation22.label, 'absolute elevation: 22'); - - final SemanticsNode elevation30 = tester.getSemantics(find.text('absolute elevation: 30')); - expect(elevation30.thickness, 8.0); - expect(elevation30.elevation, 7.0); - expect(elevation30.label, 'absolute elevation: 30'); - - semantics.dispose(); - }); - - testWidgets('single node thickness', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget( - const MaterialApp(home: Center(child: Material(elevation: 24.0, child: Text('Hello')))), - ); - - final SemanticsNode node = tester.getSemantics(find.text('Hello')); - expect(node.thickness, 0.0); - expect(node.elevation, 24.0); - expect(node.label, 'Hello'); - - semantics.dispose(); - }); - - testWidgets('force-merge', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget( - MaterialApp( - home: Card( - elevation: 10.0, - child: Column( - children: [ - const Text('abs. elevation: 10.0'), - MergeSemantics( - child: Semantics( - explicitChildNodes: - true, // just to be sure that it's going to be an explicit merge - child: const Column( - children: [ - Card(elevation: 15.0, child: Text('abs. elevation 25.0')), - Card(elevation: 5.0, child: Text('abs. elevation 15.0')), - ], - ), - ), - ), - ], - ), - ), - ), - ); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('abs. elevation: 10.0')); - expect(elevation10.thickness, 10.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'abs. elevation: 10.0'); - expect(elevation10.childrenCount, 1); - - // TODO(goderbauer): remove awkward workaround when accessing force-merged - // SemanticsData becomes easier, https://github.com/flutter/flutter/issues/25669 - SemanticsData? mergedChildData; - elevation10.visitChildren((SemanticsNode child) { - expect(mergedChildData, isNull); - mergedChildData = child.getSemanticsData(); - return true; - }); - - expect(mergedChildData!.thickness, 15.0); - expect(mergedChildData!.elevation, 10.0); - expect(mergedChildData!.label, 'abs. elevation 25.0\nabs. elevation 15.0'); - - semantics.dispose(); - }); - - testWidgets('force-merge with inversed children', (WidgetTester tester) async { - final SemanticsTester semantics = SemanticsTester(tester); - - await tester.pumpWidget( - MaterialApp( - home: Card( - elevation: 10.0, - child: Column( - children: [ - const Text('abs. elevation: 10.0'), - MergeSemantics( - child: Semantics( - explicitChildNodes: - true, // just to be sure that it's going to be an explicit merge - child: const Column( - children: [ - Card(elevation: 5.0, child: Text('abs. elevation 15.0')), - Card(elevation: 15.0, child: Text('abs. elevation 25.0')), - ], - ), - ), - ), - ], - ), - ), - ), - ); - - final SemanticsNode elevation10 = tester.getSemantics(find.text('abs. elevation: 10.0')); - expect(elevation10.thickness, 10.0); - expect(elevation10.elevation, 0.0); - expect(elevation10.label, 'abs. elevation: 10.0'); - expect(elevation10.childrenCount, 1); - - // TODO(goderbauer): remove awkward workaround when accessing force-merged - // SemanticsData becomes easier, https://github.com/flutter/flutter/issues/25669 - SemanticsData? mergedChildData; - elevation10.visitChildren((SemanticsNode child) { - expect(mergedChildData, isNull); - mergedChildData = child.getSemanticsData(); - return true; - }); - - expect(mergedChildData!.thickness, 15.0); - expect(mergedChildData!.elevation, 10.0); - expect(mergedChildData!.label, 'abs. elevation 15.0\nabs. elevation 25.0'); - - semantics.dispose(); - }); -} diff --git a/packages/flutter/test/semantics/semantics_test.dart b/packages/flutter/test/semantics/semantics_test.dart index b7129d9566732..ae9bb8e104af4 100644 --- a/packages/flutter/test/semantics/semantics_test.dart +++ b/packages/flutter/test/semantics/semantics_test.dart @@ -731,8 +731,6 @@ void main() { ' scrollPosition: null\n' ' scrollExtentMax: null\n' ' indexInParent: null\n' - ' elevation: 0.0\n' - ' thickness: 0.0\n' ' headingLevel: 0\n', ); @@ -867,8 +865,6 @@ void main() { ' scrollPosition: null\n' ' scrollExtentMax: null\n' ' indexInParent: null\n' - ' elevation: 0.0\n' - ' thickness: 0.0\n' ' headingLevel: 0\n', ); }); diff --git a/packages/flutter/test/semantics/semantics_update_test.dart b/packages/flutter/test/semantics/semantics_update_test.dart index 8f6c7d6c3d4f0..02e9804f464e3 100644 --- a/packages/flutter/test/semantics/semantics_update_test.dart +++ b/packages/flutter/test/semantics/semantics_update_test.dart @@ -206,8 +206,6 @@ class SemanticsUpdateBuilderSpy extends Fake implements ui.SemanticsUpdateBuilde required double scrollPosition, required double scrollExtentMax, required double scrollExtentMin, - required double elevation, - required double thickness, required Rect rect, required String identifier, required String label, diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart index 6f526ea43a0d2..e782072b95379 100644 --- a/packages/flutter/test/widgets/semantics_tester.dart +++ b/packages/flutter/test/widgets/semantics_tester.dart @@ -48,8 +48,6 @@ class TestSemantics { this.textDirection, this.rect, this.transform, - this.elevation, - this.thickness, this.textSelection, this.children = const [], this.scrollIndex, @@ -100,8 +98,6 @@ class TestSemantics { assert(flags is int || flags is List), assert(actions is int || actions is List), rect = TestSemantics.rootRect, - elevation = 0.0, - thickness = 0.0, tags = tags?.toSet() ?? {}; /// Creates an object with some test semantics data, with the [id] and [rect] @@ -128,8 +124,6 @@ class TestSemantics { this.textDirection, this.rect, Matrix4? transform, - this.elevation, - this.thickness, this.textSelection, this.children = const [], this.scrollIndex, @@ -233,21 +227,6 @@ class TestSemantics { /// parent). final Matrix4? transform; - /// The elevation of this node relative to the parent node. - /// - /// See also: - /// - /// * [SemanticsConfiguration.elevation] for a detailed discussion regarding - /// elevation and semantics. - final double? elevation; - - /// The extend that this node occupies in z-direction starting at [elevation]. - /// - /// See also: - /// - /// * [SemanticsConfiguration.thickness] for a more detailed definition. - final double? thickness; - /// The index of the first visible semantic node within a scrollable. final int? scrollIndex; @@ -419,16 +398,6 @@ class TestSemantics { 'expected node id $id to have transform $transform but found transform:\n${nodeData.transform}.', ); } - if (elevation != null && elevation != nodeData.elevation) { - return fail( - 'expected node id $id to have elevation $elevation but found elevation:\n${nodeData.elevation}.', - ); - } - if (thickness != null && thickness != nodeData.thickness) { - return fail( - 'expected node id $id to have thickness $thickness but found thickness:\n${nodeData.thickness}.', - ); - } if (textSelection?.baseOffset != nodeData.textSelection?.baseOffset || textSelection?.extentOffset != nodeData.textSelection?.extentOffset) { return fail( @@ -583,12 +552,6 @@ class TestSemantics { '$indent transform:\n${transform.toString().trim().split('\n').map((String line) => '$indent $line').join('\n')},', ); } - if (elevation != null) { - buf.writeln('$indent elevation: $elevation,'); - } - if (thickness != null) { - buf.writeln('$indent thickness: $thickness,'); - } if (inputType != SemanticsInputType.none) { buf.writeln('$indent inputType: $inputType,'); } diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart index 01218603b3062..052e884630661 100644 --- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart @@ -97,11 +97,9 @@ void main() { TestSemantics( children: [ TestSemantics( - thickness: 0, children: [ TestSemantics( label: 'Hello', - elevation: 0, flags: [SemanticsFlag.isHeader, SemanticsFlag.namesRoute], textDirection: TextDirection.ltr, ), diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index e1079c816cab4..a6ca25b3d082d 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -762,8 +762,6 @@ Matcher matchesSemantics({ textDirection: textDirection, rect: rect, size: size, - elevation: elevation, - thickness: thickness, platformViewId: platformViewId, customActions: customActions, maxValueLength: maxValueLength, @@ -960,8 +958,6 @@ Matcher containsSemantics({ textDirection: textDirection, rect: rect, size: size, - elevation: elevation, - thickness: thickness, platformViewId: platformViewId, customActions: customActions, maxValueLength: maxValueLength, @@ -2392,8 +2388,6 @@ class _MatchesSemanticsData extends Matcher { required this.textDirection, required this.rect, required this.size, - required this.elevation, - required this.thickness, required this.platformViewId, required this.maxValueLength, required this.currentValueLength, @@ -2547,8 +2541,6 @@ class _MatchesSemanticsData extends Matcher { final TextDirection? textDirection; final Rect? rect; final Size? size; - final double? elevation; - final double? thickness; final int? platformViewId; final int? maxValueLength; final int? currentValueLength; @@ -2650,12 +2642,6 @@ class _MatchesSemanticsData extends Matcher { if (size != null) { description.add(' with size: $size'); } - if (elevation != null) { - description.add(' with elevation: $elevation'); - } - if (thickness != null) { - description.add(' with thickness: $thickness'); - } if (platformViewId != null) { description.add(' with platformViewId: $platformViewId'); } @@ -2795,12 +2781,6 @@ class _MatchesSemanticsData extends Matcher { if (size != null && size != data.rect.size) { return failWithDescription(matchState, 'size was: ${data.rect.size}'); } - if (elevation != null && elevation != data.elevation) { - return failWithDescription(matchState, 'elevation was: ${data.elevation}'); - } - if (thickness != null && thickness != data.thickness) { - return failWithDescription(matchState, 'thickness was: ${data.thickness}'); - } if (platformViewId != null && platformViewId != data.platformViewId) { return failWithDescription(matchState, 'platformViewId was: ${data.platformViewId}'); } diff --git a/packages/flutter_test/test/matchers_test.dart b/packages/flutter_test/test/matchers_test.dart index 56b9a6ae09dc9..d337b3fcda688 100644 --- a/packages/flutter_test/test/matchers_test.dart +++ b/packages/flutter_test/test/matchers_test.dart @@ -746,8 +746,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1048,8 +1046,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1150,8 +1146,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1256,8 +1250,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1289,8 +1281,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, @@ -1379,8 +1369,6 @@ void main() { tooltip: 'f', textDirection: TextDirection.ltr, rect: const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), - elevation: 3.0, - thickness: 4.0, textSelection: null, scrollIndex: null, scrollChildCount: null, From 1709d3aafc305aafcd45a9e9803e428f6436065c Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 30 May 2025 15:53:44 -0700 Subject: [PATCH 57/66] [Impeller] Directly tessellate arc operations (#169402) Currently arcs are rendered by creating/allocating a Path and using the path rendering code. We now directly tessellate most arcs (all filled arcs and any stroked arcs that avoid "use_center" and "round caps") using the most efficient mechanism to place the necessary vertices into the host buffers. --- .../ci/licenses_golden/licenses_flutter | 4 + .../display_list/aiks_dl_basic_unittests.cc | 207 ++++++++++ .../flutter/impeller/display_list/canvas.cc | 63 ++- .../flutter/impeller/display_list/canvas.h | 4 +- .../impeller/display_list/dl_dispatcher.cc | 4 +- engine/src/flutter/impeller/entity/BUILD.gn | 2 + .../impeller/entity/geometry/arc_geometry.cc | 145 +++++++ .../impeller/entity/geometry/arc_geometry.h | 62 +++ .../impeller/entity/geometry/geometry.cc | 17 + .../impeller/entity/geometry/geometry.h | 11 + .../entity/geometry/geometry_unittests.cc | 367 ++++++++++++++++++ engine/src/flutter/impeller/geometry/point.h | 8 + engine/src/flutter/impeller/geometry/scalar.h | 69 ++++ .../impeller/tessellator/tessellator.cc | 295 +++++++++++++- .../impeller/tessellator/tessellator.h | 175 +++++++++ .../tessellator/tessellator_unittests.cc | 263 +++++++++++++ 16 files changed, 1670 insertions(+), 26 deletions(-) create mode 100644 engine/src/flutter/impeller/entity/geometry/arc_geometry.cc create mode 100644 engine/src/flutter/impeller/entity/geometry/arc_geometry.h diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 32e185519c50d..a1246501b752f 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -51372,6 +51372,8 @@ ORIGIN: ../../../flutter/impeller/entity/entity_pass_target.cc + ../../../flutte ORIGIN: ../../../flutter/impeller/entity/entity_pass_target.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_playground.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/entity_playground.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/arc_geometry.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/arc_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/circle_geometry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/circle_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/cover_geometry.cc + ../../../flutter/LICENSE @@ -54387,6 +54389,8 @@ FILE: ../../../flutter/impeller/entity/entity_pass_target.cc FILE: ../../../flutter/impeller/entity/entity_pass_target.h FILE: ../../../flutter/impeller/entity/entity_playground.cc FILE: ../../../flutter/impeller/entity/entity_playground.h +FILE: ../../../flutter/impeller/entity/geometry/arc_geometry.cc +FILE: ../../../flutter/impeller/entity/geometry/arc_geometry.h FILE: ../../../flutter/impeller/entity/geometry/circle_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/circle_geometry.h FILE: ../../../flutter/impeller/entity/geometry/cover_geometry.cc diff --git a/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc b/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc index fefe068f54b33..ad77934c7e337 100644 --- a/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc +++ b/engine/src/flutter/impeller/display_list/aiks_dl_basic_unittests.cc @@ -759,6 +759,213 @@ TEST_P(AiksTest, FilledEllipsesRenderCorrectly) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +namespace { +struct ArcFarmOptions { + bool use_center; + bool full_circles; + Scalar vertical_scale = 1.0f; +}; + +void RenderArcFarm(DisplayListBuilder& builder, + const DlPaint& paint, + const ArcFarmOptions& opts) { + builder.Save(); + builder.Translate(50, 50); + const Rect arc_bounds = Rect::MakeLTRB(0, 0, 42, 42 * opts.vertical_scale); + for (int start = 0; start <= 360; start += 30) { + builder.Save(); + for (int sweep = 30; sweep <= 360; sweep += 30) { + builder.DrawArc(arc_bounds, start, opts.full_circles ? 360 : sweep, + opts.use_center, paint); + builder.Translate(50, 0); + } + builder.Restore(); + builder.Translate(0, 50); + } + builder.Restore(); +} +} // namespace + +TEST_P(AiksTest, FilledArcsRenderCorrectly) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, FilledArcsRenderCorrectlyWithCenter) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = true, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectly) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + .vertical_scale = 0.8f, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectlyWithCenter) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = true, + .full_circles = false, + .vertical_scale = 0.8f, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithButtEnds) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(6.0f); + paint.setStrokeCap(DlStrokeCap::kButt); + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareEnds) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(6.0f); + paint.setStrokeCap(DlStrokeCap::kSquare); + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareAndButtEnds) { + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(8.0f); + paint.setStrokeCap(DlStrokeCap::kSquare); + paint.setColor(DlColor::kRed()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + paint.setStrokeCap(DlStrokeCap::kButt); + paint.setColor(DlColor::kBlue()); + + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(AiksTest, StrokedArcsCoverFullArcWithButtEnds) { + // This test compares the rendering of a full circle arc against a partial + // arc by drawing a one over the other in high contrast. If the partial + // arc misses any pixels that were drawn by the full arc, there will be + // some "pixel dirt" around the missing "erased" parts of the arcs. This + // case arises while rendering a CircularProgressIndicator with a background + // color where we want the rendering of the background full arc to hit the + // same pixels around the edges as the partial arc that covers it. + // + // In this case we draw a full blue circle and then draw a partial arc + // over it in the background color (white). + + DisplayListBuilder builder; + builder.Scale(GetContentScale().x, GetContentScale().y); + builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc); + + DlPaint paint; + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(6.0f); + paint.setStrokeCap(DlStrokeCap::kButt); + paint.setColor(DlColor::kBlue()); + + // First draw full circles in blue to establish the pixels to be erased + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = true, + }); + + paint.setColor(DlColor::kWhite()); + + // Then draw partial arcs in white over the circles to "erase" them + RenderArcFarm(builder, paint, + { + .use_center = false, + .full_circles = false, + }); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) { DisplayListBuilder builder; builder.Scale(GetContentScale().x, GetContentScale().y); diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 065a9372e55d4..7e3caf9c10d7e 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -36,6 +36,7 @@ #include "impeller/entity/contents/text_shadow_cache.h" #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/contents/vertices_contents.h" +#include "impeller/entity/geometry/arc_geometry.h" #include "impeller/entity/geometry/circle_geometry.h" #include "impeller/entity/geometry/cover_geometry.h" #include "impeller/entity/geometry/ellipse_geometry.h" @@ -650,43 +651,63 @@ void Canvas::DrawOval(const Rect& rect, const Paint& paint) { } void Canvas::DrawArc(const Rect& oval_bounds, - Scalar start_degrees, - Scalar sweep_degrees, + Degrees start, + Degrees sweep, bool use_center, const Paint& paint) { Entity entity; entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); - if (paint.style == Paint::Style::kStroke && - paint.stroke.width > oval_bounds.GetSize().MaxDimension()) { + if (paint.style == Paint::Style::kFill) { + ArcGeometry geom(oval_bounds, start, sweep, use_center); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + return; + } + + if (paint.stroke.width > oval_bounds.GetSize().MaxDimension()) { // This is a special case for rendering arcs whose stroke width is so large // you are effectively drawing a sector of a circle. // https://github.com/flutter/flutter/issues/158567 Rect expanded_rect = oval_bounds.Expand(Size(paint.stroke.width * 0.5f)); - flutter::DlPathBuilder builder; - builder.AddArc(expanded_rect, Degrees(start_degrees), - Degrees(sweep_degrees), /*use_center=*/true); - - Paint fill_paint = paint; - fill_paint.style = Paint::Style::kFill; - - ArcFillPathGeometry geom(builder.TakePath(), expanded_rect); + ArcGeometry geom(expanded_rect, start, sweep, /*include_center=*/true); AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); - } else { - flutter::DlPathBuilder builder; - builder.AddArc(oval_bounds, Degrees(start_degrees), Degrees(sweep_degrees), - use_center); + return; + } - if (paint.style == Paint::Style::kFill) { - ArcFillPathGeometry geom(builder.TakePath(), oval_bounds); - AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); - } else { - ArcStrokePathGeometry geom(builder.TakePath(), oval_bounds, paint.stroke); + // Use_center incurs lots of extra work for stroking an arc, including: + // - It introduces segments to/from the center point (not too hard). + // - It introduces joins on those segments (a bit more complicated). + // - Even if the sweep is >=360 degrees, we still draw the segment to + // the center and it basically looks like a pie cut into the complete + // boundary circle, as if the slice were cut, but not extracted + // (hard to express as a continuous kTriangleStrip). + if (!use_center) { + if (std::abs(sweep.degrees) >= 360.0f) { + return DrawOval(oval_bounds, paint); + } + + // Our fast stroking code only works for circular bounds as it assumes + // that the inner and outer radii can be scaled along each angular step + // of the arc - which is not true for elliptical arcs where the inner + // and outer samples are perpendicular to the traveling direction of the + // elliptical curve which may not line up with the center of the bounds. + // + // TODO(flar): It also only supports Butt and Square caps for now. + // See https://github.com/flutter/flutter/issues/169400 + if (oval_bounds.IsSquare() && paint.stroke.cap != Cap::kRound) { + ArcGeometry geom(oval_bounds, start, sweep, paint.stroke); AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); + return; } } + + flutter::DlPathBuilder builder; + builder.AddArc(oval_bounds, start, sweep, use_center); + + ArcStrokePathGeometry geom(builder.TakePath(), oval_bounds, paint.stroke); + AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint); } void Canvas::DrawRoundRect(const RoundRect& round_rect, const Paint& paint) { diff --git a/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index 0c4ac8af3c82a..323a5650d3ccd 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/impeller/display_list/canvas.h @@ -204,8 +204,8 @@ class Canvas { void DrawOval(const Rect& rect, const Paint& paint); void DrawArc(const Rect& oval_bounds, - Scalar start_degrees, - Scalar sweep_degrees, + Degrees start, + Degrees sweep, bool use_center, const Paint& paint); diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index 606c39e595b23..fcaa4bd5e1f00 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc @@ -679,8 +679,8 @@ void DlDispatcherBase::drawArc(const DlRect& oval_bounds, bool use_center) { AUTO_DEPTH_WATCHER(1u); - GetCanvas().DrawArc(oval_bounds, start_degrees, sweep_degrees, use_center, - paint_); + GetCanvas().DrawArc(oval_bounds, Degrees(start_degrees), + Degrees(sweep_degrees), use_center, paint_); } // |flutter::DlOpReceiver| diff --git a/engine/src/flutter/impeller/entity/BUILD.gn b/engine/src/flutter/impeller/entity/BUILD.gn index 2264682efd73b..3f0e9aeabe489 100644 --- a/engine/src/flutter/impeller/entity/BUILD.gn +++ b/engine/src/flutter/impeller/entity/BUILD.gn @@ -200,6 +200,8 @@ impeller_component("entity") { "entity_pass_clip_stack.h", "entity_pass_target.cc", "entity_pass_target.h", + "geometry/arc_geometry.cc", + "geometry/arc_geometry.h", "geometry/circle_geometry.cc", "geometry/circle_geometry.h", "geometry/cover_geometry.cc", diff --git a/engine/src/flutter/impeller/entity/geometry/arc_geometry.cc b/engine/src/flutter/impeller/entity/geometry/arc_geometry.cc new file mode 100644 index 0000000000000..ba8d33e0755d4 --- /dev/null +++ b/engine/src/flutter/impeller/entity/geometry/arc_geometry.cc @@ -0,0 +1,145 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/impeller/entity/geometry/arc_geometry.h" + +#include "flutter/impeller/entity/geometry/line_geometry.h" + +namespace impeller { + +ArcGeometry::ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center) + : oval_bounds_(oval_bounds), + start_(start), + sweep_(sweep), + include_center_(include_center), + stroke_width_(-1.0f), + cap_(Cap::kButt) {} + +ArcGeometry::ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke) + : oval_bounds_(oval_bounds), + start_(start), + sweep_(sweep), + include_center_(false), + stroke_width_(stroke.width), + cap_(stroke.cap) { + FML_DCHECK(oval_bounds_.IsSquare()); +} + +ArcGeometry::~ArcGeometry() = default; + +// |Geometry| +Scalar ArcGeometry::ComputeAlphaCoverage(const Matrix& transform) const { + if (stroke_width_ < 0) { + return 1; + } + return Geometry::ComputeStrokeAlphaCoverage(transform, stroke_width_); +} + +GeometryResult ArcGeometry::GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + auto& transform = entity.GetTransform(); + + if (stroke_width_ < 0) { + auto generator = renderer.GetTessellator().FilledArc( + transform, oval_bounds_, start_, sweep_, include_center_, + renderer.GetDeviceCapabilities().SupportsTriangleFan()); + + return ComputePositionGeometry(renderer, generator, entity, pass); + } else { + FML_DCHECK(oval_bounds_.IsSquare()); + Scalar half_width = + LineGeometry::ComputePixelHalfWidth(transform, stroke_width_); + + auto generator = renderer.GetTessellator().StrokedArc( + transform, oval_bounds_, start_, sweep_, cap_, half_width); + + return ComputePositionGeometry(renderer, generator, entity, pass); + } +} + +std::optional ArcGeometry::GetCoverage(const Matrix& transform) const { + Scalar padding = // + stroke_width_ < 0 + ? 0.0 + : LineGeometry::ComputePixelHalfWidth(transform, stroke_width_); + + if (sweep_.degrees <= -360 || sweep_.degrees >= 360) { + return oval_bounds_.Expand(padding).TransformAndClipBounds(transform); + } + + if (cap_ == Cap::kSquare) { + padding = padding * kSqrt2; + } + + Degrees start_angle, end_angle; + if (sweep_.degrees < 0) { + start_angle = (start_ + sweep_).GetPositive(); + end_angle = start_angle - sweep_; + } else { + start_angle = start_.GetPositive(); + end_angle = start_angle + sweep_; + } + FML_DCHECK(start_angle.degrees >= 0 && start_angle.degrees < 360); + FML_DCHECK(end_angle > start_angle && end_angle.degrees < 720); + + // 1. start vector + // 2. end vector + // 3. optional center + // 4-7. optional quadrant extrema + Point extrema[7]; + int count = 0; + + extrema[count++] = Matrix::CosSin(start_angle); + extrema[count++] = Matrix::CosSin(end_angle); + + if (include_center_) { + // We don't handle strokes with include_center so the stroking + // parameters should be the default. + FML_DCHECK(stroke_width_ < 0 && cap_ == Cap::kButt && padding == 0.0f); + extrema[count++] = {0, 0}; + } + + // cur_axis will be pre-incremented before recording the following axis + int cur_axis = std::floor(start_angle.degrees / 90.0f); + // end_axis is a non-inclusive end of the range + int end_axis = std::ceil(end_angle.degrees / 90.0f); + while (++cur_axis < end_axis) { + extrema[count++] = kQuadrantAxes[cur_axis & 3]; + } + + FML_DCHECK(count <= 7); + + Point center = oval_bounds_.GetCenter(); + Size radii = oval_bounds_.GetSize() * 0.5f; + + for (int i = 0; i < count; i++) { + extrema[i] = center + extrema[i] * radii; + } + auto opt_rect = Rect::MakePointBounds(extrema, extrema + count); + if (opt_rect.has_value()) { + // Pretty much guaranteed because count >= 2... + opt_rect = opt_rect // + .value() + .Expand(padding) + .TransformAndClipBounds(transform); + } + return opt_rect; +} + +bool ArcGeometry::CoversArea(const Matrix& transform, const Rect& rect) const { + return false; +} + +bool ArcGeometry::IsAxisAlignedRect() const { + return false; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/arc_geometry.h b/engine/src/flutter/impeller/entity/geometry/arc_geometry.h new file mode 100644 index 0000000000000..b06a7b6a5f1d0 --- /dev/null +++ b/engine/src/flutter/impeller/entity/geometry/arc_geometry.h @@ -0,0 +1,62 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_ARC_GEOMETRY_H_ +#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_ARC_GEOMETRY_H_ + +#include "impeller/entity/geometry/geometry.h" + +#include "impeller/geometry/stroke_parameters.h" + +namespace impeller { + +// Geometry class that can generate vertices (with or without texture +// coordinates) for either filled or stroked circles +class ArcGeometry final : public Geometry { + public: + explicit ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center); + + explicit ArcGeometry(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke); + + ~ArcGeometry() override; + + // |Geometry| + bool CoversArea(const Matrix& transform, const Rect& rect) const override; + + // |Geometry| + bool IsAxisAlignedRect() const override; + + // |Geometry| + Scalar ComputeAlphaCoverage(const Matrix& transform) const override; + + private: + // |Geometry| + GeometryResult GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + // |Geometry| + std::optional GetCoverage(const Matrix& transform) const override; + + Rect oval_bounds_; + Degrees start_; + Degrees sweep_; + bool include_center_; + Scalar stroke_width_; + Cap cap_; + + ArcGeometry(const ArcGeometry&) = delete; + + ArcGeometry& operator=(const ArcGeometry&) = delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_ARC_GEOMETRY_H_ diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.cc b/engine/src/flutter/impeller/entity/geometry/geometry.cc index 2e59d0cedf7b6..e8a2450501982 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry.cc @@ -9,6 +9,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/pipelines.h" +#include "impeller/entity/geometry/arc_geometry.h" #include "impeller/entity/geometry/circle_geometry.h" #include "impeller/entity/geometry/cover_geometry.h" #include "impeller/entity/geometry/ellipse_geometry.h" @@ -104,6 +105,22 @@ std::unique_ptr Geometry::MakeStrokedCircle(const Point& center, return std::make_unique(center, radius, stroke_width); } +std::unique_ptr Geometry::MakeFilledArc(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center) { + return std::make_unique(oval_bounds, start, sweep, + include_center); +} + +std::unique_ptr Geometry::MakeStrokedArc( + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke) { + return std::make_unique(oval_bounds, start, sweep, stroke); +} + std::unique_ptr Geometry::MakeRoundRect(const Rect& rect, const Size& radii) { return std::make_unique(rect, radii); diff --git a/engine/src/flutter/impeller/entity/geometry/geometry.h b/engine/src/flutter/impeller/entity/geometry/geometry.h index 107ed9bea97a0..44069f8a7459a 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry.h +++ b/engine/src/flutter/impeller/entity/geometry/geometry.h @@ -76,6 +76,17 @@ class Geometry { Scalar radius, Scalar stroke_width); + static std::unique_ptr MakeFilledArc(const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool include_center); + + static std::unique_ptr MakeStrokedArc( + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + const StrokeParameters& stroke); + static std::unique_ptr MakeRoundRect(const Rect& rect, const Size& radii); diff --git a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc index 2bc2ea470db7e..7d2f79fe5a9ff 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc @@ -97,6 +97,373 @@ TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) { ASSERT_FALSE(geometry->CoversArea({}, Rect())); } +TEST(EntityGeometryTest, FillArcGeometryCoverage) { + Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200); + Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-oval_bounds.GetCenter()); + + { // Sweeps <=-360 or >=360 + for (int start = -720; start <= 720; start += 10) { + for (int sweep = 360; sweep <= 720; sweep += 30) { + std::string label = + "start: " + std::to_string(start) + " + " + std::to_string(sweep); + auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(sweep), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << ", sweep: " << sweep; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-sweep), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << ", sweep: " << -sweep; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-sweep), true); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << ", sweep: " << -sweep << ", with center"; + } + } + } + { // Sweep from late in one quadrant to earlier in same quadrant + for (int start = 60; start < 360; start += 90) { + auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(330), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " without center"; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(330), true); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " with center"; + } + } + { // Sweep from early in one quadrant backwards to later in same quadrant + for (int start = 30; start < 360; start += 90) { + auto geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-330), false); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " without center"; + geometry = Geometry::MakeFilledArc(oval_bounds, Degrees(start), + Degrees(-330), true); + EXPECT_EQ(geometry->GetCoverage({}), oval_bounds) + << "start: " << start << " with center"; + } + } + { // Sweep past each quadrant axis individually, no center + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start - 45), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2, // + 150 - 50 * kSqrt2Over2, // + 200, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 45), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 150 + 50 * kSqrt2Over2, // + 150 + 50 * kSqrt2Over2, // + 200); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 135), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(100, // + 150 - 50 * kSqrt2Over2, // + 150 - 50 * kSqrt2Over2, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 225), Degrees(90), false); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 100, // + 150 + 50 * kSqrt2Over2, // + 150 - 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // Sweep past each quadrant axis individually, including the center + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start - 45), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(150, // + 150 - 50 * kSqrt2Over2, // + 200, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 45), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 150, // + 150 + 50 * kSqrt2Over2, // + 200); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 135), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(100, // + 150 - 50 * kSqrt2Over2, // + 150, // + 150 + 50 * kSqrt2Over2); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeFilledArc( + oval_bounds, Degrees(start + 225), Degrees(90), true); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2, // + 100, // + 150 + 50 * kSqrt2Over2, // + 150); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // 45 degree tilted full circle + auto geometry = + Geometry::MakeFilledArc(oval_bounds, Degrees(0), Degrees(360), false); + ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(oval_bounds)); + } + { // 45 degree tilted mostly full circle + auto geometry = + Geometry::MakeFilledArc(oval_bounds, Degrees(3), Degrees(359), false); + ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(oval_bounds)); + } +} + +TEST(EntityGeometryTest, StrokeArcGeometryCoverage) { + Rect oval_bounds = Rect::MakeLTRB(100, 100, 200, 200); + Rect expanded_bounds = Rect::MakeLTRB(95, 95, 205, 205); + Rect squared_bounds = Rect::MakeLTRB(100 - 5 * kSqrt2, 100 - 5 * kSqrt2, + 200 + 5 * kSqrt2, 200 + 5 * kSqrt2); + Matrix transform45 = Matrix::MakeTranslation(oval_bounds.GetCenter()) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-oval_bounds.GetCenter()); + + StrokeParameters butt_params = { + .width = 10.0f, + .cap = Cap::kButt, + }; + StrokeParameters square_params = { + .width = 10.0f, + .cap = Cap::kSquare, + }; + + { // Sweeps <=-360 or >=360 + for (int start = -720; start <= 720; start += 10) { + for (int sweep = 360; sweep <= 720; sweep += 30) { + std::string label = + "start: " + std::to_string(start) + " + " + std::to_string(sweep); + auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(sweep), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", sweep: " << sweep; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-sweep), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", sweep: " << -sweep; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-sweep), square_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", sweep: " << -sweep << ", square caps"; + } + } + } + { // Sweep from late in one quadrant to earlier in same quadrant + for (int start = 60; start < 360; start += 90) { + auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(330), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << ", butt caps"; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(330), square_params); + EXPECT_EQ(geometry->GetCoverage({}), squared_bounds) + << "start: " << start << ", square caps"; + } + } + { // Sweep from early in one quadrant backwards to later in same quadrant + for (int start = 30; start < 360; start += 90) { + auto geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-330), butt_params); + EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds) + << "start: " << start << " without center"; + geometry = Geometry::MakeStrokedArc(oval_bounds, Degrees(start), + Degrees(-330), square_params); + EXPECT_EQ(geometry->GetCoverage({}), squared_bounds) + << "start: " << start << " with center"; + } + } + { // Sweep past each quadrant axis individually with butt caps + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start - 45), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - 5, // + 150 - 50 * kSqrt2Over2 - 5, // + 205, // + 150 + 50 * kSqrt2Over2 + 5); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 45), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5, // + 150 + 50 * kSqrt2Over2 - 5, // + 150 + 50 * kSqrt2Over2 + 5, // + 205); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 135), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(95, // + 150 - 50 * kSqrt2Over2 - 5, // + 150 - 50 * kSqrt2Over2 + 5, // + 150 + 50 * kSqrt2Over2 + 5); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 225), Degrees(90), butt_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - 5, // + 95, // + 150 + 50 * kSqrt2Over2 + 5, // + 150 - 50 * kSqrt2Over2 + 5); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // Sweep past each quadrant axis individually with square caps + Scalar pad = 5 * kSqrt2; + for (int start = -360; start <= 720; start += 360) { + { // Quadrant 0 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start - 45), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(150 + 50 * kSqrt2Over2 - pad, // + 150 - 50 * kSqrt2Over2 - pad, // + 200 + pad, // + 150 + 50 * kSqrt2Over2 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start - 45; + } + { // Quadrant 1 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 45), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad, // + 150 + 50 * kSqrt2Over2 - pad, // + 150 + 50 * kSqrt2Over2 + pad, // + 200 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 45; + } + { // Quadrant 2 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 135), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(100 - pad, // + 150 - 50 * kSqrt2Over2 - pad, // + 150 - 50 * kSqrt2Over2 + pad, // + 150 + 50 * kSqrt2Over2 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 135; + } + { // Quadrant 3 + auto geometry = Geometry::MakeStrokedArc( + oval_bounds, Degrees(start + 225), Degrees(90), square_params); + Rect expected_bounds = Rect::MakeLTRB(150 - 50 * kSqrt2Over2 - pad, // + 100 - pad, // + 150 + 50 * kSqrt2Over2 + pad, // + 150 - 50 * kSqrt2Over2 + pad); + EXPECT_RECT_NEAR(geometry->GetCoverage({}).value_or(Rect()), + expected_bounds) + << "start: " << start + 225; + } + } + } + { // 45 degree tilted full circle, butt caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(0), Degrees(360), butt_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(expanded_bounds)); + } + { // 45 degree tilted full circle, square caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(0), Degrees(360), square_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(squared_bounds)); + } + { // 45 degree tilted mostly full circle, butt caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(3), Degrees(359), butt_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(expanded_bounds)); + } + { // 45 degree tilted mostly full circle, square caps + auto geometry = Geometry::MakeStrokedArc( // + oval_bounds, Degrees(3), Degrees(359), square_params); + ASSERT_TRUE( + oval_bounds.TransformBounds(transform45).Contains(expanded_bounds)); + + EXPECT_TRUE(geometry->GetCoverage(transform45) + .value_or(Rect()) + .Contains(squared_bounds)); + } +} + TEST(EntityGeometryTest, FillRoundRectGeometryCoversArea) { Rect bounds = Rect::MakeLTRB(100, 100, 200, 200); RoundRect round_rect = diff --git a/engine/src/flutter/impeller/geometry/point.h b/engine/src/flutter/impeller/geometry/point.h index 2c19467c6439b..fc57dd93893a3 100644 --- a/engine/src/flutter/impeller/geometry/point.h +++ b/engine/src/flutter/impeller/geometry/point.h @@ -331,6 +331,14 @@ using UintPoint32 = TPoint; using Vector2 = Point; using Quad = std::array; +[[maybe_unused]] +static constexpr impeller::Vector2 kQuadrantAxes[4] = { + {1.0f, 0.0f}, + {0.0f, 1.0f}, + {-1.0f, 0.0f}, + {0.0f, -1.0f}, +}; + #undef ONLY_ON_FLOAT #undef ONLY_ON_FLOAT_M diff --git a/engine/src/flutter/impeller/geometry/scalar.h b/engine/src/flutter/impeller/geometry/scalar.h index dadc52850cb5f..10e8e66ea6455 100644 --- a/engine/src/flutter/impeller/geometry/scalar.h +++ b/engine/src/flutter/impeller/geometry/scalar.h @@ -6,6 +6,7 @@ #define FLUTTER_IMPELLER_GEOMETRY_SCALAR_H_ #include +#include #include #include @@ -46,6 +47,30 @@ struct Radians { constexpr Radians() = default; explicit constexpr Radians(Scalar p_radians) : radians(p_radians) {} + + constexpr bool IsFinite() const { return std::isfinite(radians); } + + constexpr Radians operator-() { return Radians{-radians}; } + + constexpr Radians operator+(Radians r) { + return Radians{radians + r.radians}; + } + + constexpr Radians operator-(Radians r) { + return Radians{radians - r.radians}; + } + + constexpr bool operator>(Radians r) { return radians > r.radians; } + + constexpr bool operator>=(Radians r) { return radians >= r.radians; } + + constexpr bool operator==(Radians r) { return radians == r.radians; } + + constexpr bool operator!=(Radians r) { return radians != r.radians; } + + constexpr bool operator<=(Radians r) { return radians <= r.radians; } + + constexpr bool operator<(Radians r) { return radians < r.radians; } }; struct Degrees { @@ -58,10 +83,54 @@ struct Degrees { constexpr operator Radians() const { return Radians{degrees * kPi / 180.0f}; }; + + constexpr bool IsFinite() const { return std::isfinite(degrees); } + + constexpr Degrees operator-() const { return Degrees{-degrees}; } + + constexpr Degrees operator+(Degrees d) const { + return Degrees{degrees + d.degrees}; + } + + constexpr Degrees operator-(Degrees d) const { + return Degrees{degrees - d.degrees}; + } + + constexpr bool operator>(Degrees d) { return degrees > d.degrees; } + + constexpr bool operator>=(Degrees d) { return degrees >= d.degrees; } + + constexpr bool operator==(Degrees d) { return degrees == d.degrees; } + + constexpr bool operator!=(Degrees d) { return degrees != d.degrees; } + + constexpr bool operator<=(Degrees d) { return degrees <= d.degrees; } + + constexpr bool operator<(Degrees d) { return degrees < d.degrees; } + + constexpr Degrees GetPositive() const { + Scalar deg = std::fmod(degrees, 360.0f); + if (deg < 0.0f) { + deg += 360.0f; + } + return Degrees{deg}; + } }; // NOLINTEND(google-explicit-constructor) } // namespace impeller +namespace std { + +inline std::ostream& operator<<(std::ostream& out, const impeller::Degrees& d) { + return out << "Degrees(" << d.degrees << ")"; +} + +inline std::ostream& operator<<(std::ostream& out, const impeller::Radians& r) { + return out << "Radians(" << r.radians << ")"; +} + +} // namespace std + #endif // FLUTTER_IMPELLER_GEOMETRY_SCALAR_H_ diff --git a/engine/src/flutter/impeller/tessellator/tessellator.cc b/engine/src/flutter/impeller/tessellator/tessellator.cc index e4c68b6dcd358..51dbff8e68e08 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator.cc +++ b/engine/src/flutter/impeller/tessellator/tessellator.cc @@ -11,6 +11,7 @@ namespace { static constexpr int kPrecomputedDivisionCount = 1024; + static int kPrecomputedDivisions[kPrecomputedDivisionCount] = { // clang-format off 1, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, @@ -435,6 +436,7 @@ Tessellator::Trigs Tessellator::GetTrigsForDivisions(size_t divisions) { using TessellatedVertexProc = Tessellator::TessellatedVertexProc; using EllipticalVertexGenerator = Tessellator::EllipticalVertexGenerator; +using ArcVertexGenerator = Tessellator::ArcVertexGenerator; EllipticalVertexGenerator::EllipticalVertexGenerator( EllipticalVertexGenerator::GeneratorProc& generator, @@ -484,6 +486,106 @@ EllipticalVertexGenerator Tessellator::StrokedCircle( } } +ArcVertexGenerator::ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + bool use_center, + bool supports_triangle_fans) + : iteration_(iteration), + trigs_(std::move(trigs)), + oval_bounds_(oval_bounds), + use_center_(use_center), + half_width_(-1.0f), + cap_(Cap::kButt), + supports_triangle_fans_(supports_triangle_fans) {} + +ArcVertexGenerator::ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + Scalar half_width, + Cap cap) + : iteration_(iteration), + trigs_(std::move(trigs)), + oval_bounds_(oval_bounds), + use_center_(false), + half_width_(half_width), + cap_(cap), + supports_triangle_fans_(false) {} + +PrimitiveType ArcVertexGenerator::GetTriangleType() const { + return (half_width_ < 0 && supports_triangle_fans_) + ? PrimitiveType::kTriangleFan + : PrimitiveType::kTriangleStrip; +} + +size_t ArcVertexGenerator::GetVertexCount() const { + size_t count = iteration_.GetPointCount(); + if (half_width_ > 0) { + FML_DCHECK(!use_center_); + FML_DCHECK(cap_ != Cap::kRound); + count *= 2; + if (cap_ == Cap::kSquare) { + count += 4; + } + } else if (supports_triangle_fans_) { + if (use_center_) { + count++; + } + } else { + // corrugated triangle fan + count += (count + 1) / 2; + } + return count; +} + +void ArcVertexGenerator::GenerateVertices( + const TessellatedVertexProc& proc) const { + if (half_width_ > 0) { + FML_DCHECK(!use_center_); + Tessellator::GenerateStrokedArc(trigs_, iteration_, oval_bounds_, + half_width_, cap_, proc); + } else if (supports_triangle_fans_) { + Tessellator::GenerateFilledArcFan(trigs_, iteration_, oval_bounds_, + use_center_, proc); + } else { + Tessellator::GenerateFilledArcStrip(trigs_, iteration_, oval_bounds_, + use_center_, proc); + } +} + +ArcVertexGenerator Tessellator::FilledArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool use_center, + bool supports_triangle_fans) { + size_t divisions = + ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * + oval_bounds.GetSize().MaxDimension()); + + return ArcVertexGenerator( + ComputeArcQuadrantIterations(divisions + 1, start, sweep), + GetTrigsForDivisions(divisions), oval_bounds, use_center, + supports_triangle_fans); +}; + +ArcVertexGenerator Tessellator::StrokedArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + Cap cap, + Scalar half_width) { + FML_DCHECK(half_width > 0); + FML_DCHECK(oval_bounds.IsSquare()); + size_t divisions = ComputeQuadrantDivisions( + view_transform.GetMaxBasisLengthXY() * + (oval_bounds.GetSize().MaxDimension() + half_width)); + + return ArcVertexGenerator( + ComputeArcQuadrantIterations(divisions + 1, start, sweep), + GetTrigsForDivisions(divisions), oval_bounds, half_width, cap); +} + EllipticalVertexGenerator Tessellator::RoundCapLine( const Matrix& view_transform, const Point& p0, @@ -578,7 +680,7 @@ void Tessellator::GenerateFilledCircle( // we can instead iterate forward and swap the x/y values of the // offset as the angles should be symmetric and thus should generate // symmetrically reversed trig vectors. - // Quadrant 2 connecting with Quadrant 2: + // Quadrant 2 connecting with Quadrant 3: for (auto& trig : trigs) { auto offset = trig * radius; proc({center.x + offset.y, center.y + offset.x}); @@ -641,6 +743,98 @@ void Tessellator::GenerateStrokedCircle( } } +void Tessellator::GenerateFilledArcFan(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc) { + Point center = oval_bounds.GetCenter(); + Size radii = oval_bounds.GetSize() * 0.5f; + + if (use_center) { + proc(center); + } + proc(center + iteration.start * radii); + for (size_t i = 0; i < iteration.quadrant_count; i++) { + auto quadrant = iteration.quadrants[i]; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + proc(center + trigs[j] * quadrant.axis * radii); + } + } + proc(center + iteration.end * radii); +} + +void Tessellator::GenerateFilledArcStrip(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc) { + Point center = oval_bounds.GetCenter(); + Size radii = oval_bounds.GetSize() * 0.5f; + + Point origin; + if (use_center) { + origin = center; + } else { + Point midpoint = (iteration.start + iteration.end) * 0.5f; + origin = center + midpoint * radii; + } + + proc(origin); + proc(center + iteration.start * radii); + bool insert_origin = false; + for (size_t i = 0; i < iteration.quadrant_count; i++) { + auto quadrant = iteration.quadrants[i]; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + if (insert_origin) { + proc(origin); + } + insert_origin = !insert_origin; + proc(center + trigs[j] * quadrant.axis * radii); + } + } + if (insert_origin) { + proc(origin); + } + proc(center + iteration.end * radii); +} + +void Tessellator::GenerateStrokedArc(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + Scalar half_width, + Cap cap, + const TessellatedVertexProc& proc) { + Point center = oval_bounds.GetCenter(); + Size base_radii = oval_bounds.GetSize() * 0.5f; + Size inner_radii = base_radii - Size(half_width, half_width); + Size outer_radii = base_radii + Size(half_width, half_width); + + FML_DCHECK(cap != Cap::kRound); + if (cap == Cap::kSquare) { + Vector2 offset = + Vector2{iteration.start.y, -iteration.start.x} * half_width; + proc(center + iteration.start * inner_radii + offset); + proc(center + iteration.start * outer_radii + offset); + } + proc(center + iteration.start * inner_radii); + proc(center + iteration.start * outer_radii); + for (size_t i = 0; i < iteration.quadrant_count; i++) { + auto quadrant = iteration.quadrants[i]; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + proc(center + trigs[j] * quadrant.axis * inner_radii); + proc(center + trigs[j] * quadrant.axis * outer_radii); + } + } + proc(center + iteration.end * inner_radii); + proc(center + iteration.end * outer_radii); + if (cap == Cap::kSquare) { + Vector2 offset = Vector2{-iteration.end.y, iteration.end.x} * half_width; + proc(center + iteration.end * inner_radii + offset); + proc(center + iteration.end * outer_radii + offset); + } +} + void Tessellator::GenerateRoundCapLine( const Trigs& trigs, const EllipticalVertexGenerator::Data& data, @@ -734,4 +928,103 @@ void Tessellator::GenerateFilledRoundRect( } } +const Tessellator::ArcIteration Tessellator::ComputeCircleArcIterations( + size_t count) { + return { + {1.0f, 0.0f}, + {1.0f, 0.0f}, + 4u, + { + {kQuadrantAxes[0], 1u, count}, + {kQuadrantAxes[1], 0u, count}, + {kQuadrantAxes[2], 0u, count}, + {kQuadrantAxes[3], 0u, count}, + {{}, 0u, 0u}, + }, + }; +} + +Tessellator::ArcIteration Tessellator::ComputeArcQuadrantIterations( + size_t trig_size, + Degrees start, + Degrees sweep) { + if (sweep.degrees == 0 || !start.IsFinite() || !sweep.IsFinite()) { + return {}; + } + + if (sweep.degrees < 0) { + start = start + sweep; + sweep = -sweep; + } + + size_t steps = trig_size - 1; + + if (sweep.degrees >= 360) { + return ComputeCircleArcIterations(steps); + } + + start = start.GetPositive(); + Degrees end = start + sweep; + FML_DCHECK(start.degrees >= 0.0f && start.degrees < 360.0f); + FML_DCHECK(end >= start && end.degrees < start.degrees + 360.0f); + + ArcIteration iterations; + iterations.start = impeller::Matrix::CosSin(start); + iterations.end = impeller::Matrix::CosSin(end); + + // We nudge the start and stop by 1/10th of a step so we don't end + // up with degenerately small steps at the start and end of the + // arc. + Degrees nudge = Degrees((90.0f / steps) * 0.1f); + + if ((start + nudge) >= (end - nudge)) { + iterations.quadrant_count = 0u; + return iterations; + } + + int cur_quadrant = + static_cast(std::floor((start + nudge).degrees / 90.0f)); + int end_quadrant = + static_cast(std::floor((end - nudge).degrees / 90.0f)); + FML_DCHECK(cur_quadrant >= 0 && // + cur_quadrant <= 4); + FML_DCHECK(end_quadrant >= cur_quadrant && // + end_quadrant <= cur_quadrant + 4); + FML_DCHECK(cur_quadrant * 90 <= (start + nudge).degrees); + FML_DCHECK(end_quadrant * 90 + 90 >= (end - nudge).degrees); + + auto next_step = [steps](Degrees angle, int quadrant) -> size_t { + Scalar quadrant_fract = angle.degrees / 90.0f - quadrant; + return static_cast(std::ceil(quadrant_fract * steps)); + }; + + int i = 0; + iterations.quadrants[i] = { + kQuadrantAxes[cur_quadrant & 3], + next_step(start + nudge, cur_quadrant), + steps, + }; + if (iterations.quadrants[0].end_index > iterations.quadrants[0].start_index) { + i++; + } + while (cur_quadrant < end_quadrant) { + iterations.quadrants[i++] = { + kQuadrantAxes[(++cur_quadrant) % 4], + 0u, + steps, + }; + } + FML_DCHECK(i <= 5); + if (i > 0) { + iterations.quadrants[i - 1].end_index = + next_step(end - nudge, cur_quadrant); + if (iterations.quadrants[i - 1].end_index <= + iterations.quadrants[i - 1].start_index) { + i--; + } + } + iterations.quadrant_count = i; + return iterations; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/tessellator/tessellator.h b/engine/src/flutter/impeller/tessellator/tessellator.h index 6cf408d6e8c14..fe72e692de1ad 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator.h +++ b/engine/src/flutter/impeller/tessellator/tessellator.h @@ -14,11 +14,13 @@ #include "impeller/core/vertex_buffer.h" #include "impeller/geometry/path_source.h" #include "impeller/geometry/point.h" +#include "impeller/geometry/stroke_parameters.h" #include "impeller/geometry/trig.h" namespace impeller { /// The size of the point arena buffer stored on the tessellator. +[[maybe_unused]] static constexpr size_t kPointArenaSize = 4096u; //------------------------------------------------------------------------------ @@ -181,6 +183,116 @@ class Tessellator { Data&& data); }; + /// A structure to describe the iteration through a set of angle vectors + /// in a |Trigs| structure to render the points along an arc. The start + /// and end vectors and each iteration's axis vector are all unit vectors + /// that point in the direction of the point on the circle to be emitted. + /// + /// Each vector should be rendered by multiplying it by the radius of the + /// circle, or in the case of a stroked arc, by the inner and outer radii + /// of the sides of the stroke. + /// + /// - The start vector will always be rendered first. + /// - Then each quadrant will be iterated by composing the trigs vectors + /// with the given axis vector, iterating from the start index (inclusive) + /// to the end index (exclusive) of the vector of |Trig| values. + /// - Finally the end vector will be rendered. + /// For example: + /// Insert(arc_iteration.start * radius); + /// for (size_t i = 0u, i < arc_iteration.iteration_count; i++) { + /// Quadrant quadrant = arc_iteration.quadrants[i]; + /// for (j = quadrant.start_index; j < quadrant.end_index; j++) { + /// Insert(quadrant.axis * trigs[j] * radius); + /// } + /// } + /// Insert(arc_iteration.end * radius); + /// + /// The rendering routine may adjust the manner/order in which those vertices + /// are inserted into the vertex buffer to optimally match the vertex triangle + /// mode it plans to use, but the description above represents the basic + /// technique to compute the points along the actual curve. + struct ArcIteration { + // The axis to multiply by each |Trig| value and the half-open [start, end) + // range of the |Trig| vector over which to compute. + struct Quadrant { + impeller::Vector2 axis; + size_t start_index = 0u; + size_t end_index = 0u; + + size_t GetPointCount() const { + FML_DCHECK(start_index < end_index); + return end_index - start_index; + } + }; + + // The true begin and end angles of the arc, expressed as unit direction + // vectors. + impeller::Vector2 start; + impeller::Vector2 end; + + // The variable number of quadrants that have to be iterated and + // cross-referenced with values in a |Trigs| object. + size_t quadrant_count = 0u; + // We can have at most 5 |Quadrant| entries when an arc starts and ends in + // the same circle quadrant with the start point later in the quadrant + // than the end point. + // + // Worst case: + // - First iteration goes from the start angle to the end of that quadrant. + // - Then 3 full iterations for the 3 other full quarter circles. + // - Then a last iteration that goes from the start of that quadrant to the + // end angle. + // + // We can also have 0 quadrants for arcs that are smaller than the + // step size of the pixel-radius |Trigs| vector. + Quadrant quadrants[5]; + + size_t GetPointCount() const { + size_t count = 2; + for (size_t i = 0; i < quadrant_count; i++) { + count += quadrants[i].GetPointCount(); + } + return count; + } + }; + + /// @brief The |VertexGenerator| implementation common to all shapes + /// that are based on a polygonal representation of an ellipse. + class ArcVertexGenerator : public virtual VertexGenerator { + public: + /// |VertexGenerator| + PrimitiveType GetTriangleType() const override; + + /// |VertexGenerator| + size_t GetVertexCount() const override; + + /// |VertexGenerator| + void GenerateVertices(const TessellatedVertexProc& proc) const override; + + private: + friend class Tessellator; + + const ArcIteration iteration_; + const Trigs trigs_; + const Rect oval_bounds_; + const bool use_center_; + const Scalar half_width_; + const Cap cap_; + const bool supports_triangle_fans_; + + ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + bool use_center, + bool supports_triangle_fans); + + ArcVertexGenerator(const ArcIteration& iteration, + Trigs&& trigs, + const Rect& oval_bounds, + Scalar half_width, + Cap cap); + }; + Tessellator(); virtual ~Tessellator(); @@ -250,6 +362,44 @@ class Tessellator { Scalar radius, Scalar half_width); + /// @brief Create a |VertexGenerator| that can produce vertices for + /// a stroked arc inscribed within the given oval_bounds with + /// the given stroke half_width with enough polygon sub-divisions + /// to provide reasonable fidelity when viewed under the given + /// view transform. The outer edge of the stroked arc is + /// generated at (radius + half_width) and the inner edge is + /// generated at (radius - half_width). + /// + /// Note that the view transform is only used to choose the + /// number of sample points to use per quarter circle and the + /// returned points are not transformed by it, instead they are + /// relative to the coordinate space of the oval bounds. + ArcVertexGenerator FilledArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + bool use_center, + bool supports_triangle_fans); + + /// @brief Create a |VertexGenerator| that can produce vertices for + /// a stroked arc inscribed within the given oval_bounds with + /// the given stroke half_width with enough polygon sub-divisions + /// to provide reasonable fidelity when viewed under the given + /// view transform. The outer edge of the stroked arc is + /// generated at (radius + half_width) and the inner edge is + /// generated at (radius - half_width). + /// + /// Note that the view transform is only used to choose the + /// number of sample points to use per quarter circle and the + /// returned points are not transformed by it, instead they are + /// relative to the coordinate space of the oval bounds. + ArcVertexGenerator StrokedArc(const Matrix& view_transform, + const Rect& oval_bounds, + Degrees start, + Degrees sweep, + Cap cap, + Scalar half_width); + /// @brief Create a |VertexGenerator| that can produce vertices for /// a line with round end caps of the given radius with enough /// polygon sub-divisions to provide reasonable fidelity when @@ -296,6 +446,10 @@ class Tessellator { /// circle quadrant of the specified pixel radius Trigs GetTrigsForDeviceRadius(Scalar pixel_radius); + static ArcIteration ComputeArcQuadrantIterations(size_t trig_count, + impeller::Degrees start, + impeller::Degrees sweep); + protected: /// Used for polyline generation. std::unique_ptr> point_buffer_; @@ -320,6 +474,25 @@ class Tessellator { const EllipticalVertexGenerator::Data& data, const TessellatedVertexProc& proc); + static void GenerateFilledArcFan(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc); + + static void GenerateFilledArcStrip(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + bool use_center, + const TessellatedVertexProc& proc); + + static void GenerateStrokedArc(const Trigs& trigs, + const ArcIteration& iteration, + const Rect& oval_bounds, + Scalar half_width, + Cap cap, + const TessellatedVertexProc& proc); + static void GenerateRoundCapLine(const Trigs& trigs, const EllipticalVertexGenerator::Data& data, const TessellatedVertexProc& proc); @@ -333,6 +506,8 @@ class Tessellator { const EllipticalVertexGenerator::Data& data, const TessellatedVertexProc& proc); + static const ArcIteration ComputeCircleArcIterations(size_t count); + Tessellator(const Tessellator&) = delete; Tessellator& operator=(const Tessellator&) = delete; diff --git a/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc b/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc index 9ebd50d550d0b..159e839a0d8d5 100644 --- a/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc +++ b/engine/src/flutter/impeller/tessellator/tessellator_unittests.cc @@ -526,5 +526,268 @@ TEST(TessellatorTest, EarlyReturnEmptyConvexShape) { EXPECT_TRUE(indices.empty()); } +namespace { + +// Tests the basic relationships of the angles iterated according to the +// rules of the ArcIteration struct. Each step iterated should be just +// about the same angular distance from the previous step, computed using +// the Cross product of the adjacent vectors, which should be the same as +// the sine of the angle between them when using unit vectors. +// +// Special support for shorter starting and ending steps to bridge the gap +// from the true arc start and the true arc end and the first and last +// angles iterated from the trigs. +void TestArcIterator(const impeller::Tessellator::ArcIteration arc_iteration, + const impeller::Tessellator::Trigs& trigs, + Degrees start, + Degrees sweep, + const std::string& label) { + EXPECT_POINT_NEAR(arc_iteration.start, impeller::Matrix::CosSin(start)) + << label; + EXPECT_POINT_NEAR(arc_iteration.end, impeller::Matrix::CosSin(start + sweep)) + << label; + if (arc_iteration.quadrant_count == 0u) { + // There is just the begin and end angle and there are no constraints + // on how far apart they should be, but the end vector should be + // non-counterclockwise from the start vector. + EXPECT_GE(arc_iteration.start.Cross(arc_iteration.end), 0.0f); + return; + } + + const size_t steps = trigs.size() - 1; + const Scalar step_angle = kPiOver2 / steps; + + // The first and last steps are allowed to be from 0.1 to 1.1 in size + // as we don't want to iterate an extra step that is less than 0.1 steps + // from the begin/end angles. We use min/max values that are ever so + // slightly larger than that to avoid round-off errors. + const Scalar edge_min_cross = std::sin(step_angle * 0.099f); + const Scalar edge_max_cross = std::sin(step_angle * 1.101f); + const Scalar typical_min_cross = std::sin(step_angle * 0.999f); + const Scalar typical_max_cross = std::sin(step_angle * 1.001f); + + Vector2 cur_vector; + auto trace = [&cur_vector](Vector2 vector, Scalar min_cross, Scalar max_cross, + const std::string& label) -> void { + EXPECT_GT(cur_vector.Cross(vector), min_cross) << label; + EXPECT_LT(cur_vector.Cross(vector), max_cross) << label; + cur_vector = vector; + }; + + // The first edge encountered in the loop should be judged by the edge + // conditions. After that the steps derived from the Trigs should be + // judged by the typical min/max values. + Scalar min_cross = edge_min_cross; + Scalar max_cross = edge_max_cross; + + cur_vector = arc_iteration.start; + for (size_t i = 0; i < arc_iteration.quadrant_count; i++) { + auto& quadrant = arc_iteration.quadrants[i]; + EXPECT_LT(quadrant.start_index, quadrant.end_index) + << label << ", quadrant: " << i; + for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) { + trace(trigs[j] * quadrant.axis, min_cross, max_cross, + label + ", quadrant: " + std::to_string(i) + + ", step: " + std::to_string(j)); + // At this point we can guarantee that we've already used the initial + // min/max values, now replace them with the typical values. + min_cross = typical_min_cross; + max_cross = typical_max_cross; + } + } + + // The jump to the end angle should be judged by the edge conditions. + trace(arc_iteration.end, edge_min_cross, edge_max_cross, + label + " step to end"); +} + +void TestFullCircleArc(Degrees start, Degrees sweep) { + auto label = + std::to_string(start.degrees) + " += " + std::to_string(sweep.degrees); + + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + size_t steps = trigs.size() - 1; + const auto& arc_iteration = + impeller::Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, + sweep); + + EXPECT_EQ(arc_iteration.start, Vector2(1.0f, 0.0f)) << label; + EXPECT_EQ(arc_iteration.quadrant_count, 4u) << label; + EXPECT_EQ(arc_iteration.quadrants[0].axis, Vector2(1.0f, 0.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[0].start_index, 1u) << label; + EXPECT_EQ(arc_iteration.quadrants[0].end_index, steps) << label; + EXPECT_EQ(arc_iteration.quadrants[1].axis, Vector2(0.0f, 1.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[1].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[1].end_index, steps) << label; + EXPECT_EQ(arc_iteration.quadrants[2].axis, Vector2(-1.0f, 0.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[2].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[2].end_index, steps) << label; + EXPECT_EQ(arc_iteration.quadrants[3].axis, Vector2(0.0f, -1.0f)) << label; + EXPECT_EQ(arc_iteration.quadrants[3].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[3].end_index, steps) << label; + EXPECT_EQ(arc_iteration.end, Vector2(1.0f, 0.0f)) << label; + + // For full circle arcs the original start and sweep are ignored and it + // returns an iterator that always goes from 0->360. + TestArcIterator(arc_iteration, trigs, Degrees(0), Degrees(360), + "Full Circle(" + label + ")"); +} + +} // namespace + +TEST(TessellatorTest, ArcIterationsFullCircle) { + // Anything with a sweep <=-360 or >=360 is a full circle regardless of + // starting angle + for (int start = -720; start < 720; start += 30) { + for (int sweep = 360; sweep < 1080; sweep += 45) { + TestFullCircleArc(Degrees(start), Degrees(sweep)); + TestFullCircleArc(Degrees(start), Degrees(-sweep)); + } + } +} + +namespace { +static void CheckOneQuadrant(Degrees start, Degrees sweep) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + + EXPECT_POINT_NEAR(arc_iteration.start, Matrix::CosSin(start)); + EXPECT_EQ(arc_iteration.quadrant_count, 1u); + EXPECT_POINT_NEAR(arc_iteration.end, Matrix::CosSin(start + sweep)); + + std::string label = "Quadrant(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees) + ")"; + TestArcIterator(arc_iteration, trigs, start, sweep, label); +} +} // namespace + +TEST(TessellatorTest, ArcIterationsVariousStartAnglesNearQuadrantAxis) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const Degrees sweep(45); + + for (int start_i = -1000; start_i < 1000; start_i += 5) { + Scalar start_degrees = start_i * 0.01f; + for (int quadrant = -360; quadrant <= 360; quadrant += 90) { + const Degrees start(quadrant + start_degrees); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Various angles(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees)); + } + } +} + +TEST(TessellatorTest, ArcIterationsVariousEndAnglesNearQuadrantAxis) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + + for (int sweep_i = 5; sweep_i < 20000; sweep_i += 5) { + const Degrees sweep(sweep_i * 0.01f); + for (int quadrant = -360; quadrant <= 360; quadrant += 90) { + const Degrees start(quadrant + 80); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Various angles(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees)); + } + } +} + +TEST(TessellatorTest, ArcIterationsVariousTinyArcsNearQuadrantAxis) { + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const Degrees sweep(0.1f); + + for (int start_i = -1000; start_i < 1000; start_i += 5) { + Scalar start_degrees = start_i * 0.01f; + for (int quadrant = -360; quadrant <= 360; quadrant += 90) { + const Degrees start(quadrant + start_degrees); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + ASSERT_EQ(arc_iteration.quadrant_count, 0u); + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Various angles(" + std::to_string(start.degrees) + + " += " + std::to_string(sweep.degrees)); + } + } +} + +TEST(TessellatorTest, ArcIterationsOnlyFirstQuadrant) { + CheckOneQuadrant(Degrees(90 * 0 + 30), Degrees(30)); +} + +TEST(TessellatorTest, ArcIterationsOnlySecondQuadrant) { + CheckOneQuadrant(Degrees(90 * 1 + 30), Degrees(30)); +} + +TEST(TessellatorTest, ArcIterationsOnlyThirdQuadrant) { + CheckOneQuadrant(Degrees(90 * 2 + 30), Degrees(30)); +} + +TEST(TessellatorTest, ArcIterationsOnlyFourthQuadrant) { + CheckOneQuadrant(Degrees(90 * 3 + 30), Degrees(30)); +} + +namespace { +static void CheckFiveQuadrants(Degrees start, Degrees sweep) { + std::string label = + std::to_string(start.degrees) + " += " + std::to_string(sweep.degrees); + + Tessellator tessellator; + const auto trigs = tessellator.GetTrigsForDeviceRadius(100); + const auto& arc_iteration = + Tessellator::ComputeArcQuadrantIterations(trigs.size(), start, sweep); + size_t steps = trigs.size() - 1; + + EXPECT_POINT_NEAR(arc_iteration.start, Matrix::CosSin(start)) << label; + EXPECT_EQ(arc_iteration.quadrant_count, 5u) << label; + + // quadrant 0 start index depends on angle + EXPECT_EQ(arc_iteration.quadrants[0].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[1].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[1].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[2].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[2].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[3].start_index, 0u) << label; + EXPECT_EQ(arc_iteration.quadrants[3].end_index, steps) << label; + + EXPECT_EQ(arc_iteration.quadrants[4].start_index, 0u) << label; + // quadrant 4 end index depends on angle + + EXPECT_POINT_NEAR(arc_iteration.end, Matrix::CosSin(start + sweep)) << label; + + TestArcIterator(arc_iteration, trigs, start, sweep, + "Five quadrants(" + label + ")"); +} +} // namespace + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromFirst) { + CheckFiveQuadrants(Degrees(90 * 0 + 60), Degrees(330)); +} + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromSecond) { + CheckFiveQuadrants(Degrees(90 * 1 + 60), Degrees(330)); +} + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromThird) { + CheckFiveQuadrants(Degrees(90 * 2 + 60), Degrees(330)); +} + +TEST(TessellatorTest, ArcIterationsAllQuadrantsFromFourth) { + CheckFiveQuadrants(Degrees(90 * 3 + 60), Degrees(330)); +} + } // namespace testing } // namespace impeller From 99f74987aa46022c56f2b6d4cf9ae364cc3dc667 Mon Sep 17 00:00:00 2001 From: "auto-submit[bot]" <98614782+auto-submit[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 23:35:47 +0000 Subject: [PATCH 58/66] Reverts "Remove legacy platforms in `.ci.yaml` with 0 usages. (#169783)" (#169799) Reverts: flutter/flutter#169783 Initiated by: gaaclarke Reason for reverting: breaks `Linux ci_yaml flutter roller` https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20ci_yaml%20flutter%20roller/19333/overview Original PR Author: matanlurey Reviewed By: {zanderso} This change reverts the following previous change: No description provided. Co-authored-by: auto-submit[bot] --- .ci.yaml | 66 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 51d0f4ac24f11..5213230dc5157 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -26,7 +26,6 @@ platform_properties: cores: "8" device_type: none ignore_flakiness: "true" - linux: properties: dependencies: >- @@ -36,7 +35,6 @@ platform_properties: os: Ubuntu cores: "8" device_type: none - # The current android emulator config names can be found here: # https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/android/avd/proto # You may use those names for the android_virtual_device version. You may find the @@ -60,7 +58,6 @@ platform_properties: cores: "8" device_type: none kvm: "1" - # linux_android_emu_unstable is intended to be how flutter-android proves the stability # of new combinations of dependencies. linux_android_emu_unstable: @@ -80,7 +77,6 @@ platform_properties: cores: "8" device_type: none kvm: "1" - linux_build_test: properties: dependencies: >- @@ -92,6 +88,16 @@ platform_properties: os: Ubuntu cores: "8" device_type: none + linux_android: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:36v1"}, + {"dependency": "open_jdk", "version": "version:21"}, + {"dependency": "curl", "version": "version:7.64.0"} + ] + os: Linux + device_type: "msm8952" linux_pixel_7pro: properties: @@ -142,7 +148,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_arm64: properties: contexts: >- @@ -160,7 +165,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_benchmark: properties: contexts: >- @@ -180,7 +184,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_x64: properties: contexts: >- @@ -198,7 +201,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_build_test: properties: contexts: >- @@ -217,6 +219,27 @@ platform_properties: { "sdk_version": "16c5032a" } + mac_android: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:36v1"}, + {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, + {"dependency": "open_jdk", "version": "version:21"} + ] + os: Mac-14|Mac-15.5 + cpu: x86 + device_type: "msm8952" + mac_arm64_android: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:36v1"}, + {"dependency": "open_jdk", "version": "version:21"} + ] + os: Mac-14|Mac-15.5 + cpu: arm64 + device_type: "msm8952" mac_mokey: properties: @@ -229,7 +252,6 @@ platform_properties: os: Mac-14|Mac-15.5 cpu: x86 device_type: "mokey" - mac_arm64_mokey: properties: dependencies: >- @@ -241,6 +263,16 @@ platform_properties: cpu: arm64 device_type: "mokey" + mac_pixel_7pro: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:36v1"}, + {"dependency": "open_jdk", "version": "version:21"} + ] + os: Mac-14|Mac-15.5 + cpu: x86 + device_type: "Pixel 7 Pro" mac_ios: properties: contexts: >- @@ -258,7 +290,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_x64_ios: properties: contexts: >- @@ -277,7 +308,6 @@ platform_properties: { "sdk_version": "16c5032a" } - mac_arm64_ios: properties: contexts: >- @@ -296,18 +326,26 @@ platform_properties: { "sdk_version": "16c5032a" } - windows: properties: os: Windows-10 device_type: none - windows_arm64: properties: + # The arch can be removed after https://github.com/flutter/flutter/issues/135722. arch: arm os: Windows cpu: arm64 - + windows_android: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:36v1"}, + {"dependency": "chrome_and_driver", "version": "version:125.0.6422.141"}, + {"dependency": "open_jdk", "version": "version:21"} + ] + os: Windows-10 + device_type: "msm8952" windows_mokey: properties: dependencies: >- From bcfb87134b040726f7106da6708048d910733138 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Fri, 30 May 2025 19:14:31 -0500 Subject: [PATCH 59/66] [web] Pass the same JS flags to both stages of the compiler (#169730) Fixes https://github.com/flutter/flutter/issues/169714 --- .../lib/src/build_system/targets/web.dart | 6 +- .../lib/src/web/compiler_config.dart | 11 +- .../hermetic/build_web_test.dart | 2 +- .../build_system/targets/web_test.dart | 447 +++++++----------- 4 files changed, 191 insertions(+), 275 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart index e6775432fcf73..cebed01c44e65 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/web.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart @@ -181,7 +181,8 @@ class Dart2JSTarget extends Dart2WebTarget { for (final String dartDefine in computeDartDefines(environment)) '-D$dartDefine', ]; - final List compilationArgs = [ + // NOTE: most args should be populated in [toSharedCommandOptions]. + final List cfeCompilationArgs = [ ...sharedCommandOptions, ...compilerConfig.toSharedCommandOptions(buildMode), '-o', @@ -198,7 +199,7 @@ class Dart2JSTarget extends Dart2WebTarget { // Run the dart2js compilation in two stages, so that icon tree shaking can // parse the kernel file for web builds. - await processUtils.run(compilationArgs, throwOnError: true); + await processUtils.run(cfeCompilationArgs, throwOnError: true); final File outputJSFile = environment.buildDir.childFile('main.dart.js'); @@ -337,7 +338,6 @@ class Dart2WasmTarget extends Dart2WebTarget { ...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions), for (final String dartDefine in dartDefines) '-D$dartDefine', '--extra-compiler-option=--depfile=${depFile.path}', - ...compilerConfig.toCommandOptions(buildMode), '-o', outputWasmFile.path, diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart index a0f1610a3d281..aeb19c7de3070 100644 --- a/packages/flutter_tools/lib/src/web/compiler_config.dart +++ b/packages/flutter_tools/lib/src/web/compiler_config.dart @@ -93,11 +93,16 @@ class JsCompilerConfig extends WebCompilerConfig { CompileTarget get compileTarget => CompileTarget.js; /// Arguments to use in both phases: full JS compile and CFE-only. + /// + /// NOTE: MOST args should be passed here! List toSharedCommandOptions(BuildMode buildMode) => [ if (nativeNullAssertions) '--native-null-assertions', if (!sourceMaps) '--no-source-maps', if (buildMode == BuildMode.debug) '--enable-asserts', '-O${optimizationLevelForBuildMode(buildMode)}', + if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', + if (noFrequencyBasedMinification) '--no-frequency-based-minification', + if (csp) '--csp', ]; @override @@ -113,14 +118,12 @@ class JsCompilerConfig extends WebCompilerConfig { /// Arguments to use in the full JS compile, but not CFE-only. /// - /// Includes the contents of [toSharedCommandOptions]. + /// Includes the contents of [toSharedCommandOptions]. That is where MOST + /// JS compiler flags should be passed! @override List toCommandOptions(BuildMode buildMode) => [ - if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', ...toSharedCommandOptions(buildMode), if (dumpInfo) '--stage=dump-info-all', - if (noFrequencyBasedMinification) '--no-frequency-based-minification', - if (csp) '--csp', ]; @override diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart index 82f20eba8d534..e67b699fbf1da 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart @@ -425,10 +425,10 @@ void main() { expect(config.compileTarget, CompileTarget.js); final List options = config.toCommandOptions(BuildMode.release); expect(options, [ - '--minify', '--native-null-assertions', '--no-source-maps', '-O4', + '--minify', ]); }), }, diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index 03cdbc85af4cf..8033697e59d0b 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -32,6 +32,12 @@ const List _kDart2jsLinuxArgs = [ '--invoker=flutter_tool', ]; +const List _kStandardFlutterWebDefines = [ + '-DFLUTTER_WEB_USE_SKIA=true', + '-DFLUTTER_WEB_USE_SKWASM=false', + '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', +]; + const List _kDart2WasmLinuxArgs = [ 'Artifact.engineDartBinary.TargetPlatform.web_javascript', 'compile', @@ -514,17 +520,20 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with csp', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '--csp', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -535,16 +544,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '--csp', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -559,16 +559,18 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with minify false', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -579,14 +581,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -602,17 +597,19 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; environment.defines[kFrontendServerStarterPath] = 'path/to/frontend_server_starter.dart'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -623,15 +620,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -647,18 +636,20 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; environment.defines[kExtraFrontEndOptions] = '--enable-experiment=non-nullable'; + final List common = [ + ..._kDart2jsLinuxArgs, + '--enable-experiment=non-nullable', + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '--enable-experiment=non-nullable', - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -669,16 +660,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '--enable-experiment=non-nullable', - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -693,17 +675,19 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in profile mode', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -714,15 +698,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -737,17 +713,19 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in release mode', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -758,15 +736,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -781,18 +751,20 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in release mode with native null assertions', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--native-null-assertions', + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--native-null-assertions', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -803,16 +775,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--native-null-assertions', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -829,17 +792,19 @@ name: foo 'Dart2JSTarget calls dart2js with expected args in release with dart2js optimization override', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O3', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O3', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -850,15 +815,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O3', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -875,17 +832,19 @@ name: foo 'Dart2JSTarget produces expected depfile', () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -899,15 +858,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -934,19 +885,21 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; environment.defines[kDartDefines] = encodeDartDefines(['FOO=bar', 'BAZ=qux']); + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + '-DFOO=bar', + '-DBAZ=qux', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -957,17 +910,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -983,16 +926,18 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'release'; environment.defines[WebCompilerConfig.kSourceMapsEnabled] = 'true'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.product=true', + ..._kStandardFlutterWebDefines, + '-O4', + '--minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1003,14 +948,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.product=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--minify', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -1026,19 +964,21 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; environment.defines[kDartDefines] = encodeDartDefines(['FOO=bar', 'BAZ=qux']); + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + '-DFOO=bar', + '-DBAZ=qux', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1049,17 +989,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -1075,19 +1005,21 @@ name: foo () => testbed.run(() async { environment.defines[kBuildMode] = 'debug'; environment.defines[kDartDefines] = encodeDartDefines(['FOO=bar', 'BAZ=qux']); + final List common = [ + ..._kDart2jsLinuxArgs, + '-DFOO=bar', + '-DBAZ=qux', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '--enable-asserts', + '-O1', + '--no-minify', + '-o', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '--enable-asserts', - '-O1', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1098,17 +1030,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-DFOO=bar', - '-DBAZ=qux', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '--enable-asserts', - '-O1', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], @@ -1123,16 +1045,18 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with dump-info', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + ]; processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', + ...common, '-o', environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', @@ -1144,14 +1068,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', + ...common, '--stage=dump-info-all', '-o', environment.buildDir.childFile('main.dart.js').absolute.path, @@ -1170,17 +1087,22 @@ name: foo 'Dart2JSTarget calls dart2js with expected args with no-frequency-based-minification', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; + + final List common = [ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + ..._kStandardFlutterWebDefines, + '--no-source-maps', + '-O4', + '--no-minify', + '--no-frequency-based-minification', + '-o', + ]; + processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-source-maps', - '-O4', - '-o', + ...common, environment.buildDir.childFile('app.dill').absolute.path, '--packages=/.dart_tool/package_config.json', '--cfe-only', @@ -1191,16 +1113,7 @@ name: foo processManager.addCommand( FakeCommand( command: [ - ..._kDart2jsLinuxArgs, - '-Ddart.vm.profile=true', - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--no-minify', - '--no-source-maps', - '-O4', - '--no-frequency-based-minification', - '-o', + ...common, environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, ], From 677e56256074f3f70b61ea911de0cff0e33c1343 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 30 May 2025 17:16:20 -0700 Subject: [PATCH 60/66] [ios]: Warning for FlutterAppDelegate.window.rootViewController in launch functions (#169166) fixes https://github.com/flutter/flutter/issues/169218 ## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> --- packages/flutter_tools/bin/xcode_backend.dart | 9 ++ .../lib/src/build_system/targets/ios.dart | 127 +++++++++++++++++- packages/flutter_tools/lib/src/ios/mac.dart | 21 +++ .../flutter_tools/lib/src/xcode_project.dart | 4 + .../build_system/targets/ios_test.dart | 81 +++++++++++ 5 files changed, 241 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index e8b83e1ebb547..72f69d15f763f 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -128,6 +128,15 @@ class Context { } errorOutput.write(resultStderr); echoError(errorOutput.toString()); + + // Stream stderr to the Flutter build process. + // When in verbose mode, `echoError` above will show the logs. So only + // stream if not in verbose mode to avoid duplicate logs. + // Also, only stream if exitCode is 0 since errors are handled separately + // by the tool on failure. + if (!verbose && exitCode == 0) { + streamOutput(errorOutput.toString()); + } } if (!allowFail && result.exitCode != 0) { throw Exception('Command "$bin ${args.join(' ')}" exited with code ${result.exitCode}'); diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index 8d0c6a80dae19..ac7234a196761 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -10,6 +10,7 @@ import '../../base/build.dart'; import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; +import '../../base/logger.dart' show Logger; import '../../base/process.dart'; import '../../base/version.dart'; import '../../build_info.dart'; @@ -365,6 +366,126 @@ class DebugUnpackIOS extends UnpackIOS { BuildMode get buildMode => BuildMode.debug; } +// TODO(gaaclarke): Remove this after a reasonable amount of time where the +// UISceneDelegate migration being on stable. This incurs a minor build time +// cost. +Future _checkForLaunchRootViewControllerAccessDeprecation( + Logger logger, + File file, + Pattern usage, + Pattern terminator, +) async { + final List lines = file.readAsLinesSync(); + + bool inDidFinishLaunchingWithOptions = false; + int lineNumber = 0; + for (final String line in lines) { + lineNumber += 1; + if (!inDidFinishLaunchingWithOptions) { + if (line.contains('didFinishLaunchingWithOptions')) { + inDidFinishLaunchingWithOptions = true; + } + } else { + if (line.startsWith(terminator)) { + inDidFinishLaunchingWithOptions = false; + } else if (line.contains(usage)) { + _printWarning( + logger, + file.path, + lineNumber, + // TODO(gaaclarke): Add a link to the migration guide when it's written. + 'Flutter deprecation: Accessing rootViewController in `application:didFinishLaunchingWithOptions:` [flutter-launch-rootvc].\n' + '\tnote: \n' // The space after `note:` is meaningful, it is required associate the note with the warning in Xcode. + '\tAfter the UISceneDelegate migration the `UIApplicationDelegate.window` and ' + '`UIWindow.rootViewController` properties will not be set in ' + '`application:didFinishLaunchingWithOptions:`. If you are relying on that ' + 'in order to register platform channels at application launch use the ' + '`FlutterPluginRegistry` API instead. Other setup can be moved to a ' + 'FlutterViewController subclass (ex: `awakeFromNib`).', + ); + } + } + } +} + +/// Checks [file] representing objc code for deprecated usage of the +/// rootViewController and writes it to [logger]. +@visibleForTesting +Future checkForLaunchRootViewControllerAccessDeprecationObjc(Logger logger, File file) async { + try { + await _checkForLaunchRootViewControllerAccessDeprecation( + logger, + file, + RegExp('self.*?window.*?rootViewController'), + RegExp('^}'), + ); + // ignore: avoid_catches_without_on_clauses + } catch (_) {} +} + +/// Checks [file] representing swift code for deprecated usage of the +/// rootViewController and writes it to [logger]. +@visibleForTesting +Future checkForLaunchRootViewControllerAccessDeprecationSwift( + Logger logger, + File file, +) async { + try { + await _checkForLaunchRootViewControllerAccessDeprecation( + logger, + file, + 'window?.rootViewController', + RegExp(r'^.*?func\s*?\S*?\('), + ); + // ignore: avoid_catches_without_on_clauses + } catch (_) {} +} + +void _printWarning(Logger logger, String path, int line, String warning) { + logger.printWarning('$path:$line: warning: $warning'); +} + +class _IssueLaunchRootViewControllerAccess extends Target { + const _IssueLaunchRootViewControllerAccess(); + + @override + Future build(Environment environment) async { + final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir); + if (flutterProject.ios.appDelegateSwift.existsSync()) { + await checkForLaunchRootViewControllerAccessDeprecationSwift( + environment.logger, + flutterProject.ios.appDelegateSwift, + ); + } + if (flutterProject.ios.appDelegateObjc.existsSync()) { + await checkForLaunchRootViewControllerAccessDeprecationObjc( + environment.logger, + flutterProject.ios.appDelegateObjc, + ); + } + } + + @override + List get dependencies => []; + + @override + List get inputs { + return [ + const Source.pattern( + '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart', + ), + Source.fromProject((FlutterProject project) => project.ios.appDelegateObjc, optional: true), + Source.fromProject((FlutterProject project) => project.ios.appDelegateSwift, optional: true), + ]; + } + + @override + String get name => 'IssueLaunchRootViewControllerAccess'; + + @override + List get outputs => []; +} + abstract class IosLLDBInit extends Target { const IosLLDBInit(); @@ -495,7 +616,11 @@ abstract class IosAssetBundle extends Target { const IosAssetBundle(); @override - List get dependencies => const [KernelSnapshot(), InstallCodeAssets()]; + List get dependencies => const [ + KernelSnapshot(), + InstallCodeAssets(), + _IssueLaunchRootViewControllerAccess(), + ]; @override List get inputs => const [ diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index aa7b70bdd1de8..484eecd3e5751 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -418,6 +418,8 @@ Future buildXcodeProject({ Future listenToScriptOutputLine() async { final List lines = await scriptOutputPipeFile!.readAsLines(); + bool inWarningBlock = false; + bool inNoteBlock = false; for (final String line in lines) { if (line == 'done' || line == 'all done') { buildSubStatus?.stop(); @@ -426,6 +428,25 @@ Future buildXcodeProject({ return; } } else { + if (!globals.logger.isVerbose) { + if (line.contains('error:')) { + globals.printError(line); + } else if (line.contains('warning:')) { + globals.printWarning(line); + inWarningBlock = true; + } else if (inNoteBlock) { + globals.printWarning(line); + inNoteBlock = false; + } else if (inWarningBlock) { + if (line.startsWith(RegExp(r'\s+?note[:]'))) { + // Xcode doesn't echo this, so we don't. + inNoteBlock = true; + } + inWarningBlock = false; + } + continue; + } + initialBuildStatus?.cancel(); initialBuildStatus = null; buildSubStatus = globals.logger.startProgress( diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index 33635ef1b2b39..c7a44824886a7 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -436,6 +436,10 @@ def __lldb_init_module(debugger: lldb.SBDebugger, _): File get appDelegateSwift => _editableDirectory.childDirectory('Runner').childFile('AppDelegate.swift'); + /// The 'AppDelegate.m' file of the host app. This file might not exist if the app project uses Swift. + File get appDelegateObjc => + _editableDirectory.childDirectory('Runner').childFile('AppDelegate.m'); + File get infoPlist => _editableDirectory.childDirectory('Runner').childFile('Info.plist'); Directory get symlinks => _flutterLibRoot.childDirectory('.symlinks'); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart index c08fafc3d6b78..8e9af0ca324c4 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -955,6 +955,87 @@ void main() { ); }); + group('CheckForLaunchRootViewControllerAccessDeprecation', () { + testWithoutContext('Swift Positive', () async { + final File file = fileSystem.file('AppDelegate.swift'); + file.writeAsStringSync(''' +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + } +} +'''); + await checkForLaunchRootViewControllerAccessDeprecationSwift(logger, file); + expect( + logger.warningText, + startsWith( + 'AppDelegate.swift:6: warning: Flutter deprecation: Accessing rootViewController', + ), + ); + }); + + testWithoutContext('Swift Negative', () async { + final File file = fileSystem.file('AppDelegate.swift'); + file.writeAsStringSync(''' +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + } + + func doIt() { + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + } +} +'''); + await checkForLaunchRootViewControllerAccessDeprecationSwift(logger, file); + expect(logger.warningText, equals('')); + }); + + testWithoutContext('Objc Positive', () async { + final File file = fileSystem.file('AppDelegate.m'); + file.writeAsStringSync(''' +@implementation AppDelegate + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + FlutterViewController* controller = + (FlutterViewController*)self.window.rootViewController; +} + +@end +'''); + await checkForLaunchRootViewControllerAccessDeprecationObjc(logger, file); + expect( + logger.warningText, + startsWith('AppDelegate.m:6: warning: Flutter deprecation: Accessing rootViewController'), + ); + }); + + testWithoutContext('Objc Negative', () async { + final File file = fileSystem.file('AppDelegate.m'); + file.writeAsStringSync(''' +@implementation AppDelegate + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { +} + +- (void)doIt { + FlutterViewController* controller = + (FlutterViewController*)self.window.rootViewController; +} + +@end +'''); + await checkForLaunchRootViewControllerAccessDeprecationObjc(logger, file); + expect(logger.warningText, equals('')); + }); + }); + testWithoutContext('skips thin framework', () async { binary.createSync(recursive: true); From 0a6e4a6de69698b8c8a7bc7a9d9f75427136ee11 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 30 May 2025 23:23:26 -0400 Subject: [PATCH 61/66] Roll Fuchsia Linux SDK from 0CZI-EGv7NDSolQsj... to hRlf4HyRVtQia9RMG... (#169805) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter Please CC codefu@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_fuchsia | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/DEPS b/DEPS index 3001c2ad97018..d88e2288266c5 100644 --- a/DEPS +++ b/DEPS @@ -813,7 +813,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '0CZI-EGv7NDSolQsjzps1riuFJt2Ii5FXpy1OVM0kd0C' + 'version': 'hRlf4HyRVtQia9RMGmCBIq-DEwfGFFlzp354QI7CAGsC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia index 87d3950d77415..4c2ca5d58e590 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia +++ b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: b89a628353fc10e0a377c365e69f3cb4 +Signature: 0ad1e8ff5d4b822d7505b541e563383c ==================================================================================================== LIBRARY: fuchsia_sdk @@ -12101,8 +12101,6 @@ ORIGIN: ../../../fuchsia/sdk/linux/pkg/magma_client/include/lib/magma/magma_sysm ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_ref_pair.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_token_pair.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/view_ref_pair.cc + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/constructors.h + ../../../fuchsia/sdk/linux/LICENSE -ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/storage.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/utility.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/string_view.h + ../../../fuchsia/sdk/linux/LICENSE ORIGIN: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/utility.h + ../../../fuchsia/sdk/linux/LICENSE @@ -12504,8 +12502,6 @@ FILE: ../../../fuchsia/sdk/linux/pkg/magma_client/include/lib/magma/magma_sysmem FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_ref_pair.h FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/include/lib/ui/scenic/cpp/view_token_pair.h FILE: ../../../fuchsia/sdk/linux/pkg/scenic_cpp/view_ref_pair.cc -FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/constructors.h -FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/storage.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/utility.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/string_view.h FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/utility.h From 8e44cc2bcfa58f982a3bd53bad049e05b04f6b5e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sat, 31 May 2025 14:22:13 -0700 Subject: [PATCH 62/66] [Impeller] Fix rotated CircleGeometry coverage (#169743) Fixes https://github.com/flutter/flutter/issues/169710 CircleGeometry bounds were incorrect under rotation, worst at 45 degrees. --- .../entity/geometry/circle_geometry.cc | 15 +++----- .../entity/geometry/geometry_unittests.cc | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc b/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc index c7f6640c4e83a..8b1a467134041 100644 --- a/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/circle_geometry.cc @@ -57,17 +57,10 @@ GeometryResult CircleGeometry::GetPositionBuffer(const ContentContext& renderer, std::optional CircleGeometry::GetCoverage(const Matrix& transform) const { Scalar half_width = stroke_width_ < 0 ? 0.0 : stroke_width_ * 0.5f; Scalar outer_radius = radius_ + half_width; - Point corners[4]{ - {center_.x, center_.y - outer_radius}, - {center_.x + outer_radius, center_.y}, - {center_.x, center_.y + outer_radius}, - {center_.x - outer_radius, center_.y}, - }; - - for (int i = 0; i < 4; i++) { - corners[i] = transform * corners[i]; - } - return Rect::MakePointBounds(std::begin(corners), std::end(corners)); + return Rect::MakeLTRB(-outer_radius, -outer_radius, // + +outer_radius, +outer_radius) + .Shift(center_) + .TransformAndClipBounds(transform); } bool CircleGeometry::CoversArea(const Matrix& transform, diff --git a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc index 7d2f79fe5a9ff..926673aa3b9d3 100644 --- a/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc +++ b/engine/src/flutter/impeller/entity/geometry/geometry_unittests.cc @@ -1308,5 +1308,39 @@ TEST(EntityGeometryTest, TightCubic180DegreeJoins) { EXPECT_GT(points_round.size(), points_reference.size()); } +TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) { + Point center = Point(50, 50); + auto geometry = Geometry::MakeCircle(center, 50); + Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100); + ASSERT_EQ(geometry->GetCoverage({}).value_or(Rect()), circle_bounds); + + Matrix transform45 = Matrix::MakeTranslation(center) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-center); + + EXPECT_TRUE(geometry->GetCoverage(transform45).has_value()); + Rect bounds = geometry->GetCoverage(transform45).value_or(Rect()); + EXPECT_TRUE(bounds.Contains(circle_bounds)) + << "geometry bounds: " << bounds << std::endl + << " circle bounds: " << circle_bounds; +} + +TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) { + Point center = Point(50, 50); + auto geometry = Geometry::MakeStrokedCircle(center, 50, 10); + Rect circle_bounds = Rect::MakeLTRB(0, 0, 100, 100).Expand(5); + ASSERT_EQ(geometry->GetCoverage({}).value_or(Rect()), circle_bounds); + + Matrix transform45 = Matrix::MakeTranslation(center) * + Matrix::MakeRotationZ(Degrees(45)) * + Matrix::MakeTranslation(-center); + + EXPECT_TRUE(geometry->GetCoverage(transform45).has_value()); + Rect bounds = geometry->GetCoverage(transform45).value_or(Rect()); + EXPECT_TRUE(bounds.Contains(circle_bounds)) + << "geometry bounds: " << bounds << std::endl + << " circle bounds: " << circle_bounds; +} + } // namespace testing } // namespace impeller From 8b22f67c85114def3f090286c386627efdf59614 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 1 Jun 2025 01:37:31 -0400 Subject: [PATCH 63/66] Roll Fuchsia Linux SDK from hRlf4HyRVtQia9RMG... to _zS92klQ4fiwoImf3... (#169823) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter Please CC codefu@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d88e2288266c5..e84d1b8fe87ef 100644 --- a/DEPS +++ b/DEPS @@ -813,7 +813,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'hRlf4HyRVtQia9RMGmCBIq-DEwfGFFlzp354QI7CAGsC' + 'version': '_zS92klQ4fiwoImf3A8YMLOLGhGHz5WWjeD3xbItRm4C' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia index 4c2ca5d58e590..c5b22b788b171 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia +++ b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 0ad1e8ff5d4b822d7505b541e563383c +Signature: 3e611e73815812574f272342032f8a85 ==================================================================================================== LIBRARY: fuchsia_sdk From 0b3ba809cc109193cd3cbb0748741f167cb4303d Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Mon, 2 Jun 2025 10:00:46 +0200 Subject: [PATCH 64/66] Revert "Fix NavigationBar indicator overlay color (#164484)" (#169497) ## Description This PR reverts the change from [Fix NavigationBar indicator overlay color](https://github.com/flutter/flutter/pull/164484) as it leads to several regressions. The change was very small: replacing a Container (which obscured the overlay) with an Ink. Unfortunately this leads to some rendering issues which seem related to the Ink painting not being fully in sync with the animation logic implemented by `NavigationIndicator`. I investigated this but did not find an obvious solution. So I would prefer to revert https://github.com/flutter/flutter/pull/164484 as the issue it fixed has less impact than the regression. cc @justinmc for review and also in case you have some clue about why an Ink would cause such problems compared to a Container. ## Related Issue Fixes [[Flutter 3.32.0] Active NavigationBar item not selected when switching items programmatically](https://github.com/flutter/flutter/issues/169249) Fixes [NavigationDrawer active indicator offset with SvgPicture](https://github.com/flutter/flutter/issues/169436) Fixes https://github.com/flutter/flutter/pull/164484#issuecomment-2910505630 Reopens https://github.com/flutter/flutter/issues/163871 --- .../lib/src/material/navigation_bar.dart | 3 +- .../test/material/navigation_bar_test.dart | 4 +- .../material/navigation_bar_theme_test.dart | 4 +- .../test/material/navigation_drawer_test.dart | 10 ++-- .../navigation_drawer_theme_test.dart | 4 +- .../test/material/navigation_rail_test.dart | 58 +++++++++++++------ .../material/navigation_rail_theme_test.dart | 4 +- 7 files changed, 52 insertions(+), 35 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index 83217782071fd..9465e7ef96f37 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -16,7 +16,6 @@ import 'package:flutter/widgets.dart'; import 'color_scheme.dart'; import 'colors.dart'; import 'elevation_overlay.dart'; -import 'ink_decoration.dart'; import 'ink_well.dart'; import 'material.dart'; import 'material_localizations.dart'; @@ -869,7 +868,7 @@ class NavigationIndicator extends StatelessWidget { builder: (BuildContext context, Animation fadeAnimation) { return FadeTransition( opacity: fadeAnimation, - child: Ink( + child: Container( width: width, height: height, decoration: ShapeDecoration( diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index f7d16d5f56fd4..121c1ad8b0c68 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -1716,8 +1716,8 @@ Material _getMaterial(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index e47a3ff752f53..9784a929aa071 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -367,8 +367,8 @@ Material _barMaterial(WidgetTester tester) { ShapeDecoration? _indicator(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index 06f217f94a2a8..667be62ebfa45 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -123,16 +123,14 @@ void main() { await tester.tap(find.text('AC')); await tester.pump(); - // When no background color is set, only the non-visible indicator Ink is expected. - expect(findDestinationInk('AC'), findsOne); + expect(findDestinationInk('AC'), findsNothing); // Destination with a custom background color. await tester.tap(find.byIcon(Icons.access_alarm)); await tester.pump(); // A Material is added with the custom color. - expect(findDestinationInk('Alarm'), findsNWidgets(2)); - // The drawer destination Ink is the first one, the second is the indicator's one. + expect(findDestinationInk('Alarm'), findsOne); final BoxDecoration destinationDecoration = tester.firstWidget(findDestinationInk('Alarm')).decoration! as BoxDecoration; expect(destinationDecoration.color, color); @@ -551,8 +549,8 @@ InkWell? _getInkWell(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_drawer_theme_test.dart b/packages/flutter/test/material/navigation_drawer_theme_test.dart index 4a30bc8cf3b76..9ad94a8e8f3f3 100644 --- a/packages/flutter/test/material/navigation_drawer_theme_test.dart +++ b/packages/flutter/test/material/navigation_drawer_theme_test.dart @@ -285,8 +285,8 @@ Material _getMaterial(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index 5e0e10631a138..b60893aa3ac82 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -3076,7 +3076,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere( (RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures', ); - const Rect indicatorRect = Rect.fromLTRB(12.0, 0.0, 68.0, 32.0); const Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); @@ -3102,7 +3101,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(12.0, 0.0, 68.0, 32.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(12.0, 72.0, 68.0, 104.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3164,7 +3163,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(12.0, 6.0, 68.0, 38.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(12.0, 58.0, 68.0, 90.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3230,7 +3229,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(30.0, 24.0, 86.0, 56.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(30.0, 96.0, 86.0, 128.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3295,7 +3294,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(0.0, 6.0, 50.0, 38.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(0.0, 58.0, 50.0, 90.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3362,7 +3361,7 @@ void main() { ) ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( - rrect: RRect.fromLTRBR(140.0, 24.0, 196.0, 56.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR(140.0, 96.0, 196.0, 128.0, const Radius.circular(16)), color: const Color(0xffe8def8), ), ); @@ -3402,11 +3401,13 @@ void main() { ); // Default values from M3 specification. - const double railMinWidth = 80.0; const double indicatorHeight = 32.0; const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalIconLabelSpacing = 4.0; + const double verticalDestinationSpacing = 12.0; // The navigation rail width is larger than default because of the first destination long label. final double railWidth = tester.getSize(find.byType(NavigationRail)).width; @@ -3417,7 +3418,13 @@ void main() { final Rect indicatorRect = Rect.fromLTRB(indicatorLeft, 0.0, indicatorRight, indicatorHeight); final Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); - const double indicatorHorizontalPadding = (railMinWidth - indicatorWidth) / 2; // 12.0 + + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double labelHeight = 16; // fontSize is 12 and height is 1.3. + const double destinationHeight = + indicatorHeight + verticalIconLabelSpacing + labelHeight + verticalDestinationSpacing; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset; expect( inkFeatures, @@ -3441,10 +3448,10 @@ void main() { ..rect(rect: indicatorRect, color: const Color(0x0a6750a4)) ..rrect( rrect: RRect.fromLTRBR( - indicatorHorizontalPadding, - 0.0, - indicatorHorizontalPadding + indicatorWidth, - indicatorHeight, + indicatorLeft, + secondIndicatorVerticalOffset, + indicatorRight, + secondIndicatorVerticalOffset + indicatorHeight, const Radius.circular(16), ), color: const Color(0xffe8def8), @@ -3497,6 +3504,9 @@ void main() { const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalIconLabelSpacing = 4.0; + const double verticalDestinationSpacing = 12.0; // The navigation rail width is the default one because labels are short. final double railWidth = tester.getSize(find.byType(NavigationRail)).width; @@ -3516,8 +3526,13 @@ void main() { final Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); - // Icon height is greater than indicator height so the indicator has a vertical offset. - const double secondIndicatorVerticalOffset = (iconSize - indicatorHeight) / 2; + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double labelHeight = 16; // fontSize is 12 and height is 1.3. + const double destinationHeight = + iconSize + verticalIconLabelSpacing + labelHeight + verticalDestinationSpacing; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double indicatorOffset = (iconSize - indicatorHeight) / 2; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset + indicatorOffset; expect( inkFeatures, @@ -3596,6 +3611,7 @@ void main() { const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; const double verticalDestinationSpacingM3 = 12.0; // The navigation rail width is the default one because labels are short. @@ -3615,7 +3631,11 @@ void main() { final Rect excludedRect = includedRect.inflate(10); // Compute the vertical position for the selected destination (the one with 'bookmark' icon). - const double secondIndicatorVerticalOffset = verticalDestinationSpacingM3 / 2; + const double destinationHeight = indicatorHeight + verticalDestinationSpacingM3; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double secondIndicatorVerticalOffset = + secondDestinationVerticalOffset + verticalDestinationSpacingM3 / 2; + const double secondDestinationHorizontalOffset = 800 - railMinExtendedWidth; // RTL. expect( inkFeatures, @@ -3641,9 +3661,9 @@ void main() { // Indicator for the selected destination (the one with 'bookmark' icon). ..rrect( rrect: RRect.fromLTRBR( - indicatorLeft, + secondDestinationHorizontalOffset + indicatorLeft, secondIndicatorVerticalOffset, - indicatorRight, + secondDestinationHorizontalOffset + indicatorRight, secondIndicatorVerticalOffset + indicatorHeight, const Radius.circular(16), ), @@ -6150,8 +6170,8 @@ Widget _buildWidget(Widget child, {bool useMaterial3 = true, bool isRTL = false} ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(FadeTransition), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(FadeTransition), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; diff --git a/packages/flutter/test/material/navigation_rail_theme_test.dart b/packages/flutter/test/material/navigation_rail_theme_test.dart index 07236c9e63347..49581b8ba90b3 100644 --- a/packages/flutter/test/material/navigation_rail_theme_test.dart +++ b/packages/flutter/test/material/navigation_rail_theme_test.dart @@ -327,8 +327,8 @@ Material _railMaterial(WidgetTester tester) { ShapeDecoration? _indicatorDecoration(WidgetTester tester) { return tester - .firstWidget( - find.descendant(of: find.byType(NavigationIndicator), matching: find.byType(Ink)), + .firstWidget( + find.descendant(of: find.byType(NavigationIndicator), matching: find.byType(Container)), ) .decoration as ShapeDecoration?; From 36ea2bdeab611e908967b6fa57659998f600a2cb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 2 Jun 2025 06:22:19 -0400 Subject: [PATCH 65/66] Roll Fuchsia Linux SDK from _zS92klQ4fiwoImf3... to pulsQbHjgvxS4Z1DQ... (#169849) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter Please CC codefu@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- engine/src/flutter/ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e84d1b8fe87ef..819a969b9bc67 100644 --- a/DEPS +++ b/DEPS @@ -813,7 +813,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '_zS92klQ4fiwoImf3A8YMLOLGhGHz5WWjeD3xbItRm4C' + 'version': 'pulsQbHjgvxS4Z1DQVtsMjhJcWlgdKsgGoRg0n89oVwC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia index c5b22b788b171..cfab62eba375a 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_fuchsia +++ b/engine/src/flutter/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 3e611e73815812574f272342032f8a85 +Signature: 48043fe727a1773d1d6a7b0a79f458e1 ==================================================================================================== LIBRARY: fuchsia_sdk From d064c95c1065e71ea397aa40767c2fa828d07036 Mon Sep 17 00:00:00 2001 From: Koji Wakamiya Date: Mon, 2 Jun 2025 22:58:26 +0900 Subject: [PATCH 66/66] [Web][Engine] Update MediaQuery in response to semanticsEnabled (#166836) fix https://github.com/flutter/flutter/issues/134980 Calling `EnginePlatformDispatcher.instance.invokeOnAccessibilityFeaturesChanged();` after `EnginePlatformDispatcher.instance.configuration = newConfiguration` to notify update configuration event to `MediaQuery`. before https://github.com/user-attachments/assets/89969cc7-f9fa-4ac0-8ce0-d026d5676f27 after https://github.com/user-attachments/assets/8a284d42-e344-4039-8569-8567956326b7
Example Code ```dart import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; void main() { runApp(const MaterialApp(home: MyHomePage())); } class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () { SemanticsBinding.instance.ensureSemantics(); }, child: const Text('Enable a11y'), ), const SizedBox(height: 24), ElevatedButton( onPressed: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('Should stay visible'), action: SnackBarAction(label: 'Action', onPressed: () {}), ), ); }, child: const Text('Show snackbar'), ), const SizedBox(height: 24), Text( 'MediaQuery.accessibleNavigationOf(context): ${MediaQuery.accessibleNavigationOf(context)}', ), Text( 'SemanticsBinding.instance.semanticsEnabled: ${SemanticsBinding.instance.semanticsEnabled}', ), Text( 'SemanticsBinding.instance.platformDispatcher.semanticsEnabled: ${SemanticsBinding.instance.platformDispatcher.semanticsEnabled}', ), Text( 'SemanticsBinding.instance.accessibilityFeatures: ${SemanticsBinding.instance.accessibilityFeatures}', ), ], ), ), ); } } ```
## 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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> Co-authored-by: Mouad Debbar --- .../web_ui/lib/src/engine/semantics/semantics.dart | 1 + .../flutter/lib/web_ui/test/engine/window_test.dart | 13 +++++++++++++ packages/flutter/lib/src/semantics/binding.dart | 13 ++++++++++++- packages/flutter/test/material/app_test.dart | 2 +- packages/flutter/test/widgets/media_query_test.dart | 4 ++-- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart index d571e631c888d..014fffbbd9651 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -2477,6 +2477,7 @@ class EngineSemantics { final PlatformConfiguration newConfiguration = EnginePlatformDispatcher.instance.configuration .copyWith(accessibilityFeatures: original.copyWith(accessibleNavigation: value)); EnginePlatformDispatcher.instance.configuration = newConfiguration; + EnginePlatformDispatcher.instance.invokeOnAccessibilityFeaturesChanged(); _semanticsEnabled = value; diff --git a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart index 73a2bd50a167b..822520cf96845 100644 --- a/engine/src/flutter/lib/web_ui/test/engine/window_test.dart +++ b/engine/src/flutter/lib/web_ui/test/engine/window_test.dart @@ -334,6 +334,19 @@ Future testMain() async { EnginePlatformDispatcher.instance.invokeOnAccessibilityFeaturesChanged(); }); + test('onAccessibilityFeaturesChanged is called when semantics is enabled', () { + bool a11yChangeInvoked = false; + myWindow.onAccessibilityFeaturesChanged = () { + a11yChangeInvoked = true; + }; + + expect(EngineSemantics.instance.semanticsEnabled, isFalse); + EngineSemantics.instance.semanticsEnabled = true; + + expect(EngineSemantics.instance.semanticsEnabled, isTrue); + expect(a11yChangeInvoked, isTrue); + }); + test('onPlatformMessage preserves the zone', () { final Zone innerZone = Zone.current.fork(); diff --git a/packages/flutter/lib/src/semantics/binding.dart b/packages/flutter/lib/src/semantics/binding.dart index e09ab6538438c..b02315df9ea69 100644 --- a/packages/flutter/lib/src/semantics/binding.dart +++ b/packages/flutter/lib/src/semantics/binding.dart @@ -10,6 +10,7 @@ library; import 'dart:ui' as ui show AccessibilityFeatures, SemanticsActionEvent, SemanticsUpdateBuilder; import 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'debug.dart'; @@ -26,7 +27,17 @@ mixin SemanticsBinding on BindingBase { platformDispatcher ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged ..onSemanticsActionEvent = _handleSemanticsActionEvent - ..onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged; + ..onAccessibilityFeaturesChanged = () { + // TODO(chunhtai): Web should not notify accessibility feature changes during updateSemantics + // https://github.com/flutter/flutter/issues/158399 + if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) { + SchedulerBinding.instance.addPostFrameCallback((Duration duration) { + handleAccessibilityFeaturesChanged(); + }, debugLabel: 'SemanticsBinding.handleAccessibilityFeaturesChanged'); + } else { + handleAccessibilityFeaturesChanged(); + } + }; _handleSemanticsEnabledChanged(); } diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index af9e0565ea701..ee04f3d252472 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -425,7 +425,7 @@ void main() { // didChangeAccessibilityFeatures tester.platformDispatcher.accessibilityFeaturesTestValue = FakeAccessibilityFeatures.allOn; - await tester.pump(); + await tester.pumpAndSettle(); expect(routeBuildCount, equals(1)); expect(dependentBuildCount, equals(5)); diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 8ca9fddcf8bc2..6f671c3841bb2 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -451,7 +451,7 @@ void main() { expect(data.accessibleNavigation, true); tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); - await tester.pump(); + await tester.pumpAndSettle(); expect(data.accessibleNavigation, false); expect(rebuildCount, 4); @@ -512,7 +512,7 @@ void main() { expect(data.accessibleNavigation, true); tester.platformDispatcher.accessibilityFeaturesTestValue = const FakeAccessibilityFeatures(); - await tester.pump(); + await tester.pumpAndSettle(); expect(data.accessibleNavigation, true); expect(rebuildCount, 1);