Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 507dba2fa32ad23cba904af464524b9d8c62af0d
https://github.com/WebKit/WebKit/commit/507dba2fa32ad23cba904af464524b9d8c62af0d
Author: Tyler Wilcock <[email protected]>
Date: 2026-08-10 (Mon, 10 Aug 2026)
Changed paths:
A LayoutTests/accessibility/append-and-remove-in-one-cycle-expected.txt
A LayoutTests/accessibility/append-and-remove-in-one-cycle.html
M Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp
M Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h
Log Message:
-----------
AX: An append queued after a subtree removal can be incorrectly discarded as
stale
https://bugs.webkit.org/show_bug.cgi?id=321357
rdar://184389421
Reviewed by Dominic Mazzoni.
A batch of pending changes carries appends and subtree removals in two separate
vectors, so the same AXID can appear in both, and the relative order of the two
decisions is not recoverable from the batch. removeStaleAppends has to tell a
leftover append (the object was appended, then genuinely deleted, so applying
the
append would resurrect a dead object) apart from a reparent (the object was
removed
from its old parent and appended under a new one, so the append must be kept),
and
it inferred the order from parentage. Differing parents meant a move, matching
parents meant stale.
That inference is wrong when a node is removed from a parent and then
legitimately
re-added under that same parent. The parents match, so the append is judged
stale
and dropped, even though it is the newer decision. The object is then missing
from
the tree while the main thread's node map still lists it as a child of that
parent.
owner.setAttribute("aria-owns", "child"); // cycle 1: remove child from parent,
// append child under owner
owner.remove(); // cycle 2: append child under
natural parent again
Fix this by recording the order instead of inferring it. nextChangeSequence()
creates a monotonic
counter onto NodeChange and NodeAndParentID at the point the main thread
decides on
the append or removal, and removeStaleAppends now drops an append only when it
was
decided before the removal that would invalidate it.
The test exercises the merged-batch case via aria-owns, which moves an object
in the
accessibility tree without touching the render tree so the object keeps its
AXID. A
DOM reparent cannot reach this code, as it destroys and recreates the renderer
and the
new parent's append is therefore for a new AXID.
Note the test passes both with and without this change on trunk. Reaching the
bug
requires two main-thread update cycles to land in one batch before the
accessibility
thread applies it, which only happens deterministically with the
browser-tick-based
batching atomic tree updates in https://bugs.webkit.org/show_bug.cgi?id=316148,
where
this test does fail without this fix.
* LayoutTests/accessibility/append-and-remove-in-one-cycle-expected.txt: Added.
* LayoutTests/accessibility/append-and-remove-in-one-cycle.html: Added.
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:
(WebCore::AXIsolatedTree::createEmptyContent):
(WebCore::AXIsolatedTree::nodeChangeForObject):
(WebCore::AXIsolatedTree::addUnconnectedNode):
(WebCore::AXIsolatedTree::resolveAppends):
(WebCore::AXIsolatedTree::collectNodeChangesForSubtree):
(WebCore::AXIsolatedTree::updateNode):
(WebCore::AXIsolatedTree::updateChildren):
(WebCore::AXIsolatedTree::removeNode):
(WebCore::AXIsolatedTree::removeStaleAppends):
(WebCore::AXIsolatedTree::processQueuedNodeUpdates):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h:
(WebCore::AXIsolatedTree::NodeChange::NodeChange):
(WebCore::AXIsolatedTree::nextChangeSequence):
Canonical link: https://commits.webkit.org/318905@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications