Update Linux embedder to latest semantics API (flutter/engine#51030)

Change to the latest semantics API and remove an unused class.
This commit is contained in:
Robert Ancell 2024-02-29 15:18:19 +13:00 committed by GitHub
parent 65f3a2348b
commit da5550db7f
10 changed files with 122 additions and 254 deletions

View File

@ -36876,8 +36876,6 @@ ORIGIN: ../../../flutter/shell/platform/glfw/system_utils.h + ../../../flutter/L
ORIGIN: ../../../flutter/shell/platform/glfw/system_utils_test.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/glfw/text_input_plugin.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/glfw/text_input_plugin.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessibility_plugin.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessibility_plugin.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_node.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_node.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/linux/fl_accessible_node_test.cc + ../../../flutter/LICENSE
@ -39751,8 +39749,6 @@ FILE: ../../../flutter/shell/platform/glfw/system_utils.h
FILE: ../../../flutter/shell/platform/glfw/system_utils_test.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
FILE: ../../../flutter/shell/platform/linux/fl_accessibility_plugin.cc
FILE: ../../../flutter/shell/platform/linux/fl_accessibility_plugin.h
FILE: ../../../flutter/shell/platform/linux/fl_accessible_node.cc
FILE: ../../../flutter/shell/platform/linux/fl_accessible_node.h
FILE: ../../../flutter/shell/platform/linux/fl_accessible_node_test.cc

View File

@ -96,7 +96,6 @@ source_set("flutter_linux_sources") {
configs += [ "//flutter/shell/platform/linux/config:gtk" ]
sources = [
"fl_accessibility_plugin.cc",
"fl_accessible_node.cc",
"fl_accessible_text_field.cc",
"fl_backing_store_provider.cc",

View File

@ -1,56 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/linux/fl_accessibility_plugin.h"
#include "flutter/shell/platform/linux/fl_view_accessible.h"
struct _FlAccessibilityPlugin {
GObject parent_instance;
FlView* view;
};
G_DEFINE_TYPE(FlAccessibilityPlugin, fl_accessibility_plugin, G_TYPE_OBJECT)
static void fl_accessibility_plugin_dispose(GObject* object) {
FlAccessibilityPlugin* self = FL_ACCESSIBILITY_PLUGIN(object);
if (self->view != nullptr) {
g_object_remove_weak_pointer(G_OBJECT(self),
reinterpret_cast<gpointer*>(&(self->view)));
self->view = nullptr;
}
G_OBJECT_CLASS(fl_accessibility_plugin_parent_class)->dispose(object);
}
static void fl_accessibility_plugin_class_init(
FlAccessibilityPluginClass* klass) {
G_OBJECT_CLASS(klass)->dispose = fl_accessibility_plugin_dispose;
}
static void fl_accessibility_plugin_init(FlAccessibilityPlugin* self) {}
FlAccessibilityPlugin* fl_accessibility_plugin_new(FlView* view) {
FlAccessibilityPlugin* self = FL_ACCESSIBILITY_PLUGIN(
g_object_new(fl_accessibility_plugin_get_type(), nullptr));
self->view = view;
g_object_add_weak_pointer(G_OBJECT(self),
reinterpret_cast<gpointer*>(&(self->view)));
return self;
}
void fl_accessibility_plugin_handle_update_semantics_node(
FlAccessibilityPlugin* self,
const FlutterSemanticsNode* node) {
if (self->view == nullptr) {
return;
}
AtkObject* accessible = gtk_widget_get_accessible(GTK_WIDGET(self->view));
fl_view_accessible_handle_update_semantics_node(
FL_VIEW_ACCESSIBLE(accessible), node);
}

View File

@ -1,50 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_ACCESSIBILITY_PLUGIN_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_ACCESSIBILITY_PLUGIN_H_
#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h"
#include "flutter/shell/platform/embedder/embedder.h"
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(FlAccessibilityPlugin,
fl_accessibility_plugin,
FL,
ACCESSIBILITY_PLUGIN,
GObject);
/**
* FlAccessibilityPlugin:
*
* #FlAccessibilityPlugin is a plugin that handles semantic node updates and
* converts them to ATK events.
*/
/**
* fl_accessibility_plugin_new:
* @view: an #FlView to export accessibility information to.
*
* Creates a new plugin handles semantic node updates.
*
* Returns: a new #FlAccessibilityPlugin.
*/
FlAccessibilityPlugin* fl_accessibility_plugin_new(FlView* view);
/**
* fl_accessibility_plugin_handle_update_semantics_node:
* @plugin: an #FlAccessibilityPlugin.
* @node: semantic node information.
*
* Handle a semantics node update.
*/
void fl_accessibility_plugin_handle_update_semantics_node(
FlAccessibilityPlugin* plugin,
const FlutterSemanticsNode* node);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_ACCESSIBILITY_PLUGIN_H_

View File

@ -59,9 +59,9 @@ struct _FlEngine {
GDestroyNotify platform_message_handler_destroy_notify;
// Function to call when a semantic node is received.
FlEngineUpdateSemanticsNodeHandler update_semantics_node_handler;
gpointer update_semantics_node_handler_data;
GDestroyNotify update_semantics_node_handler_destroy_notify;
FlEngineUpdateSemanticsHandler update_semantics_handler;
gpointer update_semantics_handler_data;
GDestroyNotify update_semantics_handler_destroy_notify;
// Function to call right before the engine is restarted.
FlEngineOnPreEngineRestartHandler on_pre_engine_restart_handler;
@ -333,13 +333,13 @@ static void fl_engine_platform_message_cb(const FlutterPlatformMessage* message,
}
// Called when a semantic node update is received from the engine.
static void fl_engine_update_semantics_node_cb(const FlutterSemanticsNode* node,
void* user_data) {
static void fl_engine_update_semantics_cb(const FlutterSemanticsUpdate2* update,
void* user_data) {
FlEngine* self = FL_ENGINE(user_data);
if (self->update_semantics_node_handler != nullptr) {
self->update_semantics_node_handler(
self, node, self->update_semantics_node_handler_data);
if (self->update_semantics_handler != nullptr) {
self->update_semantics_handler(self, update,
self->update_semantics_handler_data);
}
}
@ -425,12 +425,12 @@ static void fl_engine_dispose(GObject* object) {
self->platform_message_handler_data = nullptr;
self->platform_message_handler_destroy_notify = nullptr;
if (self->update_semantics_node_handler_destroy_notify) {
self->update_semantics_node_handler_destroy_notify(
self->update_semantics_node_handler_data);
if (self->update_semantics_handler_destroy_notify) {
self->update_semantics_handler_destroy_notify(
self->update_semantics_handler_data);
}
self->update_semantics_node_handler_data = nullptr;
self->update_semantics_node_handler_destroy_notify = nullptr;
self->update_semantics_handler_data = nullptr;
self->update_semantics_handler_destroy_notify = nullptr;
if (self->on_pre_engine_restart_handler_destroy_notify) {
self->on_pre_engine_restart_handler_destroy_notify(
@ -527,7 +527,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
args.command_line_argv =
reinterpret_cast<const char* const*>(command_line_args->pdata);
args.platform_message_callback = fl_engine_platform_message_cb;
args.update_semantics_node_callback = fl_engine_update_semantics_node_cb;
args.update_semantics_callback2 = fl_engine_update_semantics_cb;
args.custom_task_runners = &custom_task_runners;
args.shutdown_dart_vm_when_done = true;
args.on_pre_engine_restart_callback = fl_engine_on_pre_engine_restart_cb;
@ -610,21 +610,21 @@ void fl_engine_set_platform_message_handler(
self->platform_message_handler_destroy_notify = destroy_notify;
}
void fl_engine_set_update_semantics_node_handler(
void fl_engine_set_update_semantics_handler(
FlEngine* self,
FlEngineUpdateSemanticsNodeHandler handler,
FlEngineUpdateSemanticsHandler handler,
gpointer user_data,
GDestroyNotify destroy_notify) {
g_return_if_fail(FL_IS_ENGINE(self));
if (self->update_semantics_node_handler_destroy_notify) {
self->update_semantics_node_handler_destroy_notify(
self->update_semantics_node_handler_data);
if (self->update_semantics_handler_destroy_notify) {
self->update_semantics_handler_destroy_notify(
self->update_semantics_handler_data);
}
self->update_semantics_node_handler = handler;
self->update_semantics_node_handler_data = user_data;
self->update_semantics_node_handler_destroy_notify = destroy_notify;
self->update_semantics_handler = handler;
self->update_semantics_handler_data = user_data;
self->update_semantics_handler_destroy_notify = destroy_notify;
}
void fl_engine_set_on_pre_engine_restart_handler(

View File

@ -48,16 +48,16 @@ typedef gboolean (*FlEnginePlatformMessageHandler)(
gpointer user_data);
/**
* FlEngineUpdateSemanticsNodeHandler:
* FlEngineUpdateSemanticsHandler:
* @engine: an #FlEngine.
* @node: semantic node information.
* @user_data: (closure): data provided when registering this handler.
*
* Function called when semantics node updates are received.
*/
typedef void (*FlEngineUpdateSemanticsNodeHandler)(
typedef void (*FlEngineUpdateSemanticsHandler)(
FlEngine* engine,
const FlutterSemanticsNode* node,
const FlutterSemanticsUpdate2* update,
gpointer user_data);
/**
@ -112,18 +112,18 @@ void fl_engine_set_platform_message_handler(
GDestroyNotify destroy_notify);
/**
* fl_engine_set_update_semantics_node_handler:
* fl_engine_set_update_semantics_handler:
* @engine: an #FlEngine.
* @handler: function to call when a semantics node update is received.
* @handler: function to call when a semantics update is received.
* @user_data: (closure): user data to pass to @handler.
* @destroy_notify: (allow-none): a function which gets called to free
* @user_data, or %NULL.
*
* Registers the function called when a semantics node update is reveived.
* Registers the function called when a semantics update is received.
*/
void fl_engine_set_update_semantics_node_handler(
void fl_engine_set_update_semantics_handler(
FlEngine* engine,
FlEngineUpdateSemanticsNodeHandler handler,
FlEngineUpdateSemanticsHandler handler,
gpointer user_data,
GDestroyNotify destroy_notify);

View File

@ -8,7 +8,6 @@
#include <cstring>
#include "flutter/shell/platform/linux/fl_accessibility_plugin.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
#include "flutter/shell/platform/linux/fl_key_event.h"
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
@ -46,7 +45,6 @@ struct _FlView {
GdkWindowState window_state;
// Flutter system channel handlers.
FlAccessibilityPlugin* accessibility_plugin;
FlKeyboardManager* keyboard_manager;
FlScrollingManager* scrolling_manager;
FlTextInputPlugin* text_input_plugin;
@ -225,14 +223,15 @@ static void handle_geometry_changed(FlView* self) {
}
}
// Called when the engine updates accessibility nodes.
static void update_semantics_node_cb(FlEngine* engine,
const FlutterSemanticsNode* node,
gpointer user_data) {
// Called when the engine updates accessibility.
static void update_semantics_cb(FlEngine* engine,
const FlutterSemanticsUpdate2* update,
gpointer user_data) {
FlView* self = FL_VIEW(user_data);
fl_accessibility_plugin_handle_update_semantics_node(
self->accessibility_plugin, node);
AtkObject* accessible = gtk_widget_get_accessible(GTK_WIDGET(self));
fl_view_accessible_handle_update_semantics(FL_VIEW_ACCESSIBLE(accessible),
update);
}
// Invoked by the engine right before the engine is restarted.
@ -559,8 +558,8 @@ static void fl_view_constructed(GObject* object) {
self->renderer = FL_RENDERER(fl_renderer_gl_new());
self->engine = fl_engine_new(self->project, self->renderer);
fl_engine_set_update_semantics_node_handler(
self->engine, update_semantics_node_cb, self, nullptr);
fl_engine_set_update_semantics_handler(self->engine, update_semantics_cb,
self, nullptr);
fl_engine_set_on_pre_engine_restart_handler(
self->engine, on_pre_engine_restart_cb, self, nullptr);
@ -569,7 +568,6 @@ static void fl_view_constructed(GObject* object) {
// Create system channel handlers.
FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine);
self->accessibility_plugin = fl_accessibility_plugin_new(self);
init_scrolling(self);
self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self);
self->platform_plugin = fl_platform_plugin_new(messenger);
@ -666,8 +664,8 @@ static void fl_view_dispose(GObject* object) {
FlView* self = FL_VIEW(object);
if (self->engine != nullptr) {
fl_engine_set_update_semantics_node_handler(self->engine, nullptr, nullptr,
nullptr);
fl_engine_set_update_semantics_handler(self->engine, nullptr, nullptr,
nullptr);
fl_engine_set_on_pre_engine_restart_handler(self->engine, nullptr, nullptr,
nullptr);
}
@ -681,7 +679,6 @@ static void fl_view_dispose(GObject* object) {
g_clear_object(&self->project);
g_clear_object(&self->renderer);
g_clear_object(&self->engine);
g_clear_object(&self->accessibility_plugin);
g_clear_object(&self->keyboard_manager);
if (self->keymap_keys_changed_cb_id != 0) {
g_signal_handler_disconnect(self->keymap, self->keymap_keys_changed_cb_id);

View File

@ -15,9 +15,6 @@ struct _FlViewAccessible {
// Semantics nodes keyed by ID
GHashTable* semantics_nodes_by_id;
// Child IDs stored until commit_updates is called
GHashTable* pending_children;
};
enum { kProp0, kPropEngine, kPropLast };
@ -42,7 +39,7 @@ static FlEngine* get_engine(FlViewAccessible* self) {
}
static FlAccessibleNode* create_node(FlViewAccessible* self,
const FlutterSemanticsNode* semantics) {
FlutterSemanticsNode2* semantics) {
FlEngine* engine = get_engine(self);
if (semantics->flags & kFlutterSemanticsFlagIsTextField) {
@ -60,7 +57,7 @@ static FlAccessibleNode* lookup_node(FlViewAccessible* self, int32_t id) {
// Gets the ATK node for the given id.
// If the node doesn't exist it will be created.
static FlAccessibleNode* get_node(FlViewAccessible* self,
const FlutterSemanticsNode* semantics) {
FlutterSemanticsNode2* semantics) {
FlAccessibleNode* node = lookup_node(self, semantics->id);
if (node != nullptr) {
return node;
@ -78,33 +75,6 @@ static FlAccessibleNode* get_node(FlViewAccessible* self,
return node;
}
static void commit_updates(FlViewAccessible* self) {
g_hash_table_foreach_remove(
self->pending_children,
[](gpointer key, gpointer value, gpointer user_data) -> gboolean {
FlViewAccessible* self = FL_VIEW_ACCESSIBLE(user_data);
FlAccessibleNode* parent = FL_ACCESSIBLE_NODE(key);
size_t child_count = fl_value_get_length(static_cast<FlValue*>(value));
const int32_t* children_in_traversal_order =
fl_value_get_int32_list(static_cast<FlValue*>(value));
g_autoptr(GPtrArray) children = g_ptr_array_new();
for (size_t i = 0; i < child_count; i++) {
FlAccessibleNode* child =
lookup_node(self, children_in_traversal_order[i]);
g_assert(child != nullptr);
fl_accessible_node_set_parent(child, ATK_OBJECT(parent), i);
g_ptr_array_add(children, child);
}
fl_accessible_node_set_children(parent, children);
return true;
},
self);
}
// Implements AtkObject::get_n_children
static gint fl_view_accessible_get_n_children(AtkObject* accessible) {
FlViewAccessible* self = FL_VIEW_ACCESSIBLE(accessible);
@ -154,7 +124,6 @@ static void fl_view_accessible_dispose(GObject* object) {
FlViewAccessible* self = FL_VIEW_ACCESSIBLE(object);
g_clear_pointer(&self->semantics_nodes_by_id, g_hash_table_unref);
g_clear_pointer(&self->pending_children, g_hash_table_unref);
if (self->engine != nullptr) {
g_object_remove_weak_pointer(object,
@ -184,34 +153,58 @@ static void fl_view_accessible_class_init(FlViewAccessibleClass* klass) {
static void fl_view_accessible_init(FlViewAccessible* self) {
self->semantics_nodes_by_id = g_hash_table_new_full(
g_direct_hash, g_direct_equal, nullptr, g_object_unref);
self->pending_children =
}
void fl_view_accessible_handle_update_semantics(
FlViewAccessible* self,
const FlutterSemanticsUpdate2* update) {
g_autoptr(GHashTable) pending_children =
g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr,
reinterpret_cast<GDestroyNotify>(fl_value_unref));
}
void fl_view_accessible_handle_update_semantics_node(
FlViewAccessible* self,
const FlutterSemanticsNode* node) {
if (node->id == kFlutterSemanticsNodeIdBatchEnd) {
commit_updates(self);
return;
for (size_t i = 0; i < update->node_count; i++) {
FlutterSemanticsNode2* node = update->nodes[i];
FlAccessibleNode* atk_node = get_node(self, node);
fl_accessible_node_set_flags(atk_node, node->flags);
fl_accessible_node_set_actions(atk_node, node->actions);
fl_accessible_node_set_name(atk_node, node->label);
fl_accessible_node_set_extents(
atk_node, node->rect.left + node->transform.transX,
node->rect.top + node->transform.transY,
node->rect.right - node->rect.left, node->rect.bottom - node->rect.top);
fl_accessible_node_set_value(atk_node, node->value);
fl_accessible_node_set_text_selection(atk_node, node->text_selection_base,
node->text_selection_extent);
fl_accessible_node_set_text_direction(atk_node, node->text_direction);
FlValue* children = fl_value_new_int32_list(
node->children_in_traversal_order, node->child_count);
g_hash_table_insert(pending_children, atk_node, children);
}
FlAccessibleNode* atk_node = get_node(self, node);
g_hash_table_foreach_remove(
pending_children,
[](gpointer key, gpointer value, gpointer user_data) -> gboolean {
FlViewAccessible* self = FL_VIEW_ACCESSIBLE(user_data);
fl_accessible_node_set_flags(atk_node, node->flags);
fl_accessible_node_set_actions(atk_node, node->actions);
fl_accessible_node_set_name(atk_node, node->label);
fl_accessible_node_set_extents(
atk_node, node->rect.left + node->transform.transX,
node->rect.top + node->transform.transY,
node->rect.right - node->rect.left, node->rect.bottom - node->rect.top);
fl_accessible_node_set_value(atk_node, node->value);
fl_accessible_node_set_text_selection(atk_node, node->text_selection_base,
node->text_selection_extent);
fl_accessible_node_set_text_direction(atk_node, node->text_direction);
FlAccessibleNode* parent = FL_ACCESSIBLE_NODE(key);
FlValue* children = fl_value_new_int32_list(node->children_in_traversal_order,
node->child_count);
g_hash_table_insert(self->pending_children, atk_node, children);
size_t child_count = fl_value_get_length(static_cast<FlValue*>(value));
const int32_t* children_in_traversal_order =
fl_value_get_int32_list(static_cast<FlValue*>(value));
g_autoptr(GPtrArray) children = g_ptr_array_new();
for (size_t i = 0; i < child_count; i++) {
FlAccessibleNode* child =
lookup_node(self, children_in_traversal_order[i]);
g_assert(child != nullptr);
fl_accessible_node_set_parent(child, ATK_OBJECT(parent), i);
g_ptr_array_add(children, child);
}
fl_accessible_node_set_children(parent, children);
return true;
},
self);
}

View File

@ -29,15 +29,15 @@ G_DECLARE_FINAL_TYPE(FlViewAccessible,
*/
/**
* fl_view_accessible_handle_update_semantics_node:
* fl_view_accessible_handle_update_semantics:
* @accessible: an #FlViewAccessible.
* @node: semantic node information.
* @update: semantic update information.
*
* Handle a semantics node update from Flutter.
* Handle a semantics update from Flutter.
*/
void fl_view_accessible_handle_update_semantics_node(
void fl_view_accessible_handle_update_semantics(
FlViewAccessible* accessible,
const FlutterSemanticsNode* node);
const FlutterSemanticsUpdate2* update);
G_END_DECLS

View File

@ -10,30 +10,23 @@
#include "flutter/shell/platform/linux/testing/fl_test.h"
#include "flutter/shell/platform/linux/testing/mock_signal_handler.h"
static const FlutterSemanticsNode kBatchEndNode = {
.id = kFlutterSemanticsNodeIdBatchEnd};
TEST(FlViewAccessibleTest, BuildTree) {
g_autoptr(FlEngine) engine = make_mock_engine();
g_autoptr(FlViewAccessible) accessible = FL_VIEW_ACCESSIBLE(
g_object_new(fl_view_accessible_get_type(), "engine", engine, nullptr));
const int32_t children[] = {111, 222};
const FlutterSemanticsNode root_node = {
int32_t children[] = {111, 222};
FlutterSemanticsNode2 root_node = {
.id = 0,
.label = "root",
.child_count = 2,
.children_in_traversal_order = children,
};
fl_view_accessible_handle_update_semantics_node(accessible, &root_node);
const FlutterSemanticsNode child1_node = {.id = 111, .label = "child 1"};
fl_view_accessible_handle_update_semantics_node(accessible, &child1_node);
const FlutterSemanticsNode child2_node = {.id = 222, .label = "child 2"};
fl_view_accessible_handle_update_semantics_node(accessible, &child2_node);
fl_view_accessible_handle_update_semantics_node(accessible, &kBatchEndNode);
FlutterSemanticsNode2 child1_node = {.id = 111, .label = "child 1"};
FlutterSemanticsNode2 child2_node = {.id = 222, .label = "child 2"};
FlutterSemanticsNode2* nodes[3] = {&root_node, &child1_node, &child2_node};
FlutterSemanticsUpdate2 update = {.node_count = 3, .nodes = nodes};
fl_view_accessible_handle_update_semantics(accessible, &update);
AtkObject* root_object =
atk_object_ref_accessible_child(ATK_OBJECT(accessible), 0);
@ -59,14 +52,14 @@ TEST(FlViewAccessibleTest, AddRemoveChildren) {
g_autoptr(FlViewAccessible) accessible = FL_VIEW_ACCESSIBLE(
g_object_new(fl_view_accessible_get_type(), "engine", engine, nullptr));
FlutterSemanticsNode root_node = {
FlutterSemanticsNode2 root_node = {
.id = 0,
.label = "root",
.child_count = 0,
};
fl_view_accessible_handle_update_semantics_node(accessible, &root_node);
fl_view_accessible_handle_update_semantics_node(accessible, &kBatchEndNode);
FlutterSemanticsNode2* nodes[1] = {&root_node};
FlutterSemanticsUpdate2 update = {.node_count = 1, .nodes = nodes};
fl_view_accessible_handle_update_semantics(accessible, &update);
AtkObject* root_object =
atk_object_ref_accessible_child(ATK_OBJECT(accessible), 0);
@ -74,21 +67,19 @@ TEST(FlViewAccessibleTest, AddRemoveChildren) {
// add child1
AtkObject* child1_object = nullptr;
FlutterSemanticsNode2 child1_node = {.id = 111, .label = "child 1"};
{
flutter::testing::MockSignalHandler2<gint, AtkObject*> child1_added(
root_object, "children-changed::add");
EXPECT_SIGNAL2(child1_added, ::testing::Eq(0), ::testing::A<AtkObject*>())
.WillOnce(::testing::SaveArg<1>(&child1_object));
const int32_t children[] = {111};
int32_t children[] = {111};
root_node.child_count = 1;
root_node.children_in_traversal_order = children;
fl_view_accessible_handle_update_semantics_node(accessible, &root_node);
const FlutterSemanticsNode child1_node = {.id = 111, .label = "child 1"};
fl_view_accessible_handle_update_semantics_node(accessible, &child1_node);
fl_view_accessible_handle_update_semantics_node(accessible, &kBatchEndNode);
FlutterSemanticsNode2* nodes[2] = {&root_node, &child1_node};
FlutterSemanticsUpdate2 update = {.node_count = 2, .nodes = nodes};
fl_view_accessible_handle_update_semantics(accessible, &update);
}
EXPECT_EQ(atk_object_get_n_accessible_children(root_object), 1);
@ -101,21 +92,19 @@ TEST(FlViewAccessibleTest, AddRemoveChildren) {
// add child2
AtkObject* child2_object = nullptr;
FlutterSemanticsNode2 child2_node = {.id = 222, .label = "child 2"};
{
flutter::testing::MockSignalHandler2<gint, AtkObject*> child2_added(
root_object, "children-changed::add");
EXPECT_SIGNAL2(child2_added, ::testing::Eq(1), ::testing::A<AtkObject*>())
.WillOnce(::testing::SaveArg<1>(&child2_object));
const int32_t children[] = {111, 222};
int32_t children[] = {111, 222};
root_node.child_count = 2;
root_node.children_in_traversal_order = children;
fl_view_accessible_handle_update_semantics_node(accessible, &root_node);
const FlutterSemanticsNode child2_node = {.id = 222, .label = "child 2"};
fl_view_accessible_handle_update_semantics_node(accessible, &child2_node);
fl_view_accessible_handle_update_semantics_node(accessible, &kBatchEndNode);
FlutterSemanticsNode2* nodes[3] = {&root_node, &child1_node, &child2_node};
FlutterSemanticsUpdate2 update = {.node_count = 3, .nodes = nodes};
fl_view_accessible_handle_update_semantics(accessible, &update);
}
EXPECT_EQ(atk_object_get_n_accessible_children(root_object), 2);
@ -142,9 +131,9 @@ TEST(FlViewAccessibleTest, AddRemoveChildren) {
const int32_t children[] = {222};
root_node.child_count = 1;
root_node.children_in_traversal_order = children;
fl_view_accessible_handle_update_semantics_node(accessible, &root_node);
fl_view_accessible_handle_update_semantics_node(accessible, &kBatchEndNode);
FlutterSemanticsNode2* nodes[3] = {&root_node, &child2_node};
FlutterSemanticsUpdate2 update = {.node_count = 2, .nodes = nodes};
fl_view_accessible_handle_update_semantics(accessible, &update);
}
EXPECT_EQ(atk_object_get_n_accessible_children(root_object), 1);
@ -163,9 +152,9 @@ TEST(FlViewAccessibleTest, AddRemoveChildren) {
::testing::Eq(child2_object));
root_node.child_count = 0;
fl_view_accessible_handle_update_semantics_node(accessible, &root_node);
fl_view_accessible_handle_update_semantics_node(accessible, &kBatchEndNode);
FlutterSemanticsNode2* nodes[1] = {&root_node};
FlutterSemanticsUpdate2 update = {.node_count = 1, .nodes = nodes};
fl_view_accessible_handle_update_semantics(accessible, &update);
}
EXPECT_EQ(atk_object_get_n_accessible_children(root_object), 0);