Flutter Linux Embedder
fl_view_accessible.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
10 
11 static constexpr int32_t kRootSemanticsNodeId = 0;
12 
14  AtkPlug parent_instance;
15 
16  GWeakRef engine;
17 
18  FlutterViewId view_id;
19 
20  // Semantics nodes keyed by ID
21  GHashTable* semantics_nodes_by_id;
22 
23  // Flag to track when root node is created.
25 };
26 
27 G_DEFINE_TYPE(FlViewAccessible, fl_view_accessible, ATK_TYPE_PLUG)
28 
29 static FlAccessibleNode* create_node(FlViewAccessible* self,
30  FlutterSemanticsNode2* semantics) {
31  g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
32  if (engine == nullptr) {
33  return nullptr;
34  }
35 
36  if (semantics->flags2->is_text_field) {
37  return fl_accessible_text_field_new(engine, self->view_id, semantics->id);
38  }
39 
40  return fl_accessible_node_new(engine, self->view_id, semantics->id);
41 }
42 
43 static FlAccessibleNode* lookup_node(FlViewAccessible* self, int32_t id) {
44  return FL_ACCESSIBLE_NODE(
45  g_hash_table_lookup(self->semantics_nodes_by_id, GINT_TO_POINTER(id)));
46 }
47 
48 // Gets the ATK node for the given id.
49 // If the node doesn't exist it will be created.
50 static FlAccessibleNode* get_node(FlViewAccessible* self,
51  FlutterSemanticsNode2* semantics) {
52  FlAccessibleNode* node = lookup_node(self, semantics->id);
53  if (node != nullptr) {
54  return node;
55  }
56 
57  node = create_node(self, semantics);
58  if (semantics->id == kRootSemanticsNodeId) {
59  fl_accessible_node_set_parent(node, ATK_OBJECT(self), 0);
60  }
61  g_hash_table_insert(self->semantics_nodes_by_id,
62  GINT_TO_POINTER(semantics->id),
63  reinterpret_cast<gpointer>(node));
64 
65  // Update when root node is created.
66  if (!self->root_node_created && semantics->id == kRootSemanticsNodeId) {
67  g_signal_emit_by_name(self, "children-changed::add", 0, node, nullptr);
68  self->root_node_created = true;
69  }
70 
71  return node;
72 }
73 
74 // Implements AtkObject::get_n_children
75 static gint fl_view_accessible_get_n_children(AtkObject* accessible) {
76  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(accessible);
77  FlAccessibleNode* node = lookup_node(self, 0);
78 
79  if (node == nullptr) {
80  return 0;
81  }
82 
83  return 1;
84 }
85 
86 // Implements AtkObject::ref_child
87 static AtkObject* fl_view_accessible_ref_child(AtkObject* accessible, gint i) {
88  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(accessible);
89  FlAccessibleNode* node = lookup_node(self, 0);
90 
91  if (i != 0 || node == nullptr) {
92  return nullptr;
93  }
94 
95  return ATK_OBJECT(g_object_ref(node));
96 }
97 
98 // Implements AtkObject::get_role
99 static AtkRole fl_view_accessible_get_role(AtkObject* accessible) {
100  return ATK_ROLE_PANEL;
101 }
102 
103 // Implements AtkObject::ref_state_set
104 static AtkStateSet* fl_view_accessible_ref_state_set(AtkObject* accessible) {
105  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(accessible);
106  FlAccessibleNode* node = lookup_node(self, 0);
107  return node != nullptr ? atk_object_ref_state_set(ATK_OBJECT(node)) : nullptr;
108 }
109 
110 static void fl_view_accessible_dispose(GObject* object) {
111  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(object);
112 
113  g_clear_pointer(&self->semantics_nodes_by_id, g_hash_table_unref);
114 
115  g_weak_ref_clear(&self->engine);
116 
117  G_OBJECT_CLASS(fl_view_accessible_parent_class)->dispose(object);
118 }
119 
120 static void fl_view_accessible_class_init(FlViewAccessibleClass* klass) {
121  ATK_OBJECT_CLASS(klass)->get_n_children = fl_view_accessible_get_n_children;
122  ATK_OBJECT_CLASS(klass)->ref_child = fl_view_accessible_ref_child;
123  ATK_OBJECT_CLASS(klass)->get_role = fl_view_accessible_get_role;
124  ATK_OBJECT_CLASS(klass)->ref_state_set = fl_view_accessible_ref_state_set;
125 
126  G_OBJECT_CLASS(klass)->dispose = fl_view_accessible_dispose;
127 }
128 
129 static void fl_view_accessible_init(FlViewAccessible* self) {
130  self->semantics_nodes_by_id = g_hash_table_new_full(
131  g_direct_hash, g_direct_equal, nullptr, g_object_unref);
132 }
133 
134 FlViewAccessible* fl_view_accessible_new(FlEngine* engine,
135  FlutterViewId view_id) {
136  FlViewAccessible* self =
137  FL_VIEW_ACCESSIBLE(g_object_new(fl_view_accessible_get_type(), nullptr));
138  g_weak_ref_init(&self->engine, engine);
139  self->view_id = view_id;
140  return self;
141 }
142 
144  FlViewAccessible* self,
145  const FlutterSemanticsUpdate2* update) {
146  g_return_if_fail(FL_IS_VIEW_ACCESSIBLE(self));
147 
148  g_autoptr(GHashTable) pending_children =
149  g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr,
150  reinterpret_cast<GDestroyNotify>(fl_value_unref));
151  for (size_t i = 0; i < update->node_count; i++) {
152  FlutterSemanticsNode2* node = update->nodes[i];
153  FlAccessibleNode* atk_node = get_node(self, node);
154 
155  fl_accessible_node_set_flags(atk_node, node->flags2);
156  fl_accessible_node_set_actions(atk_node, node->actions);
157  fl_accessible_node_set_name(atk_node, node->label);
159  atk_node, node->rect.left + node->transform.transX,
160  node->rect.top + node->transform.transY,
161  node->rect.right - node->rect.left, node->rect.bottom - node->rect.top);
162  fl_accessible_node_set_value(atk_node, node->value);
163  fl_accessible_node_set_text_selection(atk_node, node->text_selection_base,
164  node->text_selection_extent);
165  fl_accessible_node_set_text_direction(atk_node, node->text_direction);
166 
167  FlValue* children = fl_value_new_int32_list(
168  node->children_in_traversal_order, node->child_count);
169  g_hash_table_insert(pending_children, atk_node, children);
170  }
171 
172  g_hash_table_foreach_remove(
173  pending_children,
174  [](gpointer key, gpointer value, gpointer user_data) -> gboolean {
175  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(user_data);
176 
177  FlAccessibleNode* parent = FL_ACCESSIBLE_NODE(key);
178 
179  size_t child_count = fl_value_get_length(static_cast<FlValue*>(value));
180  const int32_t* children_in_traversal_order =
181  fl_value_get_int32_list(static_cast<FlValue*>(value));
182 
183  g_autoptr(GPtrArray) children = g_ptr_array_new();
184  for (size_t i = 0; i < child_count; i++) {
185  FlAccessibleNode* child =
186  lookup_node(self, children_in_traversal_order[i]);
187  g_assert(child != nullptr);
188  fl_accessible_node_set_parent(child, ATK_OBJECT(parent), i);
189  g_ptr_array_add(children, child);
190  }
191  fl_accessible_node_set_children(parent, children);
192 
193  return TRUE;
194  },
195  self);
196 }
void fl_accessible_node_set_name(FlAccessibleNode *self, const gchar *name)
void fl_accessible_node_set_text_direction(FlAccessibleNode *self, FlutterTextDirection direction)
void fl_accessible_node_set_text_selection(FlAccessibleNode *self, gint base, gint extent)
void fl_accessible_node_set_actions(FlAccessibleNode *self, FlutterSemanticsAction actions)
void fl_accessible_node_set_children(FlAccessibleNode *self, GPtrArray *children)
void fl_accessible_node_set_extents(FlAccessibleNode *self, gint x, gint y, gint width, gint height)
void fl_accessible_node_set_value(FlAccessibleNode *self, const gchar *value)
void fl_accessible_node_set_parent(FlAccessibleNode *self, AtkObject *parent, gint index)
void fl_accessible_node_set_flags(FlAccessibleNode *self, FlutterSemanticsFlags *flags)
FlAccessibleNode * fl_accessible_node_new(FlEngine *engine, FlutterViewId view_id, int32_t node_id)
FlAccessibleNode * fl_accessible_text_field_new(FlEngine *engine, FlutterViewId view_id, int32_t id)
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
uint8_t value
G_MODULE_EXPORT FlValue * fl_value_new_int32_list(const int32_t *data, size_t data_length)
Definition: fl_value.cc:309
G_MODULE_EXPORT void fl_value_unref(FlValue *self)
Definition: fl_value.cc:400
G_MODULE_EXPORT const int32_t * fl_value_get_int32_list(FlValue *self)
Definition: fl_value.cc:696
G_MODULE_EXPORT size_t fl_value_get_length(FlValue *self)
Definition: fl_value.cc:724
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
static void fl_view_accessible_dispose(GObject *object)
static FlAccessibleNode * create_node(FlViewAccessible *self, FlutterSemanticsNode2 *semantics)
static AtkObject * fl_view_accessible_ref_child(AtkObject *accessible, gint i)
FlViewAccessible * fl_view_accessible_new(FlEngine *engine, FlutterViewId view_id)
static void fl_view_accessible_init(FlViewAccessible *self)
static AtkRole fl_view_accessible_get_role(AtkObject *accessible)
static FlAccessibleNode * lookup_node(FlViewAccessible *self, int32_t id)
static FlAccessibleNode * get_node(FlViewAccessible *self, FlutterSemanticsNode2 *semantics)
static gint fl_view_accessible_get_n_children(AtkObject *accessible)
static void fl_view_accessible_class_init(FlViewAccessibleClass *klass)
static constexpr int32_t kRootSemanticsNodeId
void fl_view_accessible_handle_update_semantics(FlViewAccessible *self, const FlutterSemanticsUpdate2 *update)
static AtkStateSet * fl_view_accessible_ref_state_set(AtkObject *accessible)
G_BEGIN_DECLS FlutterViewId view_id
GHashTable * semantics_nodes_by_id