Repository navigation
macOS: Set static text accessibility role for read-only text fields - #190330
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates FlutterPlatformNodeDelegateMac to treat read-only or disabled text fields as static text by overriding GetData and adjusting the logic in Init and NodeDataChanged. Additionally, the corresponding tests are updated to load the view controller, assert non-nil accessibility elements, and use string comparison for accessibility roles. The review feedback points out a redundant check in Init, suggesting a simplification since GetData already overrides the role of read-only or disabled text fields.
| void FlutterPlatformNodeDelegateMac::Init(std::weak_ptr<OwnerBridge> bridge, ui::AXNode* node) { | ||
| FlutterPlatformNodeDelegate::Init(bridge, node); | ||
| if (GetData().IsTextField()) { | ||
| if (GetData().IsTextField() && !GetData().IsReadOnlyOrDisabled()) { |
There was a problem hiding this comment.
Since GetData() overrides the role of read-only or disabled text fields to ax::mojom::Role::kStaticText, GetData().IsTextField() will already return false for those nodes. Therefore, the additional check !GetData().IsReadOnlyOrDisabled() is redundant and can be removed to simplify the condition.
if (GetData().IsTextField()) {
There was a problem hiding this comment.
Bad bot. Not redundant.
GetData() only rewrites the role to kStaticText but leaves kEditableRoot untouched. IsTextField() returns true whenever kEditableRoot is set, completely independently of the role, so the role rewrite only makese GetData().IsTextField() false for read-only fields where kEditableRoot is unset.
chunhtai
left a comment
There was a problem hiding this comment.
The code LGTM, but can you double check whether the voice over still work when you use mouse to select text? it should announce what gets selected or unselected with a lower pitch
flutter#184501 updated accessibility role mapping such that read-only text fields are mapped to `ax::mojom::Role::kTextField`. On macOS, read-only text fields are intentionally treated as static text. Because of the role change, the macOS embedder incorrectly instantiated `FlutterTextPlatformNode` for read-only text fields, leading to detached accessibility elements and test crashes. This updates the macOS platform node delegate to only instantiate a FlutterTextPlatformNode when the target text field is actually editable and not read-only or disabled. We now explicitly return read-only text fields as standard static text elements. This matches current behaviour but makes it explicit in the platform node delegate for macOS. We're also now calling loadView on the viewController in tests. In a running app, the view controller will always be loaded, so this better approximates reality in the tests... and avoids bugs such as those caught in flutter#184501. Issue: flutter#184559
5bd94be to
e0385ee
Compare
Manually verified this and can confirm selection still works correctly. |
This is a partial re-land of flutter#184501, which just lands the common bridge code and tests as well as a macOS test for behaviour landed in landed in flutter#190330. This sets AXNodeData::SetRestriction() from the Flutter semantics flags: kDisabled when is_enabled is false, and kReadOnly for read-only text fields. Previously the restriction was never populated, so disabled and read-only nodes were indistinguishable from editable/enabled ones at the platform layer. We also add a macOS regression test that checks that a disabled, editable text field is exposed as static text rather than a FlutterTextField. This guards the !GetData().IsReadOnlyOrDisabled() check in FlutterPlatformNodeDelegateMac::Init. The GetData() override rewrites a disabled field's role to kStaticText but leaves kEditableRoot set, so IsTextField() stays true and the restriction check is what prevents an editable FlutterTextField from being created. I've added this in response to a bad comment by the Gemini review bot to ensure that this doesn't regress. Issue: flutter#184559
This is a partial re-land of flutter#184501, which just lands the common bridge code and tests as well as a macOS test for behaviour landed in landed in flutter#190330. This sets AXNodeData::SetRestriction() from the Flutter semantics flags: kDisabled when is_enabled is false, and kReadOnly for read-only text fields. Previously the restriction was never populated, so disabled and read-only nodes were indistinguishable from editable/enabled ones at the platform layer. We also add a macOS regression test that checks that a disabled, editable text field is exposed as static text rather than a FlutterTextField. This guards the !GetData().IsReadOnlyOrDisabled() check in FlutterPlatformNodeDelegateMac::Init. The GetData() override rewrites a disabled field's role to kStaticText but leaves kEditableRoot set, so IsTextField() stays true and the restriction check is what prevents an editable FlutterTextField from being created. I've added this in response to a bad comment by the Gemini review bot to ensure that this doesn't regress. Issue: flutter#184559
This is a partial re-land of flutter#184501, which just lands the common bridge code and tests as well as a macOS test for behaviour landed in landed in flutter#190330. This sets AXNodeData::SetRestriction() from the Flutter semantics flags: kDisabled when is_enabled is false, and kReadOnly for read-only text fields. Previously the restriction was never populated, so disabled and read-only nodes were indistinguishable from editable/enabled ones at the platform layer. We also add a macOS regression test that checks that a disabled, editable text field is exposed as static text rather than a FlutterTextField. This guards the !GetData().IsReadOnlyOrDisabled() check in FlutterPlatformNodeDelegateMac::Init. The GetData() override rewrites a disabled field's role to kStaticText but leaves kEditableRoot set, so IsTextField() stays true and the restriction check is what prevents an editable FlutterTextField from being created. I've added this in response to a bad comment by the Gemini review bot to ensure that this doesn't regress. Issue: flutter#184559
…r#190353) This is a partial re-land of flutter#184501, which just lands the common bridge code and tests as well as a macOS test for behaviour landed in landed in flutter#190330. This sets AXNodeData::SetRestriction() from the Flutter semantics flags: kDisabled when is_enabled is false, and kReadOnly for read-only text fields. Previously the restriction was never populated, so disabled and read-only nodes were indistinguishable from editable/enabled ones at the platform layer. We also add a macOS regression test that checks that a disabled, editable text field is exposed as static text rather than a FlutterTextField. This guards the !GetData().IsReadOnlyOrDisabled() check in FlutterPlatformNodeDelegateMac::Init. The GetData() override rewrites a disabled field's role to kStaticText but leaves kEditableRoot set, so IsTextField() stays true and the restriction check is what prevents an editable FlutterTextField from being created. I've added this in response to a bad comment by the Gemini review bot to ensure that this doesn't regress. Issue: flutter#184559 <!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [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]. If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [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
Relands flutter#184501, which was reverted in flutter#186492 because mapping read-only text fields to Role::kTextField caused the macOS embedder to instantiate a FlutterTextPlatformNode for them, producing detached accessibility elements and test crashes. The underlying macOS issue is now fixed by flutter#190330 and flutter#190353. This relands the remaining bits of flutter#184501. In the common bits of the bridge, read-only text fields now map to `Role::kTextField`. In the Windows implementation `ENABLED_CHANGED` and `READONLY_CHANGED` are dispatched as MSAA `kStateChanged` events and `AXPlatformNodeWin` now raises the corresponding `UIA_IsEnabledPropertyId` change. Issue: flutter#184559
Relands flutter#184501, which was reverted in flutter#186492 because mapping read-only text fields to Role::kTextField caused the macOS embedder to instantiate a FlutterTextPlatformNode for them, producing detached accessibility elements and test crashes. The underlying macOS issue is now fixed by flutter#190330 and flutter#190353. This relands the remaining bits of flutter#184501. In the common bits of the bridge, read-only text fields now map to `Role::kTextField`. In the Windows implementation `ENABLED_CHANGED` and `READONLY_CHANGED` are dispatched as MSAA `kStateChanged` events and `AXPlatformNodeWin` now raises the corresponding `UIA_IsEnabledPropertyId` change. Issue: flutter#184559
Relands flutter#184501, which was reverted in flutter#186492 because mapping read-only text fields to Role::kTextField caused the macOS embedder to instantiate a FlutterTextPlatformNode for them, producing detached accessibility elements and test crashes. The underlying macOS issue is now fixed by flutter#190330 and flutter#190353. This relands the remaining bits of flutter#184501. In the common bits of the bridge, read-only text fields now map to `Role::kTextField`. In the Windows implementation `ENABLED_CHANGED` and `READONLY_CHANGED` are dispatched as MSAA `kStateChanged` events and `AXPlatformNodeWin` now raises the corresponding `UIA_IsEnabledPropertyId` change. Fixes: flutter#184559 ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [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]. If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [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
…12401) Manual roll Flutter from 2757a77a73df to e52f01c920ad (47 revisions) Manual roll requested by [email protected] flutter/flutter@2757a77...e52f01c 2026-07-31 [email protected] [Impeller] Execute PipelineCompileQueue jobs in the order that they were added (flutter/flutter#190262) 2026-07-31 [email protected] Roll Packages from 7d17fc8 to 5351d8c (5 revisions) (flutter/flutter#190351) 2026-07-31 [email protected] Roll Skia from dcbd015c9646 to 7ef86a5b0eb9 (4 revisions) (flutter/flutter#190347) 2026-07-31 [email protected] [Impeller] Do not acquire an unneeded image in KHRSwapchainVK if the swapchain must be recreated due to a size change (flutter/flutter#190116) 2026-07-31 [email protected] Remove the --enable-serial-gc engine flag (flutter/flutter#190310) 2026-07-31 [email protected] Migrate platform_channel_swift example to material_ui (flutter/flutter#190308) 2026-07-31 [email protected] macOS: Set static text accessibility role for read-only text fields (flutter/flutter#190330) 2026-07-31 [email protected] Roll Dart SDK from 96f49fc43f59 to c3acfc2479f6 (1 revision) (flutter/flutter#190336) 2026-07-31 [email protected] Roll Skia from 07f08414dd66 to dcbd015c9646 (1 revision) (flutter/flutter#190333) 2026-07-31 [email protected] [web] Autofill all AutofillGroup fields in semantics mode (flutter/flutter#187108) 2026-07-31 [email protected] iOS: Configure test task runner thread at display QoS (flutter/flutter#190283) 2026-07-31 [email protected] Roll Skia from a1109355de78 to 07f08414dd66 (5 revisions) (flutter/flutter#190328) 2026-07-31 [email protected] Support reduceMotion accessibility feature in MediaQuery (flutter/flutter#190287) 2026-07-30 [email protected] Roll Dart SDK from 43f7de5f4977 to 96f49fc43f59 (4 revisions) (flutter/flutter#190312) 2026-07-30 [email protected] fix: text selection two handles directionality. (flutter/flutter#179928) 2026-07-30 [email protected] Add java/gradle check when gradle crashes (flutter/flutter#189997) 2026-07-30 [email protected] [Impeller] Add filterQuality support to ImageFilter.shader (flutter/flutter#188544) 2026-07-30 [email protected] [flutter/flutter] Migrate multiple_windows example to material_ui (flutter/flutter#190313) 2026-07-30 [email protected] Roll Skia from 50cf67910462 to a1109355de78 (6 revisions) (flutter/flutter#190306) 2026-07-30 [email protected] Migrate swift xctests to Swift testing tests (flutter/flutter#187801) 2026-07-30 [email protected] Migrates the platform_channel example to material_ui (flutter/flutter#190253) 2026-07-30 [email protected] iOS: Drop unnecessary @mainactor from VSyncClientTests (flutter/flutter#190285) 2026-07-30 [email protected] Add nullptr check to isOpaque (flutter/flutter#189796) 2026-07-30 [email protected] [Flutter GPU] Bind uniforms and textures by cached reflection index (flutter/flutter#189820) 2026-07-30 [email protected] Migrate layers example to material_ui (flutter/flutter#190237) 2026-07-30 [email protected] Add `ShapeBorder` hit test fast paths (flutter/flutter#187962) 2026-07-30 [email protected] ci: mac-must-wait part duex (flutter/flutter#190295) 2026-07-30 [email protected] Roll Skia from 491301f393d1 to 50cf67910462 (3 revisions) (flutter/flutter#190294) 2026-07-30 [email protected] Roll Packages from dd11626 to 7d17fc8 (1 revision) (flutter/flutter#190293) 2026-07-30 [email protected] Roll Skia from 177de1940bf2 to 491301f393d1 (1 revision) (flutter/flutter#190279) 2026-07-30 [email protected] Roll Skia from b8bda91f02db to 177de1940bf2 (5 revisions) (flutter/flutter#190272) 2026-07-30 [email protected] Roll Fuchsia Linux SDK from J8rVTlBnjnUpuHYk3... to _J8wM3kyQpLN9wvRD... (flutter/flutter#190273) 2026-07-30 [email protected] Roll Skia from 78afc18c9ba0 to b8bda91f02db (3 revisions) (flutter/flutter#190268) 2026-07-30 [email protected] Revert: Split the platform and cpuArch part of TargetPlatform (flutter/flutter#190258) 2026-07-30 [email protected] Return null from RenderProxyBoxMixin.computeDryBaseline when the child has no baseline (flutter/flutter#189723) 2026-07-30 [email protected] Roll Skia from 6fea713d32ec to 78afc18c9ba0 (4 revisions) (flutter/flutter#190257) 2026-07-30 [email protected] Roll pub packages (flutter/flutter#190259) 2026-07-29 [email protected] [cross imports] Check examples cross imports (flutter/flutter#187662) 2026-07-29 [email protected] ci: mac verify binaries still has to wait on linux_host_engine (flutter/flutter#190239) 2026-07-29 [email protected] Adds analytics to macos impeller opt in/out (flutter/flutter#190220) 2026-07-29 [email protected] Roll Skia from 0f35bba4945c to 6fea713d32ec (6 revisions) (flutter/flutter#190230) 2026-07-29 [email protected] iOS: Fix Swift warning in TracingTests (flutter/flutter#190203) 2026-07-29 [email protected] Convert all gradle-wrapper.properties in /dev to use distribution 'bin' (flutter/flutter#190226) 2026-07-29 [email protected] Roll Packages from 3e63635 to dd11626 (11 revisions) (flutter/flutter#190216) ...
#184501 updated accessibility role mapping such that read-only text fields are mapped to
ax::mojom::Role::kTextField. On macOS, read-only text fields are intentionally treated as static text. Because of the role change, the macOS embedder incorrectly instantiatedFlutterTextPlatformNodefor read-only text fields, leading to detached accessibility elements and test crashes.This updates the macOS platform node delegate to only instantiate a FlutterTextPlatformNode when the target text field is actually editable and not read-only or disabled. We now explicitly return read-only text fields as standard static text elements. This matches current behaviour but makes it explicit in the platform node delegate for macOS.
We're also now calling loadView on the viewController in tests. In a running app, the view controller will always be loaded, so this better approximates reality in the tests... and avoids bugs such as those caught in #184501.
This should allow us to reland #184501.
Issue: #184559
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.