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

Reply via email to