Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 61766a5e91da5358a559eef454ebca0f86ac4b1f
https://github.com/WebKit/WebKit/commit/61766a5e91da5358a559eef454ebca0f86ac4b1f
Author: Andres Gonzalez <[email protected]>
Date: 2026-07-16 (Thu, 16 Jul 2026)
Changed paths:
A
LayoutTests/accessibility/mac/line-text-marker-range-for-out-of-flow-image-expected.txt
A
LayoutTests/accessibility/mac/line-text-marker-range-for-out-of-flow-image.html
M Source/WebCore/accessibility/AccessibilityObject.cpp
Log Message:
-----------
AX: VoiceOver reads nothing for a line containing only an out-of-flow
decorative image
https://bugs.webkit.org/show_bug.cgi?id=319503
<rdar://problem/182309215>
Reviewed by Dominic Mazzoni.
When VoiceOver reads by line (arrow navigation) with the accessibility
isolated tree OFF, a line whose only content is an out-of-flow
(position:absolute or floated) decorative image (e.g. <img alt=""> whose
accessible name lives on an ancestor) is announced as nothing. With the
isolated tree ON the same line is correctly announced as "image".
Root cause: the two code paths disagree about whether such an element has
a line. VoiceOver asks for the caret's line via
kAXLineTextMarkerRangeForTextMarker, which on the main thread calls
AccessibilityObject::lineRangeForPosition(). That function computes
startOfLine(visiblePosition); for a caret at an out-of-flow replaced
element startOfLine is null, because startPositionForLine() finds
RenderedPosition(c).lineBox() == null (an out-of-flow RenderReplaced /
RenderBox generates no inline line box) and its only null-line-box rescue
requires isRenderBlock(), which a RenderReplaced is not. lineRangeForPosition
therefore returns an empty range, which becomes an AXTextMarkerRange with
null boundary points, so simpleRange() is nullopt and
attributedStringForTextMarkerRange() returns nil -- VoiceOver receives no
text and speaks nothing. contentForRange() is never reached, so this is a
line-range failure, not a string-extraction one.
The isolated tree avoids this because AccessibilityRenderObject::textRuns()
emits an objectReplacementCharacter run for any isReplacedElement() and, in
its isFloatingOrOutOfFlowPositioned() branch, gives the element its own
synthetic single-object line; lineRange() over those runs then yields a
valid range that resolves to an attachment ("image").
Fix: mirror that behavior on the main thread. In lineRangeForPosition(),
when startOfLine is null and the object is an out-of-flow replaced element,
fall back to a range that spans the element's own node. Use
makeRangeSelectingNode() (the {parent, index}..{parent, index+1} span), not
simpleRange()/rangeForNodeContents(): for an accessibility-ignored replaced
element rangeForNodeContents() collapses to an empty {(node,0),(node,0)}
range (it only selects the node itself when replacedNodeNeedsCharacter() is
true, which is false for an ignored image), and TextIterator over a
collapsed range short-circuits before handleReplacedElement(). A
node-selecting range makes TextIterator descend into the image and emit the
zero-length replaced stop, which contentForRange() turns into the object
wrapper attachment, so line reading announces "image".
The new code runs only in the previously-dead start.isNull() branch and is
further gated on isReplacedElement() && isRendererReplacedElement() &&
isFloatingOrOutOfFlowPositioned(), so in-flow decorative images (which sit
on a real line box and have a non-null startOfLine) are unaffected, and
there is no impact on text-offset math, selection, or editing.
The test uses a labeled out-of-flow image so it is reachable from the AX
tree in the test harness; the fix branch it exercises is gated on the
element being out-of-flow and replaced, independent of the image's name,
and the test passes with the accessibility isolated tree both on and off.
* Source/WebCore/accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::lineRangeForPosition):
*
LayoutTests/accessibility/mac/line-text-marker-range-for-out-of-flow-image.html:
Added.
*
LayoutTests/accessibility/mac/line-text-marker-range-for-out-of-flow-image-expected.txt:
Added.
Canonical link: https://commits.webkit.org/317341@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications