Serenity Operating System
at master 121 lines 3.9 kB view raw
1/* 2 * Copyright (c) 2022, Jonah Shafran <jonahshafran@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibWebView/AccessibilityTreeModel.h> 8 9namespace WebView { 10 11AccessibilityTreeModel::AccessibilityTreeModel(JsonObject accessibility_tree, GUI::TreeView* tree_view) 12 : m_tree_view(tree_view) 13 , m_accessibility_tree(move(accessibility_tree)) 14{ 15 map_accessibility_nodes_to_parent(nullptr, &m_accessibility_tree); 16} 17 18AccessibilityTreeModel::~AccessibilityTreeModel() = default; 19 20GUI::ModelIndex AccessibilityTreeModel::index(int row, int column, GUI::ModelIndex const& parent) const 21{ 22 if (!parent.is_valid()) { 23 return create_index(row, column, &m_accessibility_tree); 24 } 25 26 auto const& parent_node = *static_cast<JsonObject const*>(parent.internal_data()); 27 auto children = get_children(parent_node); 28 if (!children.has_value()) 29 return create_index(row, column, &m_accessibility_tree); 30 31 auto const& child_node = children->at(row).as_object(); 32 return create_index(row, column, &child_node); 33} 34 35GUI::ModelIndex AccessibilityTreeModel::parent_index(GUI::ModelIndex const& index) const 36{ 37 if (!index.is_valid()) 38 return {}; 39 40 auto const& node = *static_cast<JsonObject const*>(index.internal_data()); 41 42 auto const* parent_node = get_parent(node); 43 if (!parent_node) 44 return {}; 45 46 // If the parent is the root document, we know it has index 0, 0 47 if (parent_node == &m_accessibility_tree) { 48 return create_index(0, 0, parent_node); 49 } 50 51 // Otherwise, we need to find the grandparent, to find the index of parent within that 52 auto const* grandparent_node = get_parent(*parent_node); 53 VERIFY(grandparent_node); 54 55 auto grandparent_children = get_children(*grandparent_node); 56 if (!grandparent_children.has_value()) 57 return {}; 58 59 for (size_t grandparent_child_index = 0; grandparent_child_index < grandparent_children->size(); ++grandparent_child_index) { 60 auto const& child = grandparent_children->at(grandparent_child_index).as_object(); 61 if (&child == parent_node) 62 return create_index(grandparent_child_index, 0, parent_node); 63 } 64 65 return {}; 66} 67 68int AccessibilityTreeModel::row_count(GUI::ModelIndex const& index) const 69{ 70 if (!index.is_valid()) 71 return 1; 72 73 auto const& node = *static_cast<JsonObject const*>(index.internal_data()); 74 auto children = get_children(node); 75 return children.has_value() ? children->size() : 0; 76} 77 78int AccessibilityTreeModel::column_count(const GUI::ModelIndex&) const 79{ 80 return 1; 81} 82 83GUI::Variant AccessibilityTreeModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const 84{ 85 auto const& node = *static_cast<JsonObject const*>(index.internal_data()); 86 auto type = node.get_deprecated_string("type"sv).value_or("unknown"sv); 87 88 if (role == GUI::ModelRole::Display) { 89 if (type == "text") 90 return node.get_deprecated_string("text"sv).value(); 91 92 auto node_role = node.get_deprecated_string("role"sv).value(); 93 if (type != "element") 94 return node_role; 95 96 auto name = node.get_deprecated_string("name"sv).value(); 97 auto description = node.get_deprecated_string("description"sv).value(); 98 99 StringBuilder builder; 100 builder.append(node_role.to_lowercase()); 101 builder.appendff(" name: \"{}\", description: \"{}\"", name, description); 102 return builder.to_deprecated_string(); 103 } 104 return {}; 105} 106 107void AccessibilityTreeModel::map_accessibility_nodes_to_parent(JsonObject const* parent, JsonObject const* node) 108{ 109 m_accessibility_node_to_parent_map.set(node, parent); 110 111 auto children = get_children(*node); 112 if (!children.has_value()) 113 return; 114 115 children->for_each([&](auto const& child) { 116 auto const& child_node = child.as_object(); 117 map_accessibility_nodes_to_parent(node, &child_node); 118 }); 119} 120 121}