Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: eb755a4654c3b939d8da1f74ac5aba81be427d73
https://github.com/WebKit/WebKit/commit/eb755a4654c3b939d8da1f74ac5aba81be427d73
Author: Tyler Wilcock <[email protected]>
Date: 2025-11-26 (Wed, 26 Nov 2025)
Changed paths:
A LayoutTests/accessibility/dynamic-text-stitching-expected.txt
A LayoutTests/accessibility/dynamic-text-stitching.html
M LayoutTests/platform/glib/TestExpectations
M LayoutTests/platform/ios/TestExpectations
M LayoutTests/resources/accessibility-helper.js
M Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
M Source/WebCore/Headers.cmake
M Source/WebCore/Sources.txt
M Source/WebCore/WebCore.xcodeproj/project.pbxproj
M Source/WebCore/accessibility/AXCoreObject.cpp
M Source/WebCore/accessibility/AXCoreObject.h
A Source/WebCore/accessibility/AXID.h
M Source/WebCore/accessibility/AXLogger.cpp
M Source/WebCore/accessibility/AXObjectCache.cpp
M Source/WebCore/accessibility/AXObjectCache.h
A Source/WebCore/accessibility/AXStitchUtilities.cpp
A Source/WebCore/accessibility/AXStitchUtilities.h
M Source/WebCore/accessibility/AXUtilities.cpp
M Source/WebCore/accessibility/AXUtilities.h
M Source/WebCore/accessibility/AccessibilityNodeObject.cpp
M Source/WebCore/accessibility/AccessibilityNodeObject.h
M Source/WebCore/accessibility/AccessibilityObject.h
M Source/WebCore/accessibility/AccessibilityRenderObject.cpp
M Source/WebCore/accessibility/AccessibilityScrollView.cpp
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/isolatedtree/AXIsolatedTree.cpp
M Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h
M Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
M Source/WebCore/layout/integration/inline/InlineIteratorBox.h
M Source/WebCore/layout/integration/inline/InlineIteratorBoxLegacyPath.h
M Source/WebCore/layout/integration/inline/InlineIteratorBoxModernPath.h
M Source/WebCore/page/DeprecatedGlobalSettings.h
M Source/WebCore/rendering/RenderBlockFlow.cpp
Log Message:
-----------
AX: Stitch adjacent text elements together in the accessibility tree, in turn
requiring ATs to do less work and providing a better user experience during
element navigation
https://bugs.webkit.org/show_bug.cgi?id=302894
rdar://165159758
Reviewed by Joshua Hoffman.
Prior to this commit, the WebKit accessibility tree exposes text in a way that
matches the DOM and render tree. This
provides a poor user experience, because the presence of spans or other
elements, or even just whitespace can result
in text nodes being split, despite the visual rendering still looking
contiguous. As a concrete example, this simple text
requires 8 swipes for iOS VoiceOver to traverse through:
```
<span>Hello</span> <span>world</span>
<br/>
<span>Foo</span> <span><a href="#foo">bar</a></span> <span>baz</span>
<span>last</span>
```
With this commit, we implement a new feature called accessibility text
stitching, which does what it sounds like --
stitches adjacent text elements into one, and prevents the exposure of the
stitched text in the accessibility tree.
After this commit, that same example only requires three swipes — one for the
text before the link, one for the link,
and one for the text after the link.
Specfically, this commit introduces the concept of `stithedUnignoredChildren`,
and uses it in place of unignored children in some
places (only where necessary, depending on the context, since computing
stitched children is even more work on top of
unignored children).
Test accessibility/dynamic-text-stitching.html added. This is also effectively
tested by many other layout tests which
expect string values of static text elements (our existing test suite pointed
me at many bugs which I fixed).
* LayoutTests/accessibility/dynamic-text-stitching-expected.txt: Added.
* LayoutTests/accessibility/dynamic-text-stitching.html: Added.
* LayoutTests/resources/accessibility-helper.js:
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/accessibility/AXCoreObject.cpp:
(WebCore::transformToFinalChildren):
(WebCore::AXCoreObject::finalChildren):
(WebCore::AXCoreObject::blockFlowAncestor const):
(WebCore::AXCoreObject::stitchStateFromGroups const):
(WebCore::AXCoreObject::crossFrameFinalChildren):
(WebCore::AXCoreObject::contents):
* Source/WebCore/accessibility/AXCoreObject.h:
(WebCore::AXCoreObject::isBlockFlow const):
(WebCore::AXCoreObject::hasStitchableRole const):
(WebCore::AXCoreObject::blockFlowAncestorForStitchable const):
(WebCore::AXCoreObject::StitchState::StitchState):
(WebCore::AXCoreObject::stitchState const):
(WebCore::AXCoreObject::stitchedIntoObject const):
* Source/WebCore/accessibility/AXID.h: Added.
* Source/WebCore/accessibility/AXLogger.cpp:
(WebCore::operator<<):
* Source/WebCore/accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::AXObjectCache):
(WebCore::AXObjectCache::stitchGroupsOwnedBy):
(WebCore::AXObjectCache::onLaidOutInlineContent):
* Source/WebCore/accessibility/AXObjectCache.h:
* Source/WebCore/accessibility/AXSearchManager.cpp:
(WebCore::appendChildrenToArray):
* Source/WebCore/accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::isBlockFlow const):
(WebCore::hasEnclosingInputElement):
(WebCore::hasStitchBreakingRole):
(WebCore::hasStitchBreakingTag):
(WebCore::isStitchBreakingElement):
(WebCore::shouldStopStitchingAt):
(WebCore::AccessibilityNodeObject::stitchGroups const):
(WebCore::AccessibilityNodeObject::stitchState const):
(WebCore::AccessibilityNodeObject::stringValue const):
* Source/WebCore/accessibility/AccessibilityNodeObject.h:
* Source/WebCore/accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::stitchGroups const):
* Source/WebCore/accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::stringValue const):
(WebCore::AccessibilityRenderObject::boundingBoxRect const):
* Source/WebCore/accessibility/StitchGroup.cpp: Added.
(WebCore::StitchGroup::lastNode const):
(WebCore::StitchGroup::lastObject const):
* Source/WebCore/accessibility/StitchGroup.h: Added.
(WebCore::StitchGroup::StitchGroup):
(WebCore::StitchGroup::vector const):
(WebCore::StitchGroups::StitchGroups):
(WebCore::StitchGroups::vector const):
* Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityTextMarker accessibilityObject]):
(-[WebAccessibilityObjectWrapper accessibilityElements]):
(-[WebAccessibilityObjectWrapper accessibilityElementCount]):
(-[WebAccessibilityObjectWrapper accessibilityElementAtIndex:]):
(-[WebAccessibilityObjectWrapper indexOfAccessibilityElement:]):
(-[WebAccessibilityObjectWrapper accessibilityRowRange]):
(-[WebAccessibilityObjectWrapper containsUnnaturallySegmentedChildren]):
(-[WebAccessibilityObjectWrapper accessibilityObjectForTextMarker:]):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp:
(WebCore::isDefaultValue):
(WebCore::AXIsolatedObject::stitchGroupsView const):
(WebCore::AXIsolatedObject::stitchState const):
(WebCore::AXIsolatedObject::relativeFrame const):
(WebCore::AXIsolatedObject::stringValue const):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h:
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:
(WebCore::AXIsolatedTree::updateNodeProperties):
(WebCore::convertToPropertyFlag):
(WebCore::createIsolatedObjectData):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h:
* Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(children):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
(-[WebAccessibilityObjectWrapper accessibilityIndexOfChild:]):
(-[WebAccessibilityObjectWrapper accessibilityArrayAttributeCount:]):
(-[WebAccessibilityObjectWrapper
_accessibilityChildrenFromIndex:maxCount:returnPlatformElements:]):
* Source/WebCore/layout/integration/inline/InlineIteratorBox.h:
(WebCore::InlineIterator::Box::isAtomicInlineBox const):
* Source/WebCore/layout/integration/inline/InlineIteratorBoxLegacyPath.h:
(WebCore::InlineIterator::BoxLegacyPath::isAtomicInlineBox const):
* Source/WebCore/layout/integration/inline/InlineIteratorBoxModernPath.h:
(WebCore::InlineIterator::BoxModernPath::isAtomicInlineBox const):
* Source/WebCore/page/DeprecatedGlobalSettings.h:
(WebCore::DeprecatedGlobalSettings::setAccessibilityTextStitchingEnabled):
(WebCore::DeprecatedGlobalSettings::accessibilityTextStitchingEnabled):
* Source/WebCore/rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::layoutInlineContent):
Canonical link: https://commits.webkit.org/303574@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications