Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 0c6fba63ba28ce7dcb2cc90e9afe32acbb488043
      
https://github.com/WebKit/WebKit/commit/0c6fba63ba28ce7dcb2cc90e9afe32acbb488043
  Author: Andres Gonzalez <[email protected]>
  Date:   2026-07-28 (Tue, 28 Jul 2026)

  Changed paths:
    A 
LayoutTests/accessibility/mac/text-stitching-selection-notification-element-expected.txt
    A 
LayoutTests/accessibility/mac/text-stitching-selection-notification-element.html
    M Source/WebCore/accessibility/AXCoreObject.cpp
    M Source/WebCore/accessibility/AXCoreObject.h
    M Source/WebCore/accessibility/mac/AXObjectCacheMac.mm
    M Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm

  Log Message:
  -----------
  AX: SelectedTextChanged should report the stitch representative, not a 
stitched-away text member
https://bugs.webkit.org/show_bug.cgi?id=320427
<rdar://problem/183385743>

Reviewed by Tyler Wilcock.

Accessibility text stitching combines a paragraph's inline text runs into a 
single
representative AXStaticText and removes the individual (stitched-away) runs 
from their
parent's exposed children (see childrenAfterStitching in AXCoreObject.cpp). 
Because those
members are no longer present in their parent's children, any AT-facing API 
that hands a
single object back to the client must resolve a stitched-away member to its 
representative;
otherwise it exposes an element that cannot be found in the tree it is 
supposedly part of.

309924@main added that resolution for the NSAccessibilityUIElementForTextMarker 
path
(handleUIElementForTextMarkerAttribute), but the SelectedTextChanged 
notification posted by
postTextSelectionChangePlatformNotification still targeted the stitched-away 
member. That
notification is the one an assistive client such as VoiceOver uses to follow 
the caret while
the user reads a read-only web document line by line with the arrow keys (for 
example, an
HTML mail message body). When the caret lands inside a stitched-away run, the 
client is handed
the member object that stitching removed from its parent's children. On the next
layout-changed notification VoiceOver re-validates that its focused element is 
still among its
parent's children, does not find it, concludes the focused element has been 
removed, and
re-homes focus to the web area, re-announcing the entire message from the 
beginning. The
AXUIElementForTextMarker fix did not cover this case because the element the 
client caches for
the caret comes from the selection-change notification, not from resolving a 
text marker.

This patch factors the "resolve a stitched-away object to its representative" 
step into a
single shared helper, AXCoreObject::stitchRepresentativeOrSelf(), and routes 
both AT-facing
single-object paths through it:

    1. handleUIElementForTextMarkerAttribute now calls the helper, replacing 
the inline
       resolution added in 309924@main.
    2. postTextSelectionChangePlatformNotification calls the helper before 
building and posting
       the notification, so the change element 
(NSAccessibilityTextChangeElement) and the
       object the notification is posted on are the exposed representative.

The helper resolves the representative tree-agnostically via
AXTextMarker { treeID(), representativeID, 0 }.object(), and returns the object 
itself when it
is not stitched away, so it is a no-op for non-stitched content and behaves 
correctly on both
the main-thread and the isolated tree. Stitching's presentation is unchanged: 
the individual
members are still removed from their parent's children, and only the single 
object handed to
the assistive client for the caret's position is corrected to the 
representative that is
actually present in the tree. The selected-text-marker range carried in the 
notification is
still computed from the live selection, so the reported caret range is 
unaffected.

The new test moves the caret into a stitched-away run of a read-only paragraph 
using the
accessibility selection API and verifies that the SelectedTextChanged change 
element is the
representative, whose value spans the whole run, rather than the individual 
member.

Test: accessibility/mac/text-stitching-selection-notification-element.html

* 
LayoutTests/accessibility/mac/text-stitching-selection-notification-element-expected.txt:
 Added.
* 
LayoutTests/accessibility/mac/text-stitching-selection-notification-element.html:
 Added.
* Source/WebCore/accessibility/AXCoreObject.cpp:
(WebCore::AXCoreObject::stitchRepresentativeOrSelf):
* Source/WebCore/accessibility/AXCoreObject.h:
* Source/WebCore/accessibility/mac/AXObjectCacheMac.mm:
(WebCore::AXObjectCache::postTextSelectionChangePlatformNotification):
* Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(handleUIElementForTextMarkerAttribute):

Canonical link: https://commits.webkit.org/318112@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to