**Description**
This pull request adds a navigation focus handler to the Flutter web
engine that bridges assistive technology activations with Flutter's
focus tracking system. The listener intercepts screen reader activations
(VoiceOver, NVDA, JAWS, etc.) and forces DOM focus on the activated
elements, ensuring they integrate properly with Flutter's navigation
focus restoration.
**Before**
When using VoiceOver or other screen readers to navigate between pages
in a Flutter web app, focus restoration would fail because assistive
technology activations don't naturally trigger the DOM focus events that
Flutter's navigation system expects. Users would lose their navigation
context, with focus jumping to default elements instead of returning to
the previously activated button.
**Before behavior demo**
https://focus-demo-0529-before.web.app
On mac os, Use command + F5 to activate voice over.
Use control + option + arrow right to focus on "Go to page two" button.
Use control + option + space to click the "Go to page two" button.
Then in page two, use control + option + arrow right to focus on "Back
to page one" button.
The focus will be on "Page one" heading instead of "Go to page two"
button. This is not expected
**After**
Screen reader users can now navigate between pages and have their focus
properly restored to the previously activated element (e.g., "Go to Page
Two" button) when returning to a previous page, providing a consistent
and accessible navigation experience across all assistive technologies.
**After behavior demo**
https://focus-demo-0529-after.web.app
On mac os, Use command + F5 to activate voice over.
Use control + option + arrow right to focus on "Go to page two" button.
Use control + option + space to click the "Go to page two" button.
Then in page two, use control + option + arrow right to focus on "Back
to page one" button.
The focus will be on "Go to page two" button. This is expected.
**Issue Fixed**
This PR addresses GitHub Issue #140483, which reports that VoiceOver
focus restoration doesn't work in Flutter web applications during
navigation.
## 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.
This reverts commit 7d22606cda72accc2232e6b9a1f6fee4c6ea1c9c.
It turns out that in many scenarios, resizing the OffscreenCanvas
multiple times per frame is prohibitively expensive. It also turns out
that neither API works well enough on non-Chrome browsers to make it
viable anyway, so we should switch back to `createImageBitmap`.
There's today a single boolean `debugEmulateFlutterTesterEnvironment`
that determines certain behaviors in the engine to emulate how the
Flutter Tester runs (more details at
https://github.com/flutter/flutter/issues/145779).
With this PR:
- Run all engine unit tests in production mode by default.
- Give tests more granular control over which test behaviors to
enable/disable (e.g. Ahem font).
- Keep it easy for framework tests to enable all emulation behaviors.
Fixes https://github.com/flutter/flutter/issues/145779
This PR is an attempt to reland
https://github.com/flutter/flutter/pull/168996
There were some issues that cropped up in the `web_long_running_test`
shards. However, it turns out that these tests don't actually run in
presubmit on any PR that has any engine changes, which is not ideal. I
modified the long running tests to run in presubmit, but this had issues
because apparently a big chunk of these integration tests actually are
trying to download canvaskit from CDN. I changed almost all of the tests
to use local canvaskit (which should make them more reliable and
hermetic). There is one test whose job is to actually test the CDN
itself, and I am leaving that disabled in presubmit for PRs that have
engine changes (since the engine artifacts won't be uploaded to CDN yet)
but the rest of them are all running and passing now.
Also, I fixed the underlying issue that was exposed by the long running
tests, which is that the CanvasKit path clipping stuff in the layer
visitor needs to be aware of LazyPath.
Attempted fix for https://github.com/flutter/flutter/issues/166668 .
Plan is to ask for testing once rolled into g3 since we weren't given a
repro.
Explaination: we can only submit command buffers to the metal command
queue when the device is in the foreground. push notifications
temporarily wake up the app and can trigger images to begin decoding.
This decoding can fail, possibly due to the app re-backgrounding. In
theory, the sync switch should prevent this from happening - but because
we don't actually block on the scheduling of the command buffer there is
technically a race that can happen.
Add the ability to block submission on scheduling for metal. note that
other graphics APIs do not have a distinction for commited vs scheduled
and so it no-ops for them.
See
https://developer.apple.com/documentation/metal/preparing-your-metal-app-to-run-in-the-background
> When UIKit calls your app delegate’s
[applicationDidEnterBackground(_:)](https://developer.apple.com/documentation/UIKit/UIApplicationDelegate/applicationDidEnterBackground(_:))
method, make sure Metal has scheduled all command buffers you’ve already
committed before your app returns control to the system. ... Finish
encoding commands to render the frame and commit the command buffer,
then call
[waitUntilScheduled()](https://developer.apple.com/documentation/metal/mtlcommandbuffer/waituntilscheduled()).
Fixes#155323
Before this change the `identifier` would not be updated even if marked
dirty for a `SemanticRole` that had no `SemanticBehavior`s. After this
change an `identifier` marked dirty is now updated even if the
`SemanticRole` has no `SemanticBehavior`s.
## 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 <roliv@google.com>
## Description
This pull request fixes VoiceOver tab activation by adding tappable
behavior to the SemanticTab class in the Flutter web engine. The fix
ensures that tabs can be properly activated using assistive technology
commands like VoiceOver's ctrl-option-space, making tab navigation fully
accessible for screen reader users.
## Before
When using VoiceOver to navigate tabs in a Flutter web app, users were
unable to activate tabs using the standard VoiceOver activation command
(ctrl-option-space). The SemanticTab class was missing the Tappable
semantic behavior that enables assistive technology interaction, causing
screen readers to treat tabs as non-interactive elements despite having
tap handlers in the Flutter framework.
**Before behavior:**
https://tab-0605-before.web.app/
- Navigate to a tab using VoiceOver (ctrl-option-arrow)
- Attempt to activate the tab with ctrl-option-space
- Tab does not respond to activation command
- Users cannot switch between tabs using assistive technology
## After
VoiceOver and other screen reader users can now properly activate tabs
using standard assistive technology commands. Tabs respond correctly to
ctrl-option-space and other activation gestures, providing full keyboard
accessibility for tab navigation.
**After behavior:**
https://tab-0605-after.web.app/
- Navigate to a tab using VoiceOver (ctrl-option-arrow)
- Activate the tab with ctrl-option-space
- Tab switches correctly, displaying the associated tab panel
- Consistent behavior across all assistive technologies
## Changes Made
- Added `addTappable()` call to `SemanticTab` constructor in `tabs.dart`
- Added test case "tab with tap action" to verify DOM elements receive
the `flt-tappable` attribute
- Ensures tabs with `hasTap: true` are properly marked as interactive
for assistive technologies
## Testing
Added unit test that verifies:
- Tabs with tap actions receive the `flt-tappable` DOM attribute
- SemanticTab properly integrates with the existing tappable behavior
system
## Issue Fixed
This PR addresses GitHub Issue #169279, which reports that VoiceOver
doesn't allow users to click tabs in Flutter web applications.
## 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.
<!-- start_original_pr_link -->
Reverts: flutter/flutter#168996
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: zanderso
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Failing in post submit on
web_long_running_tests_3_5
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: eyebrowsoffire
<!-- end_original_pr_author -->
<!-- start_reviewers -->
Reviewed By: {mdebbar}
<!-- end_reviewers -->
<!-- start_revert_body -->
This change reverts the following previous change:
The lifecycle of `Path` objects are currently not managed by the user.
That is to say, there is no `dispose` method on path objects and
therefore no explicit way to detect when the user is done with the path
object and the native-side object can be exposed. As of right now, we
use `FinalizationRegistry` to clean up the native-side objects when the
dart-side objects are garbage collected. However, this has a number of
issues:
* Adding objects to the finalization registry actually ends up
prolonging their lifetime in V8, since the V8 garbage collector will
only collect them in a major GC and not a minor GC once they are
registered with the finalization registry. See the following Chrome bug:
https://issues.chromium.org/issues/340777103
* We can run into OOM issues where the linear memory of canvaskit/skwasm
exceeds 2GB if the collection of paths go on too long.
* Even if the paths do get collected by the GC, they often happen
infrequently enough that paths over many frames have accumulated and are
being collected all at once. This gap can often be dozens or hundreds of
frames long, and when collection does occur it is freeing a lot of paths
at once, which causes a janky frame. I have seen this take upwards of
800ms on my M1 Macbook Pro.
There are some more details in
https://github.com/flutter/flutter/issues/153678
This PR alleviates this issue by creating a `LazyPath` object. This
object is added to an arena that explicitly collects the underlying
native objects at the end of each frame. The object also tracks the API
calls made to it so that if it is actually used across a frame boundary
that we can recreate the native object if it was freed.
Running our benchmarks, this has a non-trivial performance cost to
building and using these paths (30-50% in a microbenchmark, 3-6% in a
broader full app benchmark). However, as a team we've decided that this
cost is worth it to avoid OOM issues as well as the non-deterministic
jank associated with large collections of these objects.
<!-- end_revert_body -->
Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
The lifecycle of `Path` objects are currently not managed by the user.
That is to say, there is no `dispose` method on path objects and
therefore no explicit way to detect when the user is done with the path
object and the native-side object can be exposed. As of right now, we
use `FinalizationRegistry` to clean up the native-side objects when the
dart-side objects are garbage collected. However, this has a number of
issues:
* Adding objects to the finalization registry actually ends up
prolonging their lifetime in V8, since the V8 garbage collector will
only collect them in a major GC and not a minor GC once they are
registered with the finalization registry. See the following Chrome bug:
https://issues.chromium.org/issues/340777103
* We can run into OOM issues where the linear memory of canvaskit/skwasm
exceeds 2GB if the collection of paths go on too long.
* Even if the paths do get collected by the GC, they often happen
infrequently enough that paths over many frames have accumulated and are
being collected all at once. This gap can often be dozens or hundreds of
frames long, and when collection does occur it is freeing a lot of paths
at once, which causes a janky frame. I have seen this take upwards of
800ms on my M1 Macbook Pro.
There are some more details in
https://github.com/flutter/flutter/issues/153678
This PR alleviates this issue by creating a `LazyPath` object. This
object is added to an arena that explicitly collects the underlying
native objects at the end of each frame. The object also tracks the API
calls made to it so that if it is actually used across a frame boundary
that we can recreate the native object if it was freed.
Running our benchmarks, this has a non-trivial performance cost to
building and using these paths (30-50% in a microbenchmark, 3-6% in a
broader full app benchmark). However, as a team we've decided that this
cost is worth it to avoid OOM issues as well as the non-deterministic
jank associated with large collections of these objects.
**Summary**
This PR improves web accessibility in Flutter by separating hint from
label in the semantics engine and exposing them via ARIA attributes. The
hint is set using aria-description (or aria-describedby as a fallback
for browsers that do not support aria-description).
**Details**
Hint separation:
The hint is exposed via aria-description if supported, or via
aria-describedby with a hidden node as a fallback.
Browser compatibility:
Uses feature detection to choose between aria-description and
aria-describedby.
Test coverage:
Added/updated tests to verify correct ARIA attribute behavior and
fallback logic.
**How to verify**
All relevant tests pass (semantics_test.dart, semantics_text_test.dart).
**Motivation**
This change brings Flutter web closer to accessibility best practices
and ARIA standards, improving the experience for users of assistive
technologies.
**Before/After Change**
before: https://before-change-hint.web.app/
after: https://after-change-hint.web.app/
after(fallback to aria-describedby):
https://after-change-hint-fallback.web.app/
**Issues fixed**
https://github.com/flutter/flutter/issues/162140
**Note**
Some focus-related tests (e.g., incrementable sends focus events) are
failing, but these failures are also present on the main branch and are
unrelated to the ARIA label/hint changes in this PR.
## 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: Mouad Debbar <mouad.debbar@gmail.com>
Update documentation for `Size` and `Rect` classes in geometry.dart to
correct references for `centerRight` and `bottomCenter` methods.
Co-authored-by: stuuupidcat <stuuupidcat.3@gmail.com>
This adds a debugging utility that allows us to dump counts of the live
skwasm objects in debug mode. This is useful for understanding memory
leaks.
This is not code that runs in production or affects end users, so I'm
not bothering to write specific unit tests for this functionality.
---------
Co-authored-by: Kevin Moore <kevmoo@users.noreply.github.com>
Nearly all parts of the Impeller rendering pipeline now rely on DlPath
and PathSource objects for their path description needs. The impeller
path only exists for impeller's unit tests and benchmarks to have a
local way to construct paths. We implement path construction for the
DlPath object via DlPathBuilder which makes the impeller family of path
objects functionally obsolete and so they are now deleted.
Reduce the number of places where we convert flutter paint to DLpaint
and remove unused tonic overrides. Also does a pass on dl_paint/builder
to remove places we accidentally incremented/decrement shared_ptr ref
counts
<!-- start_original_pr_link -->
Reverts: flutter/flutter#165531
<!-- end_original_pr_link -->
<!-- start_initiating_author -->
Initiated by: matanlurey
<!-- end_initiating_author -->
<!-- start_revert_reason -->
Reason for reverting: Breaks google client tests
<!-- end_revert_reason -->
<!-- start_original_pr_author -->
Original PR Author: ash2moon
<!-- end_original_pr_author -->
<!-- start_reviewers -->
Reviewed By: {chunhtai, reidbaker, hannah-hyj}
<!-- end_reviewers -->
<!-- start_revert_body -->
This change reverts the following previous change:
Resolves partly https://github.com/flutter/flutter/issues/165510
**Context:** This issue originates from
https://github.com/flutter/flutter/issues/99715, where it was reported
that `liveRegion` alone was insufficient for announcing form validation
errors. While `liveRegion` announces the first error encountered,
subsequent submissions with the same error message on Android would not
trigger a re-announcement.
**Original Solution:** Pull request
https://github.com/flutter/flutter/pull/123373 addressed this by
implementing the `announce` event to ensure error messages were
consistently announced, even for repeated submissions.
**Native Android Behavior (Jetpack Compose):** In native Android
development using Jetpack Compose, setting the `isError` property of a
`TextField` to `true` triggers Talkback to announce "Error invalid
input." This announcement occurs *only* on the initial change to the
error state. Subsequent errors, even if the `isError` property remains
`true`, are not re-announced. This behavior closely mirrors the
functionality of `liveRegion`, with the key difference being that
`liveRegion` also announces the specific error text, in addition to the
general error state. Testing in a native Jetpack Compose application
confirms this behavior and provides a valuable comparison point against
the current Flutter form example.
**Suggested Action:** **Fork** the behavior in
https://github.com/flutter/flutter/pull/123373. Reinstate the use of
`liveRegion` for error announcements within `widgets/Form` for Android
and keep other platforms the same.
## 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].
<!-- Links -->
[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
<!-- end_revert_body -->
Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
**Description**
This pull request removes the unnecessary setAriaRole('dialog') fallback
in the SemanticRoute class within the Flutter web engine. This line was
an old fallback and is no longer needed
**Before**
https://dialog-0505-before.web.app/
**After**
https://dialog-050502-after.web.app/
**Issue Fixed**
This PR addresses GitHub Issue #168247, which proposes reconsidering the
application of role="dialog" to arbitrary routes.
## 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].
- [ ] 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.
This produces a build of Skwasm that works on Firefox and Safari. This
means we use `SkAnimatedImage` for animated gifs and webps and use
builtin ICU data in Skia.
I have unit test suites for Safari and Firefox with dart2wasm and both
`ui` and `engine` test sets. However, there are a few issues with
running these on CI:
* Safari+dart2wasm doesn't work yet until the CI bots are upgraded to
macOS 15, so these have been disabled on CI for now (but you can run the
unit test suite locally).
* Firefox+ui doesn't work because our Linux bots have no GPU and
therefore no WebGL2 support, so that one is disabled. Firefox+dart2wasm
with the `engine` suite is enabled on CI though.
I did make some changes to the host page for our unit test harness so
that Safari actually works though. Even though we're not running on CI,
you can still run locally if you have macOS 15.
In this PR:
- `felt build --experimental-webparagraph` builds a 3rd variant of
CanvasKit to be used for `WebParagraph`.
- `felt test --suite=chrome-dart2js-experimental-webparagraph-ui` runs
`test/ui/` tests against `WebParagraph`.
- `felt test --suite=chrome-dart2js-experimental-webparagraph-ui` runs
Chrome with the extra flag:
- `--enable-experimental-web-platform-features`
In the future:
- Upgrade to Chrome@133.0.6943.53 or above.
- Actual implementation and tests of WebParagraph coming in
https://github.com/flutter/flutter/pull/167559
- Run the `chrome-dart2js-experimental-webparagraph-ui` suite in CI.
- Trim the new experimental build of CK to realize the reduction in
size.