Diff
Modified: trunk/Source/WebCore/ChangeLog (260944 => 260945)
--- trunk/Source/WebCore/ChangeLog 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/ChangeLog 2020-04-30 12:57:00 UTC (rev 260945)
@@ -1,3 +1,46 @@
+2020-04-30 Andres Gonzalez <[email protected]>
+
+ Add logging of AXIsolatedTree and AXNotifications.
+ https://bugs.webkit.org/show_bug.cgi?id=211214
+
+ Reviewed by Chris Fleizach.
+
+ - Added operator<< implementations for AXIsolatedTree and AX notifications.
+ - Added corresponding AXLogger::log overloads for the above types.
+ - To set the root node and the focused node we are now always using
+ setRootNodeID and setFocusedNodeID respectively. Therefore, before
+ returning the root or the focused nodes, it is necessary to applyPendingChanges.
+
+ * accessibility/AXLogger.cpp:
+ (WebCore::AXLogger::add): Used for recursive logging of the hierarchy.
+ (WebCore::AXLogger::log):
+ (WebCore::operator<<):
+ * accessibility/AXLogger.h:
+ * accessibility/AXObjectCache.cpp:
+ Added logging of the isolated tree when it's generated and before and after updates.
+ (WebCore::AXObjectCache::isolatedTreeFocusedObject):
+ (WebCore::AXObjectCache::generateIsolatedTree):
+ (WebCore::AXObjectCache::updateIsolatedTree):
+ * accessibility/AXObjectCache.h:
+ * accessibility/isolatedtree/AXIsolatedObject.cpp:
+ (WebCore::AXIsolatedObject::focusedUIElement const):
+ * accessibility/isolatedtree/AXIsolatedTree.cpp:
+ (WebCore::AXIsolatedTree::createTreeForPageID):
+ (WebCore::AXIsolatedTree::removeTreeForPageID):
+ (WebCore::AXIsolatedTree::nodeForID const):
+ (WebCore::AXIsolatedTree::generateSubtree):
+ (WebCore::AXIsolatedTree::focusedNode):
+ (WebCore::AXIsolatedTree::rootNode):
+ (WebCore::AXIsolatedTree::setRootNodeID):
+ (WebCore::AXIsolatedTree::setFocusedNodeID):
+ (WebCore::AXIsolatedTree::applyPendingChanges):
+ (WebCore::AXIsolatedTree::focusedUIElement): Renamed focusedNode for naming consistency.
+ (WebCore::AXIsolatedTree::setRootNode): Deleted. Using setRootNodeID instead,
+ (WebCore::AXIsolatedTree::setFocusedNode): Deleted. Use setFocusedNodeID instead.
+ * accessibility/isolatedtree/AXIsolatedTree.h:
+ (WebCore::AXIsolatedTree::treeID const):
+ (WebCore::AXIsolatedTree::treeIdentifier const): renamed treeID for naming consistency.
+
2020-04-30 Philippe Normand <[email protected]>
Unreviewed, GStreamer build warning fix after r260755.
Modified: trunk/Source/WebCore/accessibility/AXLogger.cpp (260944 => 260945)
--- trunk/Source/WebCore/accessibility/AXLogger.cpp 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/AXLogger.cpp 2020-04-30 12:57:00 UTC (rev 260945)
@@ -66,6 +66,37 @@
LOG(Accessibility, "%s", stream.release().utf8().data());
}
+void AXLogger::add(TextStream& stream, const RefPtr<AXCoreObject>& object, bool recursive)
+{
+ if (!object)
+ return;
+
+ stream.increaseIndent();
+ stream << *object;
+
+ if (recursive) {
+ for (auto& child : object->children())
+ add(stream, child, true);
+ }
+ stream.decreaseIndent();
+}
+
+void AXLogger::log(const std::pair<RefPtr<AXCoreObject>, AXObjectCache::AXNotification>& notification)
+{
+ TextStream stream(TextStream::LineMode::MultipleLine);
+ stream << "Notification " << notification.second << " for object " << *notification.first;
+ LOG(Accessibility, "%s", stream.release().utf8().data());
+}
+
+#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
+void AXLogger::log(AXIsolatedTree& tree)
+{
+ TextStream stream(TextStream::LineMode::MultipleLine);
+ stream << tree;
+ LOG(Accessibility, "%s", stream.release().utf8().data());
+}
+#endif
+
TextStream& operator<<(TextStream& stream, AccessibilityRole role)
{
switch (role) {
@@ -527,12 +558,122 @@
return stream;
}
+TextStream& operator<<(TextStream& stream, AXObjectCache::AXNotification notification)
+{
+ switch (notification) {
+ case AXObjectCache::AXNotification::AXActiveDescendantChanged:
+ stream << "AXActiveDescendantChanged";
+ break;
+ case AXObjectCache::AXNotification::AXAutocorrectionOccured:
+ stream << "AXAutocorrectionOccured";
+ break;
+ case AXObjectCache::AXNotification::AXCheckedStateChanged:
+ stream << "AXCheckedStateChanged";
+ break;
+ case AXObjectCache::AXNotification::AXChildrenChanged:
+ stream << "AXChildrenChanged";
+ break;
+ case AXObjectCache::AXNotification::AXCurrentChanged:
+ stream << "AXCurrentChanged";
+ break;
+ case AXObjectCache::AXNotification::AXDisabledStateChanged:
+ stream << "AXDisabledStateChanged";
+ break;
+ case AXObjectCache::AXNotification::AXFocusedUIElementChanged:
+ stream << "AXFocusedUIElementChanged";
+ break;
+ case AXObjectCache::AXNotification::AXLayoutComplete:
+ stream << "AXLayoutComplete";
+ break;
+ case AXObjectCache::AXNotification::AXLoadComplete:
+ stream << "AXLoadComplete";
+ break;
+ case AXObjectCache::AXNotification::AXNewDocumentLoadComplete:
+ stream << "AXNewDocumentLoadComplete";
+ break;
+ case AXObjectCache::AXNotification::AXSelectedChildrenChanged:
+ stream << "AXSelectedChildrenChanged";
+ break;
+ case AXObjectCache::AXNotification::AXSelectedTextChanged:
+ stream << "AXSelectedTextChanged";
+ break;
+ case AXObjectCache::AXNotification::AXValueChanged:
+ stream << "AXValueChanged";
+ break;
+ case AXObjectCache::AXNotification::AXScrolledToAnchor:
+ stream << "AXScrolledToAnchor";
+ break;
+ case AXObjectCache::AXNotification::AXLiveRegionCreated:
+ stream << "AXLiveRegionCreated";
+ break;
+ case AXObjectCache::AXNotification::AXLiveRegionChanged:
+ stream << "AXLiveRegionChanged";
+ break;
+ case AXObjectCache::AXNotification::AXMenuListItemSelected:
+ stream << "AXMenuListItemSelected";
+ break;
+ case AXObjectCache::AXNotification::AXMenuListValueChanged:
+ stream << "AXMenuListValueChanged";
+ break;
+ case AXObjectCache::AXNotification::AXMenuClosed:
+ stream << "AXMenuClosed";
+ break;
+ case AXObjectCache::AXNotification::AXMenuOpened:
+ stream << "AXMenuOpened";
+ break;
+ case AXObjectCache::AXNotification::AXRowCountChanged:
+ stream << "AXRowCountChanged";
+ break;
+ case AXObjectCache::AXNotification::AXRowCollapsed:
+ stream << "AXRowCollapsed";
+ break;
+ case AXObjectCache::AXNotification::AXRowExpanded:
+ stream << "AXRowExpanded";
+ break;
+ case AXObjectCache::AXNotification::AXExpandedChanged:
+ stream << "AXExpandedChanged";
+ break;
+ case AXObjectCache::AXNotification::AXInvalidStatusChanged:
+ stream << "AXInvalidStatusChanged";
+ break;
+ case AXObjectCache::AXNotification::AXPressDidSucceed:
+ stream << "AXPressDidSucceed";
+ break;
+ case AXObjectCache::AXNotification::AXPressDidFail:
+ stream << "AXPressDidFail";
+ break;
+ case AXObjectCache::AXNotification::AXPressedStateChanged:
+ stream << "AXPressedStateChanged";
+ break;
+ case AXObjectCache::AXNotification::AXReadOnlyStatusChanged:
+ stream << "AXReadOnlyStatusChanged";
+ break;
+ case AXObjectCache::AXNotification::AXRequiredStatusChanged:
+ stream << "AXRequiredStatusChanged";
+ break;
+ case AXObjectCache::AXNotification::AXTextChanged:
+ stream << "AXTextChanged";
+ break;
+ case AXObjectCache::AXNotification::AXAriaAttributeChanged:
+ stream << "AXAriaAttributeChanged";
+ break;
+ case AXObjectCache::AXNotification::AXElementBusyChanged:
+ stream << "AXElementBusyChanged";
+ break;
+ default:
+ break;
+ }
+
+ return stream;
+}
+
TextStream& operator<<(TextStream& stream, const AXCoreObject& object)
{
TextStream::GroupScope groupScope(stream);
- stream << "AXCoreObject " << &object;
- stream.dumpProperty("objectID", object.objectID());
+ stream << "objectID " << object.objectID();
+ stream.dumpProperty("identifierAttribute", object.identifierAttribute());
stream.dumpProperty("roleValue", object.roleValue());
+ stream.dumpProperty("address", &object);
auto* parent = object.parentObject();
stream.dumpProperty("parentObject", parent ? parent->objectID() : 0);
@@ -543,4 +684,16 @@
return stream;
}
+#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
+TextStream& operator<<(TextStream& stream, AXIsolatedTree& tree)
+{
+ TextStream::GroupScope groupScope(stream);
+ stream << "treeID " << tree.treeID();
+ stream.dumpProperty("rootNodeID", tree.m_rootNodeID);
+ stream.dumpProperty("focusedNodeID", tree.m_focusedNodeID);
+ AXLogger::add(stream, tree.rootNode(), true);
+ return stream;
+}
+#endif
+
} // namespace WebCore
Modified: trunk/Source/WebCore/accessibility/AXLogger.h (260944 => 260945)
--- trunk/Source/WebCore/accessibility/AXLogger.h 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/AXLogger.h 2020-04-30 12:57:00 UTC (rev 260945)
@@ -25,6 +25,7 @@
#pragma once
+#include "AXObjectCache.h"
#include "AccessibilityObjectInterface.h"
namespace WebCore {
@@ -34,8 +35,13 @@
AXLogger() = default;
AXLogger(const String& methodName);
~AXLogger();
- void log(const String&);
- void log(const AXCoreObject&);
+ static void log(const String&);
+ static void log(const AXCoreObject&);
+ static void log(const std::pair<RefPtr<AXCoreObject>, AXObjectCache::AXNotification>&);
+#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
+ static void log(AXIsolatedTree&);
+#endif
+ static void add(TextStream&, const RefPtr<AXCoreObject>&, bool recursive = false);
private:
String m_methodName;
};
@@ -45,8 +51,7 @@
#define AXLOG(x) (void)0
#else
#define AXTRACE(methodName) AXLogger axLogger(methodName)
-#define AXLOG(x) AXLogger logger; \
- logger.log(x)
+#define AXLOG(x) AXLogger::log(x)
#endif // LOG_DISABLED
} // namespace WebCore
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (260944 => 260945)
--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp 2020-04-30 12:57:00 UTC (rev 260945)
@@ -379,7 +379,7 @@
AXCoreObject* AXObjectCache::isolatedTreeFocusedObject()
{
if (auto tree = getOrCreateIsolatedTree())
- return tree->focusedUIElement().get();
+ return tree->focusedNode().get();
// Should not get here, couldn't create the IsolatedTree.
ASSERT_NOT_REACHED();
@@ -3074,6 +3074,7 @@
#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
Ref<AXIsolatedTree> AXObjectCache::generateIsolatedTree(PageIdentifier pageID, Document& document)
{
+ AXTRACE("AXObjectCache::generateIsolatedTree");
RELEASE_ASSERT(isMainThread());
RefPtr<AXIsolatedTree> tree(AXIsolatedTree::createTreeForPageID(pageID));
@@ -3091,13 +3092,16 @@
auto* axFocus = axObjectCache->focusedObject(document);
if (axFocus)
- tree->setFocusedNode(axFocus->objectID());
+ tree->setFocusedNodeID(axFocus->objectID());
+ AXLOG(*tree);
return makeRef(*tree);
}
void AXObjectCache::updateIsolatedTree(AXCoreObject& object, AXNotification notification)
{
+ AXTRACE("AXObjectCache::updateIsolatedTree");
+ AXLOG(std::make_pair(&object, notification));
if (!m_pageID)
return;
@@ -3104,6 +3108,7 @@
auto tree = AXIsolatedTree::treeForPageID(*m_pageID);
if (!tree)
return;
+ AXLOG(*tree);
switch (notification) {
case AXCheckedStateChanged:
@@ -3116,6 +3121,7 @@
default:
break;
}
+ AXLOG(*tree);
}
// FIXME: should be added to WTF::Vector.
@@ -3130,6 +3136,7 @@
void AXObjectCache::updateIsolatedTree(const Vector<std::pair<RefPtr<AXCoreObject>, AXNotification>>& notifications)
{
+ AXTRACE("AXObjectCache::updateIsolatedTree");
if (!m_pageID)
return;
@@ -3136,11 +3143,13 @@
auto tree = AXIsolatedTree::treeForPageID(*m_pageID);
if (!tree)
return;
+ AXLOG(*tree);
// Filter out multiple notifications for the same object. This avoids
// updating the isolated tree multiple times unnecessarily.
Vector<std::pair<RefPtr<AXCoreObject>, AXNotification>> filteredNotifications;
for (const auto& notification : notifications) {
+ AXLOG(notification);
if (!notification.first || notification.first->objectID() == InvalidAXID)
continue;
@@ -3169,6 +3178,7 @@
break;
}
}
+ AXLOG(*tree);
}
#endif
Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (260944 => 260945)
--- trunk/Source/WebCore/accessibility/AXObjectCache.h 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h 2020-04-30 12:57:00 UTC (rev 260945)
@@ -42,6 +42,10 @@
#include <wtf/glib/GRefPtr.h>
#endif
+namespace WTF {
+class TextStream;
+}
+
namespace WebCore {
class Document;
@@ -618,4 +622,6 @@
#endif
+WTF::TextStream& operator<<(WTF::TextStream&, AXObjectCache::AXNotification);
+
} // namespace WebCore
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp (260944 => 260945)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp 2020-04-30 12:57:00 UTC (rev 260945)
@@ -582,7 +582,7 @@
AXCoreObject* AXIsolatedObject::focusedUIElement() const
{
- return tree()->focusedUIElement().get();
+ return tree()->focusedNode().get();
}
AXCoreObject* AXIsolatedObject::parentObjectUnignored() const
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp (260944 => 260945)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp 2020-04-30 12:57:00 UTC (rev 260945)
@@ -105,7 +105,7 @@
auto newTree = AXIsolatedTree::create();
treePageCache().set(pageID, newTree.copyRef());
- treeIDCache().set(newTree->treeIdentifier(), newTree.copyRef());
+ treeIDCache().set(newTree->treeID(), newTree.copyRef());
return newTree;
}
@@ -123,7 +123,7 @@
tree->setAXObjectCache(nullptr);
treeLocker.unlockEarly();
- treeIDCache().remove(tree->treeIdentifier());
+ treeIDCache().remove(tree->treeID());
}
}
@@ -140,7 +140,6 @@
RefPtr<AXIsolatedObject> AXIsolatedTree::nodeForID(AXID axID) const
{
- AXTRACE("AXIsolatedTree::nodeForID");
return axID != InvalidAXID ? m_readerThreadNodeMap.get(axID) : nullptr;
}
@@ -167,7 +166,7 @@
appendNodeChanges(nodeChanges);
if (parentID == InvalidAXID)
- setRootNode(object);
+ setRootNodeID(object->objectID());
// FIXME: else attach the newly created subtree to its parent.
}
@@ -264,51 +263,38 @@
}
}
-RefPtr<AXIsolatedObject> AXIsolatedTree::focusedUIElement()
+RefPtr<AXIsolatedObject> AXIsolatedTree::focusedNode()
{
AXTRACE("AXIsolatedTree::focusedUIElement");
+ // Apply pending changes in case focus has changed and hasn't been updated.
+ applyPendingChanges();
+ LockHolder locker { m_changeLogLock };
+ AXLOG(makeString("focusedNodeID ", m_focusedNodeID));
return nodeForID(m_focusedNodeID);
}
-
+
RefPtr<AXIsolatedObject> AXIsolatedTree::rootNode()
{
AXTRACE("AXIsolatedTree::rootNode");
+ // Apply pending changes in case the root node is in the pending changes.
+ applyPendingChanges();
+ LockHolder locker { m_changeLogLock };
return nodeForID(m_rootNodeID);
}
-void AXIsolatedTree::setRootNode(Ref<AXIsolatedObject>& root)
+void AXIsolatedTree::setRootNodeID(AXID axID)
{
- AXTRACE("AXIsolatedTree::setRootNode");
- LockHolder locker { m_changeLogLock };
- m_rootNodeID = root->objectID();
- m_readerThreadNodeMap.add(root->objectID(), WTFMove(root));
-}
-
-void AXIsolatedTree::setFocusedNode(AXID axID)
-{
- AXTRACE("AXIsolatedTree::setFocusedNode");
+ AXTRACE("AXIsolatedTree::setRootNodeID");
ASSERT(isMainThread());
LockHolder locker { m_changeLogLock };
- m_focusedNodeID = axID;
- if (axID == InvalidAXID)
- return;
-
- if (m_readerThreadNodeMap.contains(m_focusedNodeID))
- return; // Nothing to do, the focus is set.
-
- // If the focused object is in the pending appends, add it to the reader
- // map, so that we can return the right focused object if requested before
- // pending appends are applied.
- for (const auto& item : m_pendingAppends) {
- if (item.m_isolatedObject->objectID() == m_focusedNodeID
- && m_readerThreadNodeMap.add(m_focusedNodeID, item.m_isolatedObject.get()) && item.m_wrapper)
- m_readerThreadNodeMap.get(m_focusedNodeID)->attachPlatformWrapper(item.m_wrapper.get());
- }
+ m_rootNodeID = axID;
}
void AXIsolatedTree::setFocusedNodeID(AXID axID)
{
AXTRACE("AXIsolatedTree::setFocusedNodeID");
+ AXLOG(makeString("axID ", axID));
+ ASSERT(isMainThread());
LockHolder locker { m_changeLogLock };
m_pendingFocusedNodeID = axID;
}
@@ -337,7 +323,6 @@
void AXIsolatedTree::applyPendingChanges()
{
AXTRACE("AXIsolatedTree::applyPendingChanges");
- RELEASE_ASSERT(!isMainThread());
LockHolder locker { m_changeLogLock };
m_focusedNodeID = m_pendingFocusedNodeID;
@@ -344,6 +329,7 @@
while (m_pendingNodeRemovals.size()) {
auto axID = m_pendingNodeRemovals.takeLast();
+ AXLOG(makeString("removing axID ", axID));
if (axID == InvalidAXID)
continue;
@@ -353,6 +339,7 @@
while (m_pendingSubtreeRemovals.size()) {
auto axID = m_pendingSubtreeRemovals.takeLast();
+ AXLOG(makeString("removing subtree axID ", axID));
if (axID == InvalidAXID)
continue;
@@ -367,6 +354,7 @@
ASSERT((item.m_isolatedObject->wrapper() || item.m_wrapper)
&& !(item.m_isolatedObject->wrapper() && item.m_wrapper));
AXID axID = item.m_isolatedObject->objectID();
+ AXLOG(makeString("appending axID ", axID));
if (axID == InvalidAXID)
continue;
Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h (260944 => 260945)
--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h 2020-04-30 12:52:10 UTC (rev 260944)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h 2020-04-30 12:57:00 UTC (rev 260945)
@@ -33,6 +33,10 @@
#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>
+namespace WTF {
+class TextStream;
+}
+
namespace WebCore {
class AXIsolatedObject;
@@ -43,7 +47,7 @@
class AXIsolatedTree : public ThreadSafeRefCounted<AXIsolatedTree> {
WTF_MAKE_NONCOPYABLE(AXIsolatedTree); WTF_MAKE_FAST_ALLOCATED;
-
+ friend WTF::TextStream& operator<<(WTF::TextStream&, AXIsolatedTree&);
public:
static Ref<AXIsolatedTree> create();
virtual ~AXIsolatedTree();
@@ -57,7 +61,7 @@
void setAXObjectCache(AXObjectCache* axObjectCache) { m_axObjectCache = axObjectCache; }
RefPtr<AXIsolatedObject> rootNode();
- RefPtr<AXIsolatedObject> focusedUIElement();
+ RefPtr<AXIsolatedObject> focusedNode();
RefPtr<AXIsolatedObject> nodeForID(AXID) const;
static RefPtr<AXIsolatedObject> nodeInTreeForID(AXIsolatedTreeID, AXID);
Vector<RefPtr<AXCoreObject>> objectsForIDs(Vector<AXID>) const;
@@ -79,19 +83,17 @@
// Removes the given node and all its descendants.
void removeSubtree(AXID);
- // Both setRootNode and setFocusedNode must be called only during the
- // generation of the IsolatedTree.
- // The focused node needs to be set during the generation because a request
- // for it can come in before pending changes are applied. For focused node
- // updates, use setFocusNodeID.
- void setRootNode(Ref<AXIsolatedObject>&);
- void setFocusedNode(AXID);
+ // Both setRootNodeID and setFocusedNodeID are called during the generation
+ // of the IsolatedTree.
+ // Focused node updates in AXObjectCache use setFocusNodeID.
+ void setRootNodeID(AXID);
void setFocusedNodeID(AXID);
- // Call on AX thread
+ // Called on AX thread from WebAccessibilityObjectWrapper methods.
+ // During layout tests, it is called on the main thread.
void applyPendingChanges();
- AXIsolatedTreeID treeIdentifier() const { return m_treeID; }
+ AXIsolatedTreeID treeID() const { return m_treeID; }
private:
AXIsolatedTree();