Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp (289354 => 289355)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp 2022-02-08 03:00:28 UTC (rev 289354)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp 2022-02-08 03:31:51 UTC (rev 289355)
@@ -232,7 +232,7 @@
}
if (updateNodeMap)
- m_nodeMap.set(axObject.objectID(), axObject.childrenIDs());
+ m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { parentID, axObject.childrenIDs() });
if (!parentID.isValid()) {
Locker locker { m_changeLogLock };
@@ -252,7 +252,7 @@
AXID parentID = nodeChange.isolatedObject->parent();
if (parentID.isValid()) {
ASSERT_WITH_MESSAGE(m_nodeMap.contains(parentID), "node map should've contained parentID: %s", parentID.loggingString().utf8().data());
- auto siblingsIDs = m_nodeMap.get(parentID);
+ auto siblingsIDs = m_nodeMap.get(parentID).childrenIDs;
m_pendingChildrenUpdates.append({ parentID, WTFMove(siblingsIDs) });
}
@@ -259,7 +259,7 @@
AXID objectID = nodeChange.isolatedObject->objectID();
ASSERT_WITH_MESSAGE(objectID != parentID, "object ID was the same as its parent ID (%s) when queueing a node change", objectID.loggingString().utf8().data());
ASSERT_WITH_MESSAGE(m_nodeMap.contains(objectID), "node map should've contained objectID: %s", objectID.loggingString().utf8().data());
- auto childrenIDs = m_nodeMap.get(objectID);
+ auto childrenIDs = m_nodeMap.get(objectID).childrenIDs;
m_pendingChildrenUpdates.append({ objectID, WTFMove(childrenIDs) });
}
@@ -298,7 +298,7 @@
axChildrenIDs.uncheckedAppend(axChild->objectID());
}
- m_nodeMap.set(axObject.objectID(), axChildrenIDs);
+ m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { parentID, axChildrenIDs });
}
void AXIsolatedTree::updateNode(AXCoreObject& axObject)
@@ -369,8 +369,11 @@
idsBeingChanged.add(change.isolatedObject->objectID());
changes.append(WTFMove(change));
- if (axParent)
- m_nodeMap.set(axParent->objectID(), axParent->childrenIDs());
+ if (axParent && m_nodeMap.contains(axParent->objectID())) {
+ auto ids = m_nodeMap.get(axParent->objectID());
+ ids.childrenIDs = axParent->childrenIDs();
+ m_nodeMap.set(axParent->objectID(), WTFMove(ids));
+ }
axObject = axParent;
}
@@ -403,7 +406,8 @@
// isolated object to the closest existing ancestor.
Vector<NodeChange> changes = nodeAncestryChanges(axObject, idsBeingChanged);
- auto oldChildrenIDs = m_nodeMap.get(axObject.objectID());
+ auto oldIDs = m_nodeMap.get(axObject.objectID());
+ auto& oldChildrenIDs = oldIDs.childrenIDs;
const auto& newChildren = axObject.children();
auto newChildrenIDs = axObject.childrenIDs(false);
@@ -421,7 +425,7 @@
collectNodeChangesForSubtree(*newChildren[i], axObject.objectID(), true, changes, &idsBeingChanged);
}
}
- m_nodeMap.set(axObject.objectID(), newChildrenIDs);
+ m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { oldIDs.parentID, newChildrenIDs });
// What is left in oldChildrenIDs are the IDs that are no longer children of axObject.
// Thus, remove them from m_nodeMap and queue them to be removed from the tree.
@@ -431,7 +435,7 @@
// 1. Object 123 is slated to be a child of this object (i.e. in newChildren), and we collect node changes for it.
// 2. Object 123 is currently a member of a subtree of some other object in oldChildrenIDs.
// 3. Thus, we don't want to delete Object 123 from the nodemap, instead allowing it to be moved.
- removeSubtreeFromNodeMap(axID, idsBeingChanged);
+ removeSubtreeFromNodeMap(axID, &axObject, idsBeingChanged);
}
queueChangesAndRemovals(changes, oldChildrenIDs);
}
@@ -490,24 +494,34 @@
m_pendingLoadingProgress = newProgressValue;
}
-void AXIsolatedTree::removeNode(AXID axID)
+void AXIsolatedTree::removeNode(const AXCoreObject& axObject)
{
AXTRACE("AXIsolatedTree::removeNode");
- AXLOG(makeString("AXID ", axID.loggingString()));
+ AXLOG(makeString("objectID ", axObject.objectID().loggingString()));
ASSERT(isMainThread());
- m_nodeMap.remove(axID);
- Locker locker { m_changeLogLock };
- m_pendingNodeRemovals.append(axID);
+ removeSubtreeFromNodeMap(axObject.objectID(), axObject.parentObjectUnignored());
+ queueChangesAndRemovals({ }, { axObject.objectID() });
}
-void AXIsolatedTree::removeSubtreeFromNodeMap(AXID axID, const HashSet<AXID>& idsToKeep)
+void AXIsolatedTree::removeSubtreeFromNodeMap(AXID objectID, AXCoreObject* axParent, const HashSet<AXID>& idsToKeep)
{
- AXTRACE("AXIsolatedTree::removeSubtree");
- AXLOG(makeString("Removing subtree for axID ", axID.loggingString()));
+ AXTRACE("AXIsolatedTree::removeSubtreeFromNodeMap");
+ AXLOG(makeString("Removing subtree for objectID ", objectID.loggingString()));
ASSERT(isMainThread());
- Vector<AXID> removals = { axID };
+ if (!m_nodeMap.contains(objectID)) {
+ AXLOG("Tried to remove AXID that is no longer in m_nodeMap.");
+ return;
+ }
+
+ AXID axParentID = axParent ? axParent->objectID() : AXID();
+ if (axParentID != m_nodeMap.get(objectID).parentID) {
+ AXLOG(makeString("Tried to remove object from a different parent ", axParentID.loggingString(), ", actual parent ", m_nodeMap.get(objectID).parentID.loggingString(), ", bailing out."));
+ return;
+ }
+
+ Vector<AXID> removals = { objectID };
while (removals.size()) {
AXID axID = removals.takeLast();
if (!axID.isValid() || idsToKeep.contains(axID))
@@ -515,10 +529,17 @@
auto it = m_nodeMap.find(axID);
if (it != m_nodeMap.end()) {
- removals.appendVector(it->value);
+ removals.appendVector(it->value.childrenIDs);
m_nodeMap.remove(axID);
}
}
+
+ // Update the childrenIDs of the parent since one of its children has been removed.
+ if (axParent) {
+ auto ids = m_nodeMap.get(axParentID);
+ ids.childrenIDs = axParent->childrenIDs();
+ m_nodeMap.set(axParentID, WTFMove(ids));
+ }
}
void AXIsolatedTree::applyPendingChanges()
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h (289354 => 289355)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h 2022-02-08 03:00:28 UTC (rev 289354)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h 2022-02-08 03:31:51 UTC (rev 289355)
@@ -359,10 +359,10 @@
double loadingProgress() { return m_loadingProgress; }
void updateLoadingProgress(double);
- // Removes the given node leaving all descendants alone.
- void removeNode(AXID);
- // Removes the given node and all its descendants.
- void removeSubtreeFromNodeMap(AXID, const HashSet<AXID>& = { });
+ // Removes the corresponding isolated object and all descendants from the m_nodeMap and queues their removal from the tree.
+ void removeNode(const AXCoreObject&);
+ // Removes the given node and all its descendants from m_nodeMap.
+ void removeSubtreeFromNodeMap(AXID axID, AXCoreObject*, const HashSet<AXID>& = { });
// Both setRootNodeID and setFocusedNodeID are called during the generation
// of the IsolatedTree.
@@ -397,8 +397,17 @@
AXObjectCache* m_axObjectCache { nullptr };
bool m_usedOnAXThread { true };
- // Only accessed on main thread.
- HashMap<AXID, Vector<AXID>> m_nodeMap;
+ // Stores the parent ID and children IDS for a given IsolatedObject.
+ struct ParentChildrenIDs {
+ AXID parentID;
+ Vector<AXID> childrenIDs;
+ };
+ // Only accessed on the main thread.
+ // A representation of the tree's parent-child relationships. Each
+ // IsolatedObject must have one and only one entry in this map, that maps
+ // its ObjectID to its ParentChildrenIDs struct.
+ HashMap<AXID, ParentChildrenIDs> m_nodeMap;
+
// Only accessed on AX thread requesting data.
HashMap<AXID, Ref<AXIsolatedObject>> m_readerThreadNodeMap;