Skip to content

libservo: Allow the embedder to activate accessibility#42336

Merged
delan merged 8 commits intoservo:mainfrom
delan:set-accessibility-enabled
Feb 20, 2026
Merged

libservo: Allow the embedder to activate accessibility#42336
delan merged 8 commits intoservo:mainfrom
delan:set-accessibility-enabled

Conversation

@delan
Copy link
Copy Markdown
Member

@delan delan commented Feb 4, 2026

this patch adds a Servo::set_accessibility_active() method that embedders can use to tell Servo to start building and sending accessibility trees to the platform, as long as the pref is enabled (#42333). doing so sets a global flag in the constellation, which is then propagated to the layout of all existing and future pipelines.

Testing: none yet, no functional change
Fixes: part of #4344

@delan delan force-pushed the set-accessibility-enabled branch from f5bfb00 to 56054ff Compare February 4, 2026 15:56
Comment thread components/constellation/constellation.rs Outdated
Comment thread components/shared/embedder/lib.rs Outdated
@delan delan force-pushed the set-accessibility-enabled branch from 56054ff to 4e85ef3 Compare February 5, 2026 12:06
@delan delan changed the title libservo: Allow the embedder to enable accessibility libservo: Allow the embedder to activate accessibility Feb 5, 2026
@delan delan force-pushed the set-accessibility-enabled branch 3 times, most recently from 1ed4818 to 435e8ce Compare February 5, 2026 12:19
Comment thread components/script/script_thread.rs Outdated
@delan delan marked this pull request as ready for review February 5, 2026 12:22
@servo-highfive servo-highfive added the S-awaiting-review There is new code that needs to be reviewed. label Feb 5, 2026
Comment on lines +3004 to +3017
fn set_accessibility_active(&mut self, active: bool) {
self.accessibility_active = active;
for browsing_context in self.browsing_contexts.values_mut() {
if let Some(pipeline) = self.pipelines.get(&browsing_context.pipeline_id) {
let _ = pipeline
.event_loop
.send(ScriptThreadMessage::SetAccessibilityActive(
browsing_context.webview_id,
pipeline.id,
active,
));
}
}
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@mrobinson said:

Is the idea that this will be enabled or disabled per-WebView in the future? If so, the external-facing API should likely be on WebView in the API. If not (and I think that's a perfectly fine decision), then this code should probably iterate though each EventLoop by iterating through Constellation::event_loops() here.

If you take the second approach, then in ScriptThread (there is one of these per-EventLoop), iterate through all Documents and enable / disable accessibility for every Layout.

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.

@mrobinson Does the latest change do what you had in mind?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes! This is much closer. I offered a suggestion for a different approach, but maybe that isn't necessary here. I think it could come in handy when you want to add support disabling accessibility though.

@alice alice force-pushed the set-accessibility-enabled branch 2 times, most recently from 6656b26 to 34fc937 Compare February 11, 2026 14:37
Comment on lines +1198 to +1201
let _ = pipeline
.event_loop
.send(ScriptThreadMessage::SetAccessibilityActive(true));
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Another option here is to store whether or not accessibility is enabled in each ScriptThread and then seed every new Layout with that information. That would avoid having the possibility of any "in between" time where accessibility seems to be disabled -- maybe a layout happens without it event.

This would require modifying theEventLoop creation code in components/constellation/event_loop.rs. For instance it could be a member of InitialScriptState which is used to initialize the state of a new ScriptThread (one per EventLoop). Then in each ScriptThread you would store the state and ensure that new Layouts have a11y enabled.

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.

I think this is necessary, yeah. So now we have accessibility_active in:

  • Constellation, so that new ScriptThreads have the right configuration
  • InitialScriptState, to pass the value through from Constellation to each new ScriptThread
  • ScriptThread, so that new LayoutThreads have the right configuration
  • LayoutConfig, to pass the value through from ScriptThread to each new LayoutThread

I added a temporary flag in LayoutThread just to have a place for the config to "land" until we add the AccessibilityTree class.

Does this look right to you? Is there somewhere we're storing the flag unnecessarily now? Admittedly I'm still getting my head around the relationships between each of these objects.

Comment on lines +3004 to +3017
fn set_accessibility_active(&mut self, active: bool) {
self.accessibility_active = active;
for browsing_context in self.browsing_contexts.values_mut() {
if let Some(pipeline) = self.pipelines.get(&browsing_context.pipeline_id) {
let _ = pipeline
.event_loop
.send(ScriptThreadMessage::SetAccessibilityActive(
browsing_context.webview_id,
pipeline.id,
active,
));
}
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes! This is much closer. I offered a suggestion for a different approach, but maybe that isn't necessary here. I think it could come in handy when you want to add support disabling accessibility though.

@alice alice force-pushed the set-accessibility-enabled branch from b366aec to 06eb1a1 Compare February 17, 2026 10:24
@delan delan requested a review from mrobinson February 19, 2026 10:11
@alice alice force-pushed the set-accessibility-enabled branch from 06eb1a1 to 9db1350 Compare February 19, 2026 10:34
Copy link
Copy Markdown
Member

@mrobinson mrobinson left a comment

Choose a reason for hiding this comment

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

Sorry for the delay in reviewing. Great stuff! Just a couple tiny nits, but feel free to land this when addressed:

Comment thread components/constellation/constellation.rs
Comment thread components/script/script_thread.rs Outdated
Comment thread components/script/script_thread.rs Outdated
@servo-highfive servo-highfive added S-awaiting-review There is new code that needs to be reviewed. and removed S-awaiting-review There is new code that needs to be reviewed. labels Feb 19, 2026
@delan delan force-pushed the set-accessibility-enabled branch from 2e6959d to 24d67f1 Compare February 20, 2026 05:15
delan and others added 5 commits February 20, 2026 13:16
Co-authored-by: Alice Boxhall <alice@igalia.com>
Signed-off-by: delan azabani <dazabani@igalia.com>
Now, the constellation loops over its event_loops, and each script_thread loops over its documents.

Signed-off-by: Alice Boxhall <alice@igalia.com>
Also adds accessibility_active fields in InitialScriptState and LayoutConfig, so ScriptThread and LayoutThread can be initialized with the correct accessibility_active state.

Signed-off-by: Alice Boxhall <alice@igalia.com>
Signed-off-by: Alice Boxhall <alice@igalia.com>
Signed-off-by: delan azabani <dazabani@igalia.com>
Signed-off-by: delan azabani <dazabani@igalia.com>
Signed-off-by: delan azabani <dazabani@igalia.com>
@delan delan force-pushed the set-accessibility-enabled branch from 24d67f1 to 2ccb910 Compare February 20, 2026 05:16
@delan delan enabled auto-merge February 20, 2026 05:16
@delan delan added this pull request to the merge queue Feb 20, 2026
@servo-highfive servo-highfive added the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Feb 20, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Feb 20, 2026
@servo-highfive servo-highfive added S-tests-failed The changes caused existing tests to fail. and removed S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. labels Feb 20, 2026
Signed-off-by: delan azabani <dazabani@igalia.com>
@servo-highfive servo-highfive removed the S-tests-failed The changes caused existing tests to fail. label Feb 20, 2026
@delan delan enabled auto-merge February 20, 2026 05:48
@delan delan added this pull request to the merge queue Feb 20, 2026
@servo-highfive servo-highfive added the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Feb 20, 2026
Merged via the queue into servo:main with commit c07682f Feb 20, 2026
30 checks passed
@delan delan deleted the set-accessibility-enabled branch February 20, 2026 06:47
@servo-highfive servo-highfive removed the S-awaiting-merge The PR is in the process of compiling and running tests on the automated CI. label Feb 20, 2026
github-merge-queue Bot pushed a commit that referenced this pull request Mar 19, 2026
in #42336, we added a
[Servo](https://doc.servo.org/servo/struct.Servo.html)-global API for
controlling whether accessibility is active. the idea was that when the
embedder activates accessibility, all webviews and documents activate
accessibility and start sending AccessKit tree updates, and vice versa
when they deactivate.

we found a problem with this approach in #42338. global activation of
accessibility makes it too easy to accidentally cause a panic in
AccessKit, and harder than it needs to be for embedders to learn that
they are responsible for grafting each webview’s subtree into their main
AccessKit tree as soon as accessibility is activated. this is due to an
invariant of the AccessKit subtree API: if a subtree starts sending
updates before the graft node is created, the program panics.

this patch reworks accessibility activation to make it per-webview. by
requiring embedders to explicitly activate accessibility for a webview,
we can communicate the AccessKit invariant via our API docs.

Testing: this patch includes an initial accessibility test in libservo
Fixes: part of #4344, extracted from our work in #42338

---------

Signed-off-by: Alice Boxhall <alice@igalia.com>
Signed-off-by: delan azabani <dazabani@igalia.com>
Co-authored-by: Alice Boxhall <alice@igalia.com>
Gae24 pushed a commit to Gae24/servo that referenced this pull request Mar 26, 2026
in servo#42336, we added a
[Servo](https://doc.servo.org/servo/struct.Servo.html)-global API for
controlling whether accessibility is active. the idea was that when the
embedder activates accessibility, all webviews and documents activate
accessibility and start sending AccessKit tree updates, and vice versa
when they deactivate.

we found a problem with this approach in servo#42338. global activation of
accessibility makes it too easy to accidentally cause a panic in
AccessKit, and harder than it needs to be for embedders to learn that
they are responsible for grafting each webview’s subtree into their main
AccessKit tree as soon as accessibility is activated. this is due to an
invariant of the AccessKit subtree API: if a subtree starts sending
updates before the graft node is created, the program panics.

this patch reworks accessibility activation to make it per-webview. by
requiring embedders to explicitly activate accessibility for a webview,
we can communicate the AccessKit invariant via our API docs.

Testing: this patch includes an initial accessibility test in libservo
Fixes: part of servo#4344, extracted from our work in servo#42338

---------

Signed-off-by: Alice Boxhall <alice@igalia.com>
Signed-off-by: delan azabani <dazabani@igalia.com>
Co-authored-by: Alice Boxhall <alice@igalia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-awaiting-review There is new code that needs to be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants