Skip to content
Browse files
AX: Don't create isolated objects from ignored live objects

Reviewed by Chris Fleizach.

Sometimes, we can get into a state where a live object has dynamically
become ignored but not removed as a child from its parent (since
unignored objects are the only thing that should be in any
AccessibilityObject::m_children). This can cause us to create an
isolated object for this ignored live object.

With this change, we now return a std::nullopt NodeChange for an
ignored live object.

I split this change off from a different patch improving our handling of
modals. It is required to make accessibility/aria-modal-multiple-dialogs.html
pass in isolated tree mode.

* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h:

Canonical link:
git-svn-id: 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
twilco committed May 26, 2022
1 parent 8fd6de7 commit db65d107bbf3e5828ca19729eb5db6a4fa2a8c25
Showing 2 changed files with 16 additions and 10 deletions.
@@ -181,19 +181,23 @@ void AXIsolatedTree::generateSubtree(AXCoreObject& axObject)
queueRemovalsAndUnresolvedChanges({ });

AXIsolatedTree::NodeChange AXIsolatedTree::nodeChangeForObject(AXCoreObject& axObject, AttachWrapper attachWrapper)
std::optional<AXIsolatedTree::NodeChange> AXIsolatedTree::nodeChangeForObject(AXCoreObject& axObject, AttachWrapper attachWrapper)

auto object = AXIsolatedObject::create(axObject, this);
NodeChange nodeChange { object, nullptr };
// We should never create an isolated object from an ignored object.
if (axObject.accessibilityIsIgnored())
return std::nullopt;

if (!object->objectID().isValid()) {
if (!axObject.objectID().isValid()) {
// Either the axObject has an invalid ID or something else went terribly wrong. Don't bother doing anything else.
return nodeChange;
return std::nullopt;

auto object = AXIsolatedObject::create(axObject, this);
NodeChange nodeChange { object, nullptr };

if (attachWrapper == AttachWrapper::OnMainThread)
@@ -260,7 +264,8 @@ void AXIsolatedTree::queueRemovalsAndUnresolvedChanges(const Vector<AXID>& subtr
for (const auto& unresolvedAppend : m_unresolvedPendingAppends) {
if (auto* axObject = cache->objectFromAXID(unresolvedAppend.key))
resolvedAppends.uncheckedAppend(nodeChangeForObject(*axObject, unresolvedAppend.value));
if (auto nodeChange = nodeChangeForObject(*axObject, unresolvedAppend.value))
@@ -306,9 +311,10 @@ void AXIsolatedTree::updateNode(AXCoreObject& axObject)
// Otherwise, resolve the change immediately and queue it up.
// In both cases, we can't attach the wrapper immediately on the main thread, since the wrapper could be in use
// on the AX thread (because this function updates an existing node).
auto change = nodeChangeForObject(axObject, AttachWrapper::OnAXThread);
Locker locker { m_changeLogLock };
if (auto change = nodeChangeForObject(axObject, AttachWrapper::OnAXThread)) {
Locker locker { m_changeLogLock };

void AXIsolatedTree::updateNodeProperty(AXCoreObject& axObject, AXPropertyName property)
@@ -386,7 +386,7 @@ class AXIsolatedTree : public ThreadSafeRefCounted<AXIsolatedTree> {
static HashMap<PageIdentifier, Ref<AXIsolatedTree>>& treePageCache() WTF_REQUIRES_LOCK(s_cacheLock);

enum class AttachWrapper : bool { OnMainThread, OnAXThread };
NodeChange nodeChangeForObject(AXCoreObject&, AttachWrapper = AttachWrapper::OnMainThread);
std::optional<NodeChange> nodeChangeForObject(AXCoreObject&, AttachWrapper = AttachWrapper::OnMainThread);
void collectNodeChangesForSubtree(AXCoreObject&);
void queueChange(const NodeChange&) WTF_REQUIRES_LOCK(m_changeLogLock);
void queueRemovals(const Vector<AXID>&);

0 comments on commit db65d10

Please sign in to comment.