From 3eef54823ab4f718009ecedf212431e59c0426ab Mon Sep 17 00:00:00 2001 From: Jonah Date: Sun, 11 Dec 2022 12:38:27 -0600 Subject: [PATCH] LibWeb: Add Function To Build Accessiblity Tree With this patch, the accessibility tree can be build from the root node of a document. This can then be serialzed and sent to (soon to come) consumers. --- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../LibWeb/DOM/AccessibilityTreeNode.cpp | 76 +++++++++++++++++++ .../LibWeb/DOM/AccessibilityTreeNode.h | 40 ++++++++++ Userland/Libraries/LibWeb/Forward.h | 1 + 4 files changed, 118 insertions(+) create mode 100644 Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp create mode 100644 Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 0d0f987e5e..7dbbdac4f1 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -72,6 +72,7 @@ set(SOURCES DOM/AbortController.cpp DOM/AbortSignal.cpp DOM/AbstractRange.cpp + DOM/AccessibilityTreeNode.cpp DOM/Attr.cpp DOM/Attr.idl DOM/ARIAMixin.cpp diff --git a/Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp b/Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp new file mode 100644 index 0000000000..c2a4674ebc --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, Jonah Shafran + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Web::DOM { + +JS::NonnullGCPtr AccessibilityTreeNode::create(Document* document, DOM::Node const* value) +{ + return *document->heap().allocate(document->realm(), value); +} + +AccessibilityTreeNode::AccessibilityTreeNode(JS::GCPtr value) + : m_value(value) +{ + m_children = {}; +} + +void AccessibilityTreeNode::serialize_tree_as_json(JsonObjectSerializer& object) const +{ + if (value()->is_document()) { + VERIFY_NOT_REACHED(); + } else if (value()->is_element()) { + auto const* element = static_cast(value().ptr()); + + if (element->include_in_accessibility_tree()) { + MUST(object.add("type"sv, "element"sv)); + + auto role = element->role_or_default(); + bool has_role = !role.is_null() && !role.is_empty() && !ARIARoleNames::is_abstract_aria_role(role); + + if (has_role) + MUST(object.add("role"sv, role.view())); + else + MUST(object.add("role"sv, ""sv)); + } else { + VERIFY_NOT_REACHED(); + } + + } else if (value()->is_text()) { + MUST(object.add("type"sv, "text"sv)); + + auto const* text_node = static_cast(value().ptr()); + MUST(object.add("text"sv, text_node->data())); + } + + if (value()->has_child_nodes()) { + auto node_children = MUST(object.add_array("children"sv)); + for (auto child : children()) { + if (child->value()->is_uninteresting_whitespace_node()) + continue; + JsonObjectSerializer child_object = MUST(node_children.add_object()); + child->serialize_tree_as_json(child_object); + MUST(child_object.finish()); + } + MUST(node_children.finish()); + } +} + +void AccessibilityTreeNode::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(*value()); + for (auto child : children()) + child->visit_edges(visitor); +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.h b/Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.h new file mode 100644 index 0000000000..4710ef04f0 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/AccessibilityTreeNode.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, Jonah Shafran + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Web::DOM { + +class AccessibilityTreeNode final : public JS::Cell { + JS_CELL(AccessibilityTreeNode, JS::Cell) +public: + static JS::NonnullGCPtr create(Document*, DOM::Node const*); + virtual ~AccessibilityTreeNode() override = default; + + JS::GCPtr value() const { return m_value; } + void set_value(JS::GCPtr value) { m_value = value; } + Vector children() const { return m_children; } + void append_child(AccessibilityTreeNode* child) { m_children.append(child); } + + void serialize_tree_as_json(JsonObjectSerializer& object) const; + +protected: + virtual void visit_edges(Visitor&) override; + +private: + explicit AccessibilityTreeNode(JS::GCPtr); + + JS::GCPtr m_value; + Vector m_children; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 7be9b1f836..0e69beb304 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -136,6 +136,7 @@ namespace Web::DOM { class AbstractRange; class AbortController; class AbortSignal; +class AccessibilityTreeNode; class Attr; class CDATASection; class CharacterData;