Skip to content

[linux] Read heading text through the AtkText interface - #188005

Merged
robert-ancell merged 7 commits into
flutter:masterfrom
sawirricardo:fix-linux-heading-text-a11y
Aug 19, 2026
Merged

robert-ancell merged 7 commits into
flutter:masterfrom
sawirricardo:fix-linux-heading-text-a11y

Conversation

@sawirricardo

Copy link
Copy Markdown
Contributor

Fixes #187925

Problem

On Linux, a node with Semantics(header: true) is announced by Orca as just "header" — the node's text is never read. With header: false the same text is read correctly.

Root cause

Two issues in the Linux embedder's accessibility code (engine/src/flutter/shell/platform/linux/):

  1. The node's label is exposed only via the AtkObject name property, not the AtkText interface. Orca reads the text content of a heading exclusively through AtkText (see _generate_heading in Orca's speech_generator.py, which calls _generate_text_content → AXText.get_substring → atk_text_get_text). It never falls back to the name for the heading/header roles. So Orca finds no text and announces only the role.

    This matches the ATK contract used by GTK: GtkLabel exposes its text through AtkText. Flutter's label is its text content, so it should be exposed the same way. (FlAccessibleTextField already does this for editable text.)

  2. The wrong ATK role. is_header maps to ATK_ROLE_HEADER, which is the document masthead/banner role. ATK_ROLE_HEADING is the content-heading role (the HTML <h1>–<h6> analogue) and is what Semantics(header: true) means (matching iOS header trait and Android heading class).

Fix

  • Implement the AtkText interface on FlAccessibleNode, backed by the node's existing accessibility name (get_character_count, get_text, get_character_at_offset, get_caret_offset, get_n_selections, get_selection, get_text_at_offset). This is safe for other roles: Orca's default presentation for buttons/panels/images reads the AtkObject name via _generate_accessible_label_and_name, not AtkText, so their announcement is unchanged. FlAccessibleTextField already declares a richer AtkText and continues to override the base implementation.
  • Map the is_header flag to ATK_ROLE_HEADING.

Result

For the repro in #187925, Orca now announces "Section One, heading" instead of just "header".

Test plan

  • Added ExposesTextViaAtkText test verifying atk_text_get_character_count / atk_text_get_text / atk_text_get_character_at_offset return the node's label.
  • Extended the existing role-mapping test to assert is_header → ATK_ROLE_HEADING.
  • Linux linux_unit_tests (cannot run locally — Linux GTK/ATK build; developed/analyzed on macOS). Reviewers, please confirm CI is green.

@sawirricardo
sawirricardo requested a review from a team as a code owner June 15, 2026 05:10
@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. platform-linux Building on or for Linux specifically a: desktop Running on desktop team-linux Owned by the Linux platform team labels Jun 15, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the AtkText interface for FlAccessibleNode to expose accessibility names as text content to screen readers, and updates the header role to ATK_ROLE_HEADING. Feedback suggests aligning the AtkText implementation with ATK specifications by returning -1 when caret is unsupported, returning nullptr for invalid selections, and properly handling offset and boundary_type in fl_accessible_node_get_text_at_offset to support character-by-character navigation. Additionally, expanding test coverage to verify these behaviors is recommended.

Expose a semantics node's name as text content via the AtkText interface
so screen readers announce the text of headings. Orca reads the text
content of a heading exclusively through AtkText, not the AtkObject name,
so a node with `Semantics(header: true)` was announced as just "header"
while its text was skipped (flutter#187925).

Also map the `is_header` flag to ATK_ROLE_HEADING (the content-heading
role, matching HTML h1-h6 and `Semantics(header: true)`) instead of
ATK_ROLE_HEADER (the document masthead/banner role).

FlAccessibleTextField already implements a richer AtkText and continues
to override the base implementation.

Fixes flutter#187925
@sawirricardo
sawirricardo force-pushed the fix-linux-heading-text-a11y branch from 25b4f44 to aae0d05 Compare June 15, 2026 08:56
@robert-ancell robert-ancell added the CICD Run CI/CD label Jun 17, 2026
robert-ancell
robert-ancell previously approved these changes Jun 17, 2026

@robert-ancell robert-ancell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks!

@robert-ancell
robert-ancell enabled auto-merge June 17, 2026 03:35
auto-merge was automatically disabled June 17, 2026 11:24

Head branch was pushed to by a user without write access

@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
robert-ancell
robert-ancell previously approved these changes Jul 1, 2026
@robert-ancell
robert-ancell enabled auto-merge July 1, 2026 20:32
@robert-ancell
robert-ancell requested a review from mattkae July 8, 2026 22:43
mattkae
mattkae previously approved these changes Jul 9, 2026

@mattkae mattkae left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@robert-ancell robert-ancell added the CICD Run CI/CD label Jul 14, 2026
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Jul 28, 2026
@robert-ancell robert-ancell added CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App labels Jul 28, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 28, 2026
@auto-submit

auto-submit Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188005, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@robert-ancell robert-ancell added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 28, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 28, 2026
@auto-submit

auto-submit Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188005, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Jul 29, 2026
@robert-ancell robert-ancell added the CICD Run CI/CD label Jul 29, 2026
@robert-ancell

Copy link
Copy Markdown
Contributor

This is failing in formatting:

diff --git a/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc b/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc
index 8ab8eabe5e3..00000000000 100644
--- a/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc
+++ b/engine/src/flutter/shell/platform/linux/fl_accessible_node_test.cc
@@ -357,8 +357,7 @@ TEST_F(FlAccessibleNodeTest, ExposesTextViaAtkText) {
g_autofree gchar* substring = atk_text_get_text(ATK_TEXT(node), 0, 7);
EXPECT_STREQ(substring, "Section");
-  EXPECT_EQ(atk_text_get_character_at_offset(ATK_TEXT(node), 0),
-            gunichar('S'));
+  EXPECT_EQ(atk_text_get_character_at_offset(ATK_TEXT(node), 0), gunichar('S'));
EXPECT_EQ(atk_text_get_caret_offset(ATK_TEXT(node)), -1);
EXPECT_EQ(atk_text_get_n_selections(ATK_TEXT(node)), 0);
@@ -374,8 +373,7 @@ TEST_F(FlAccessibleNodeTest, ExposesTextViaAtkText) {
start_offset = -1;
end_offset = -1;
g_autofree gchar* text_at_offset = atk_text_get_string_at_offset(
-      ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_CHAR, &start_offset,
-      &end_offset);
+      ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_CHAR, &start_offset, &end_offset);
EXPECT_STREQ(text_at_offset, "S");
EXPECT_EQ(start_offset, 0);
EXPECT_EQ(end_offset, 1);
@@ -383,8 +381,7 @@ TEST_F(FlAccessibleNodeTest, ExposesTextViaAtkText) {
start_offset = -1;
end_offset = -1;
g_autofree gchar* text_at_line_offset = atk_text_get_string_at_offset(
-      ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_LINE, &start_offset,
-      &end_offset);
+      ATK_TEXT(node), 0, ATK_TEXT_GRANULARITY_LINE, &start_offset, &end_offset);
EXPECT_STREQ(text_at_line_offset, "Section One");
EXPECT_EQ(start_offset, 0);
EXPECT_EQ(end_offset, 11);
DONE

From https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8675059841287260017/+/u/test:_test:_Check_formatting/stdout

@sawirricardo can you fix this in your branch?

auto-merge was automatically disabled August 5, 2026 07:18

Head branch was pushed to by a user without write access

@sawirricardo
sawirricardo dismissed stale reviews from robert-ancell and mattkae via 05d2cfb August 5, 2026 07:18
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 5, 2026
@mattkae mattkae added the CICD Run CI/CD label Aug 12, 2026
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 19, 2026
@robert-ancell robert-ancell added the CICD Run CI/CD label Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: desktop Running on desktop CICD Run CI/CD cp: stable cherry pick this pull request to stable release candidate branch engine flutter/engine related. See also e: labels. platform-linux Building on or for Linux specifically team-linux Owned by the Linux platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A11Y: Can't read text with semantics header:true

3 participants