Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: f7017aa3657ec9f09053e457c85a752203019aa1
https://github.com/WebKit/WebKit/commit/f7017aa3657ec9f09053e457c85a752203019aa1
Author: Tyler Wilcock <[email protected]>
Date: 2026-01-21 (Wed, 21 Jan 2026)
Changed paths:
A LayoutTests/accessibility/button-hit-test-expected.txt
A LayoutTests/accessibility/button-hit-test.html
M LayoutTests/platform/ios/TestExpectations
M Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
M Source/WebCore/accessibility/AXCoreObject.cpp
M Source/WebCore/accessibility/AXCoreObject.h
M Source/WebCore/accessibility/AXLoggerBase.h
M Source/WebCore/accessibility/AXObjectCache.cpp
M Source/WebCore/accessibility/AXObjectCache.h
M Source/WebCore/accessibility/AccessibilityObject.cpp
M Source/WebCore/accessibility/AccessibilityObject.h
M Source/WebCore/accessibility/AccessibilityRenderObject.cpp
M Source/WebCore/accessibility/AccessibilityRenderObject.h
M Source/WebCore/accessibility/AccessibilityScrollView.cpp
M Source/WebCore/accessibility/AccessibilityScrollView.h
M Source/WebCore/accessibility/AccessibilitySlider.cpp
M Source/WebCore/accessibility/AccessibilitySlider.h
M Source/WebCore/accessibility/atspi/AccessibilityObjectComponentAtspi.cpp
M Source/WebCore/accessibility/cocoa/AXTextMarkerCocoa.mm
M Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm
M Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
M Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
M Source/WebCore/accessibility/mac/AXObjectCacheMac.mm
M Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
M Source/WebCore/page/DeprecatedGlobalSettings.h
M Source/WebKit/WebProcess/WebPage/mac/WKAccessibilityWebPageObjectMac.mm
Log Message:
-----------
AX: Implement support for serving hit tests off the main-thread
https://bugs.webkit.org/show_bug.cgi?id=305704
rdar://168366529
Reviewed by Joshua Hoffman.
Prior to this commit, to perform a hit test, the accessibility thread
synchronously waits an unbounded amount of time
on the main-thread. If the main-thread is busy (e.g. because of JavaScript),
this results in jank or hang for ATs.
This commit introduces an implementation of hit testing on the accessibility
thread using the geometry we have cached
off the main-thread (e.g. AXProperty::RelativeFrame). This will generally be
accurate, except in the case of complicated
z-index layering and non-rectangular shaped elements. ~10 layout tests use hit
testing, and the accessibility thread
is used for all of them after this commit, and all pass.
Furthermore, AXIsolatedObject::accessibilityHitTest will try to perform the hit
test on the main-thread first, but if
the main-thread doesn't respond within 15ms, only then will we try to do the
hit test on the accessibility
thread. Based on my testing on gmail.com, across 320 main-thread hit
round-trips, the mean duration was 1.7ms, and the
max duration was 20.2ms, so 15ms should cover most cases and also still
fallback to the accessibility thread relatively
quickly for main-threads that are totally or mostly hung.
In service of this, a new function called
retrieveValueFromMainThreadWithTimeout was created.
There are some things we can do in future patches to improve hit testing
accuracy on the main-thread:
1. When a hit-test goes to the main-thread, given the hit-point, we should
cache in a thread-shareable manner (e.g.
mutex-protected Vector) the bounds for which the result is valid. Then
future hit tests can check this data structure,
and if within one of the cached bounds, we can just return that result,
giving us main-thread accuracy quickly.
This is beneficiial for ATs that do lots of rapid hit tests when tracking
the cursor, like Hover Text.
These cached entries should be flushed when a scroll happens, or any
elements bounds change (though we can
experiment with more / different cache flushing triggers). Maybe they
should also only be valid for a time period,
like 10s, and we clean up any timed out entry on the next hit test.
2. We already track the elements in the most recent painted text
(AXObjectCache::mostRecentlyPaintedText). Can we assume
that things painted last in the most recent paint pass are most likely to
be on top, thus somewhat solving the z-index
issue?
Future work on this feature should test PDFs, widgets, attachments, and mock
objects like spinbuttons, meters, sliders, etc.
Ideally we would create explicit layout tests for these atypical elements and
any others.
Another future improvement: if we detect that the last main-thread hit test
timed out, maybe we can wait less time for
future requests until some cooldown period under the assumption that the
main-thread is busy?
Test: accessibility/button-hit-test.html
* LayoutTests/accessibility/button-hit-test-expected.txt: Added.
* LayoutTests/accessibility/button-hit-test.html: Added.
* LayoutTests/platform/ios/TestExpectations: Enable new test.
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
Add feature flag.
* Source/WebCore/accessibility/AXCoreObject.cpp:
(WebCore::AXCoreObject::partialOrder):
* Source/WebCore/accessibility/AXCoreObject.h:
(WebCore::Accessibility::TimeoutSafeSemaphore::signal):
(WebCore::Accessibility::TimeoutSafeSemaphore::wait):
(WebCore::Accessibility::performFunctionOnMainThreadAndWaitWithTimeout):
(WebCore::Accessibility::retrieveValueFromMainThreadWithTimeout):
* Source/WebCore/accessibility/AXLoggerBase.h:
* Source/WebCore/accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::isAXThreadHitTestingEnabled):
(WebCore::AXObjectCache::AXObjectCache):
(WebCore::AXObjectCache::mapScreenPointToPagePoint const):
(WebCore::AXObjectCache::page const):
* Source/WebCore/accessibility/AXObjectCache.h:
* Source/WebCore/accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::elementAccessibilityHitTest const):
* Source/WebCore/accessibility/AccessibilityObject.h:
* Source/WebCore/accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::computeIsIgnored const):
(WebCore::AccessibilityRenderObject::remoteSVGElementHitTest const):
(WebCore::AccessibilityRenderObject::elementAccessibilityHitTest const):
(WebCore::AccessibilityRenderObject::accessibilityHitTest const):
* Source/WebCore/accessibility/AccessibilityRenderObject.h:
* Source/WebCore/accessibility/AccessibilityScrollView.cpp:
(WebCore::AccessibilityScrollView::accessibilityHitTest const):
* Source/WebCore/accessibility/AccessibilityScrollView.h:
* Source/WebCore/accessibility/AccessibilitySlider.cpp:
(WebCore::AccessibilitySlider::elementAccessibilityHitTest const):
* Source/WebCore/accessibility/AccessibilitySlider.h:
* Source/WebCore/accessibility/cocoa/AXTextMarkerCocoa.mm:
(WebCore::AXTextMarkerRange::AXTextMarkerRange):
* Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper accessibilityHitTest:]):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp:
(WebCore::AXIsolatedObject::accessibilityHitTestInner const):
(WebCore::AXIsolatedObject::screenRelativeRect const):
(WebCore::AXIsolatedObject::node const):
(WebCore::AXIsolatedObject::accessibilityHitTest const): Deleted.
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h:
* Source/WebCore/accessibility/mac/AXObjectCacheMac.mm:
(WebCore::AXObjectCache::isIsolatedTreeEnabled):
* Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper debugDescription]):
* Source/WebCore/page/DeprecatedGlobalSettings.h:
(WebCore::DeprecatedGlobalSettings::setAccessibilityThreadHitTestingEnabled):
(WebCore::DeprecatedGlobalSettings::accessibilityThreadHitTestingEnabled):
* Source/WebKit/WebProcess/WebPage/mac/WKAccessibilityWebPageObjectMac.mm:
(-[WKAccessibilityWebPageObject accessibilityHitTest:]):
Canonical link: https://commits.webkit.org/305966@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications