OverviewFilesCommitsIssuesDocsReleasesPeers

nvidia-rtx-godot / drivers / accesskit / accessibility_server_accesskit.cpp

1794 lines · cpp ref:
/**************************************************************************/
/*  accessibility_server_accesskit.cpp                                    */
/**************************************************************************/
/*                         This file is part of:                          */
/*                             GODOT ENGINE                               */
/*                        https://godotengine.org                         */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
/*                                                                        */
/* Permission is hereby granted, free of charge, to any person obtaining  */
/* a copy of this software and associated documentation files (the        */
/* "Software"), to deal in the Software without restriction, including    */
/* without limitation the rights to use, copy, modify, merge, publish,    */
/* distribute, sublicense, and/or sell copies of the Software, and to     */
/* permit persons to whom the Software is furnished to do so, subject to  */
/* the following conditions:                                              */
/*                                                                        */
/* The above copyright notice and this permission notice shall be         */
/* included in all copies or substantial portions of the Software.        */
/*                                                                        */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
/**************************************************************************/

#ifdef ACCESSKIT_ENABLED

#include "accessibility_server_accesskit.h"

#include "servers/text/text_server.h"

_FORCE_INLINE_ accesskit_role AccessibilityServerAccessKit::_accessibility_role(AccessibilityServerEnums::AccessibilityRole p_role) const {
	if (role_map.has(p_role)) {
		return role_map[p_role];
	}
	return ACCESSKIT_ROLE_UNKNOWN;
}

_FORCE_INLINE_ accesskit_action AccessibilityServerAccessKit::_accessibility_action(AccessibilityServerEnums::AccessibilityAction p_action) const {
	if (action_map.has(p_action)) {
		return action_map[p_action];
	}
	return ACCESSKIT_ACTION_CLICK;
}

bool AccessibilityServerAccessKit::window_create(DisplayServerEnums::WindowID p_window_id, void *p_handle) {
	ERR_FAIL_COND_V(windows.has(p_window_id), false);

	WindowData &wd = windows[p_window_id];

	AccessibilityElement *ae = memnew(AccessibilityElement);
	ae->role = ACCESSKIT_ROLE_WINDOW;
	ae->window_id = p_window_id;
	wd.root_id = rid_owner.make_rid(ae);

#ifdef WINDOWS_ENABLED
	wd.adapter = accesskit_windows_subclassing_adapter_new(static_cast<HWND>(p_handle), &_accessibility_initial_tree_update_callback, (void *)(size_t)p_window_id, &_accessibility_action_callback, (void *)(size_t)p_window_id);
#endif
#ifdef MACOS_ENABLED
	wd.adapter = accesskit_macos_subclassing_adapter_for_window(p_handle, &_accessibility_initial_tree_update_callback, (void *)(size_t)p_window_id, &_accessibility_action_callback, (void *)(size_t)p_window_id);
#endif
#ifdef LINUXBSD_ENABLED
	wd.adapter = accesskit_unix_adapter_new(&_accessibility_initial_tree_update_callback, (void *)(size_t)p_window_id, &_accessibility_action_callback, (void *)(size_t)p_window_id, &_accessibility_deactivation_callback, (void *)(size_t)p_window_id);
#endif
	print_verbose(vformat("Accessibility: window %d adapter created.", p_window_id));

	if (wd.adapter == nullptr) {
		memdelete(ae);
		rid_owner.free(wd.root_id);
		windows.erase(p_window_id);

		return false;
	} else {
		return true;
	}
}

void AccessibilityServerAccessKit::window_destroy(DisplayServerEnums::WindowID p_window_id) {
	WindowData *wd = windows.getptr(p_window_id);
	ERR_FAIL_NULL(wd);

	print_verbose(vformat("Accessibility: window %d adapter destroyed.", p_window_id));

#ifdef WINDOWS_ENABLED
	accesskit_windows_subclassing_adapter_free(wd->adapter);
#endif
#ifdef MACOS_ENABLED
	accesskit_macos_subclassing_adapter_free(wd->adapter);
#endif
#ifdef LINUXBSD_ENABLED
	accesskit_unix_adapter_free(wd->adapter);
#endif
	free_element(wd->root_id);

	windows.erase(p_window_id);
}

void AccessibilityServerAccessKit::_accessibility_deactivation_callback(void *p_user_data) {
	DisplayServerEnums::WindowID window_id = (DisplayServerEnums::WindowID)(size_t)p_user_data;
	WindowData *wd = static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.getptr(window_id);
	ERR_FAIL_NULL(wd);

	print_verbose(vformat("Accessibility: window %d adapter deactivated.", window_id));

	if (static_cast<AccessibilityServerAccessKit *>(get_singleton())->focus.is_valid()) {
		AccessibilityElement *ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(static_cast<AccessibilityServerAccessKit *>(get_singleton())->focus);
		if (ae && ae->window_id == window_id) {
			static_cast<AccessibilityServerAccessKit *>(get_singleton())->focus = RID();
		}
	}
	if (wd->deactivate.is_valid()) {
		wd->deactivate.call_deferred(); // Should be called on main thread only.
	}

	wd->activated = false;
	wd->update.clear();
}

void AccessibilityServerAccessKit::_accessibility_action_callback(struct accesskit_action_request *p_request, void *p_user_data) {
	DisplayServerEnums::WindowID window_id = (DisplayServerEnums::WindowID)(size_t)p_user_data;
	ERR_FAIL_COND(!static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.has(window_id));

	RID rid = RID::from_uint64(p_request->target_node);
	AccessibilityElement *ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(rid);
	ERR_FAIL_NULL(ae);

	Variant rq_data;
	if (!ae->actions.has(p_request->action) && ae->role == ACCESSKIT_ROLE_TEXT_RUN && p_request->action == ACCESSKIT_ACTION_SCROLL_INTO_VIEW) {
		AccessibilityElement *root_ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(ae->parent);
		ERR_FAIL_NULL(root_ae);
		ae = root_ae;
		rq_data = ae->run;
	}

	if (ae->actions.has(p_request->action)) {
		Callable &cb = ae->actions[p_request->action];
		if (cb.is_valid()) {
			if (p_request->data.has_value) {
				switch (p_request->data.value.tag) {
					case ACCESSKIT_ACTION_DATA_CUSTOM_ACTION: {
						rq_data = p_request->data.value.custom_action;
					} break;
					case ACCESSKIT_ACTION_DATA_VALUE: {
						rq_data = String::utf8(p_request->data.value.value);
					} break;
					case ACCESSKIT_ACTION_DATA_NUMERIC_VALUE: {
						rq_data = p_request->data.value.numeric_value;
					} break;
					case ACCESSKIT_ACTION_DATA_SCROLL_HINT: {
						switch (p_request->data.value.scroll_hint) {
							case ACCESSKIT_SCROLL_HINT_TOP_LEFT: {
								rq_data = AccessibilityServerEnums::SCROLL_HINT_TOP_LEFT;
							} break;
							case ACCESSKIT_SCROLL_HINT_BOTTOM_RIGHT: {
								rq_data = AccessibilityServerEnums::SCROLL_HINT_BOTTOM_RIGHT;
							} break;
							case ACCESSKIT_SCROLL_HINT_TOP_EDGE: {
								rq_data = AccessibilityServerEnums::SCROLL_HINT_TOP_EDGE;
							} break;
							case ACCESSKIT_SCROLL_HINT_BOTTOM_EDGE: {
								rq_data = AccessibilityServerEnums::SCROLL_HINT_BOTTOM_EDGE;
							} break;
							case ACCESSKIT_SCROLL_HINT_LEFT_EDGE: {
								rq_data = AccessibilityServerEnums::SCROLL_HINT_LEFT_EDGE;
							} break;
							case ACCESSKIT_SCROLL_HINT_RIGHT_EDGE: {
								rq_data = AccessibilityServerEnums::SCROLL_HINT_RIGHT_EDGE;
							} break;
							default:
								break;
						}
					} break;
					case ACCESSKIT_ACTION_DATA_SCROLL_UNIT: {
						if (p_request->data.value.scroll_unit == ACCESSKIT_SCROLL_UNIT_ITEM) {
							rq_data = AccessibilityServerEnums::SCROLL_UNIT_ITEM;
						} else if (p_request->data.value.scroll_unit == ACCESSKIT_SCROLL_UNIT_PAGE) {
							rq_data = AccessibilityServerEnums::SCROLL_UNIT_PAGE;
						}
					} break;
					case ACCESSKIT_ACTION_DATA_SCROLL_TO_POINT: {
						rq_data = Point2(p_request->data.value.scroll_to_point.x, p_request->data.value.scroll_to_point.y);
					} break;
					case ACCESSKIT_ACTION_DATA_SET_SCROLL_OFFSET: {
						rq_data = Point2(p_request->data.value.set_scroll_offset.x, p_request->data.value.set_scroll_offset.y);
					} break;
					case ACCESSKIT_ACTION_DATA_SET_TEXT_SELECTION: {
						Dictionary sel;

						RID start_rid = RID::from_uint64(p_request->data.value.set_text_selection.anchor.node);
						AccessibilityElement *start_ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(start_rid);
						ERR_FAIL_NULL(start_ae);

						RID end_rid = RID::from_uint64(p_request->data.value.set_text_selection.focus.node);
						AccessibilityElement *end_ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(end_rid);
						ERR_FAIL_NULL(end_ae);

						sel["start_element"] = start_ae->parent;
						sel["start_char"] = (int64_t)p_request->data.value.set_text_selection.anchor.character_index + start_ae->run.x;
						sel["end_element"] = end_ae->parent;
						sel["end_char"] = (int64_t)p_request->data.value.set_text_selection.focus.character_index + end_ae->run.x;
						rq_data = sel;
					} break;
				}
			}

			cb.call_deferred(rq_data);
		}
	}
}

accesskit_tree_update *AccessibilityServerAccessKit::_accessibility_initial_tree_update_callback(void *p_user_data) {
	DisplayServerEnums::WindowID window_id = (DisplayServerEnums::WindowID)(size_t)p_user_data;
	WindowData *wd = static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.getptr(window_id);
	ERR_FAIL_NULL_V(wd, nullptr);

	accesskit_node *win_node = accesskit_node_new(ACCESSKIT_ROLE_WINDOW);
	accesskit_node_set_label(win_node, "Godot Engine");
	accesskit_node_set_busy(win_node);

	accesskit_node_id win_id = (accesskit_node_id)wd->root_id.get_id();

	accesskit_tree_update *tree_update = accesskit_tree_update_with_capacity_and_focus(1, win_id);

	accesskit_tree_update_set_tree(tree_update, accesskit_tree_new(win_id));
	accesskit_tree_update_push_node(tree_update, win_id, win_node);

	print_verbose(vformat("Accessibility: window %d adapter activated.", window_id));

	if (wd->activate.is_valid()) {
		wd->activate.call_deferred(); // Should be called on main thread only.
	}
	wd->activated = true;

	return tree_update;
}

void AccessibilityServerAccessKit::set_window_callbacks(DisplayServerEnums::WindowID p_window_id, const Callable &p_activate_callable, const Callable &p_deativate_callable) {
	WindowData *wd = static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.getptr(p_window_id);
	ERR_FAIL_NULL(wd);

	wd->activate = p_activate_callable;
	wd->deactivate = p_deativate_callable;
}

void AccessibilityServerAccessKit::window_activation_completed(DisplayServerEnums::WindowID p_window_id) {
	WindowData *wd = static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.getptr(p_window_id);
	if (!wd) {
		return;
	}

	print_verbose(vformat("Accessibility: window %d adapter initial update completed.", p_window_id));

	wd->initial_update_completed = true;
}

void AccessibilityServerAccessKit::window_deactivation_completed(DisplayServerEnums::WindowID p_window_id) {
	WindowData *wd = static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.getptr(p_window_id);
	if (!wd) {
		return;
	}

	print_verbose(vformat("Accessibility: window %d adapter deactivation completed.", p_window_id));

#ifdef DEV_ENABLED
	LocalVector<RID> to_delete;
	for (const RID &rid : rid_owner.get_owned_list()) {
		AccessibilityElement *ae = rid_owner.get_or_null(rid);
		if (rid != wd->root_id && ae && ae->window_id == p_window_id) {
			ERR_PRINT(vformat("Accessibility/BUG: Accessibility element %d was not deleted on window %d adapter deactivation.", rid.get_id(), p_window_id));
			to_delete.push_back(rid);
		}
	}
	for (const RID &rid : to_delete) {
		_free_recursive(wd, rid);
	}
#endif
	wd->initial_update_completed = false;
}

RID AccessibilityServerAccessKit::create_element(DisplayServerEnums::WindowID p_window_id, AccessibilityServerEnums::AccessibilityRole p_role) {
	AccessibilityElement *ae = memnew(AccessibilityElement);
	ae->role = _accessibility_role(p_role);
	ae->window_id = p_window_id;
	RID rid = rid_owner.make_rid(ae);

	return rid;
}

RID AccessibilityServerAccessKit::create_sub_element(const RID &p_parent_rid, AccessibilityServerEnums::AccessibilityRole p_role, int p_insert_pos) {
	AccessibilityElement *parent_ae = rid_owner.get_or_null(p_parent_rid);
	ERR_FAIL_NULL_V(parent_ae, RID());

	WindowData *wd = windows.getptr(parent_ae->window_id);
	ERR_FAIL_NULL_V(wd, RID());

	AccessibilityElement *ae = memnew(AccessibilityElement);
	ae->role = _accessibility_role(p_role);
	ae->window_id = parent_ae->window_id;
	ae->parent = p_parent_rid;
	ae->node = accesskit_node_new(ae->role);
	RID rid = rid_owner.make_rid(ae);
	if (p_insert_pos == -1) {
		parent_ae->children.push_back(rid);
	} else {
		parent_ae->children.insert(p_insert_pos, rid);
	}
	wd->update.insert(rid);

	return rid;
}

RID AccessibilityServerAccessKit::create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos, bool p_is_last_line) {
	AccessibilityElement *parent_ae = rid_owner.get_or_null(p_parent_rid);
	ERR_FAIL_NULL_V(parent_ae, RID());

	WindowData *wd = windows.getptr(parent_ae->window_id);
	ERR_FAIL_NULL_V(wd, RID());

	AccessibilityElement *root_ae = memnew(AccessibilityElement);
	root_ae->role = ACCESSKIT_ROLE_GENERIC_CONTAINER;
	root_ae->window_id = parent_ae->window_id;
	root_ae->parent = p_parent_rid;
	root_ae->node = accesskit_node_new(root_ae->role);
	RID root_rid = rid_owner.make_rid(root_ae);
	if (p_insert_pos == -1) {
		parent_ae->children.push_back(root_rid);
	} else {
		parent_ae->children.insert(p_insert_pos, root_rid);
	}
	wd->update.insert(root_rid);

	float text_width = 0;
	float text_height = p_min_height;
	Vector<int32_t> words;
	int64_t run_count = 0; // Note: runs in visual order.
	const Glyph *gl = nullptr;
	float run_off_x = 0.0;
	Vector2i full_range;

	if (p_shaped_text.is_valid()) {
		text_width = TS->shaped_text_get_size(p_shaped_text).x;
		text_height = MAX(text_height, TS->shaped_text_get_size(p_shaped_text).y);
		words = TS->shaped_text_get_word_breaks(p_shaped_text);
		run_count = TS->shaped_get_run_count(p_shaped_text);
		gl = TS->shaped_text_get_glyphs(p_shaped_text);
		full_range = TS->shaped_text_get_range(p_shaped_text);
	}

	accesskit_rect root_rect;
	root_rect.x0 = 0;
	root_rect.y0 = 0;
	root_rect.x1 = text_width;
	root_rect.y1 = MAX(p_min_height, text_height);
	accesskit_node_set_bounds(root_ae->node, root_rect);

	// Create text element for each run.
	Vector<AccessibilityElement *> text_elements;
	for (int64_t i = 0; i < run_count; i++) {
		const Vector2i range = TS->shaped_get_run_range(p_shaped_text, i);
		const Vector2i gl_range = TS->shaped_get_run_glyph_range(p_shaped_text, i);
		String run_t = TS->shaped_get_run_text(p_shaped_text, i);
		TextServer::Direction dir = TS->shaped_get_run_direction(p_shaped_text, i);

		if (run_t.is_empty()) {
			continue;
		}

		// Split long runs in to < 254 char subruns due to AccessKit limitation.
		Vector<Vector2i> subrun_ranges;
		Vector<Vector<uint8_t>> subrun_word_starts;
		{
			Vector2i cur_range = range;
			bool slice = false;
			do {
				// Word starts.
				Vector<uint8_t> word_starts;
				word_starts.push_back(0);

				slice = false;
				for (int j = 0; j < words.size(); j += 2) {
					if (words[j] <= cur_range.x) {
						continue;
					}
					if (words[j] >= cur_range.y) {
						break;
					}
					int32_t wstart = words[j] - cur_range.x;
					int32_t wend = words[j + 1] - cur_range.x;
					if (wend >= 254) {
						cur_range.y = words[j];
						slice = true;
						break;
					}
					word_starts.push_back(wstart);
				}
				subrun_ranges.push_back(cur_range);
				subrun_word_starts.push_back(word_starts);

				if (slice) {
					cur_range.x = cur_range.y;
					cur_range.y = range.y;
				}
			} while (slice);
		}

		// Process subruns.
		int start, end, delta;
		if (dir == TextServer::DIRECTION_LTR) {
			start = 0;
			end = subrun_ranges.size();
			delta = +1;
		} else {
			start = subrun_ranges.size() - 1;
			end = -1;
			delta = -1;
		}
		for (int rr = start; rr != end; rr += delta) {
			// Word starts.
			const Vector<uint8_t> &word_starts = subrun_word_starts[rr];
			const Vector2i &cur_range = subrun_ranges[rr];

			AccessibilityElement *ae = memnew(AccessibilityElement);
			ae->role = ACCESSKIT_ROLE_TEXT_RUN;
			ae->window_id = parent_ae->window_id;
			ae->parent = root_rid;
			ae->run = Vector3i(cur_range.x, cur_range.y, i);
			ae->node = accesskit_node_new(ae->role);

			text_elements.push_back(ae);

			String sub_t = run_t.substr(cur_range.x - range.x, cur_range.y - cur_range.x);
			if (sub_t.is_empty()) {
				continue;
			}

			// UTF-8 text and char lengths.
			Vector<uint8_t> char_lengths;
			CharString text = sub_t.utf8(&char_lengths);

			ae->value = sub_t;
			accesskit_node_set_value(ae->node, text.ptr());
			accesskit_node_set_character_lengths(ae->node, char_lengths.size(), char_lengths.ptr());

			accesskit_node_set_word_starts(ae->node, word_starts.size(), word_starts.ptr());

			// Char widths and positions.
			Vector<float> char_positions;
			Vector<float> char_widths;

			char_positions.resize_initialized(sub_t.length());
			float *positions_ptr = char_positions.ptrw();

			char_widths.resize_initialized(sub_t.length());
			float *widths_ptr = char_widths.ptrw();

			float size_x = 0.0;
			for (int j = gl_range.x; j <= gl_range.y; j += gl[j].count) {
				if (gl[j].start >= ae->run.y || gl[j].start < ae->run.x) {
					continue;
				}

				float advance = 0.0; // Graphame advance.
				for (int k = 0; k < gl[j].count; k++) {
					advance += gl[j + k].advance;
				}
				int chars = gl[j].end - gl[j].start;
				float adv_per_char = advance / (float)chars;

				for (int k = 0; k < chars; k++) {
					int index = gl[j].start + k - ae->run.x;
					ERR_CONTINUE(index < 0 || index >= sub_t.length());
					positions_ptr[index] = size_x + adv_per_char * k;
					widths_ptr[index] = adv_per_char;
				}
				size_x += advance * gl[j].repeat;
			}
			positions_ptr[sub_t.length() - 1] = size_x;
			widths_ptr[sub_t.length() - 1] = 1.0;

			accesskit_node_set_character_positions(ae->node, char_positions.size(), char_positions.ptr());
			accesskit_node_set_character_widths(ae->node, char_widths.size(), char_widths.ptr());

			RID font_rid = TS->shaped_get_run_font_rid(p_shaped_text, i);
			if (font_rid != RID()) {
				CharString font_name = TS->font_get_name(font_rid).utf8();
				if (font_name.length() > 0) {
					accesskit_node_set_font_family(ae->node, font_name.ptr());
				}
				if (TS->font_get_style(font_rid).has_flag(TextServer::FONT_ITALIC)) {
					accesskit_node_set_italic(ae->node);
				}
				accesskit_node_set_font_weight(ae->node, TS->font_get_weight(font_rid));
			}
			accesskit_node_set_font_size(ae->node, TS->shaped_get_run_font_size(p_shaped_text, i));
			CharString language = TS->shaped_get_run_language(p_shaped_text, i).utf8();
			if (language.length() > 0) {
				accesskit_node_set_language(ae->node, language.ptr());
			}
			accesskit_node_set_text_direction(ae->node, ACCESSKIT_TEXT_DIRECTION_LEFT_TO_RIGHT);

			accesskit_rect rect;
			rect.x0 = run_off_x;
			rect.y0 = 0;
			rect.x1 = run_off_x + size_x;
			rect.y1 = text_height;
			accesskit_node_set_bounds(ae->node, rect);
			accesskit_node_add_action(ae->node, ACCESSKIT_ACTION_SCROLL_INTO_VIEW);

			run_off_x += size_x;
		}
	}
	if (!p_is_last_line || text_elements.is_empty()) {
		// Add "\n" at the end.
		AccessibilityElement *ae = memnew(AccessibilityElement);
		ae->role = ACCESSKIT_ROLE_TEXT_RUN;
		ae->window_id = parent_ae->window_id;
		ae->parent = root_rid;
		ae->run = Vector3i(full_range.y, full_range.y, run_count);
		ae->node = accesskit_node_new(ae->role);

		text_elements.push_back(ae);

		ae->value = String();
		if (!p_is_last_line) {
			accesskit_node_set_value(ae->node, "\n");

			Vector<uint8_t> char_lengths;
			Vector<float> char_positions;
			Vector<float> char_widths;
			char_lengths.push_back(1);
			char_positions.push_back(0.0);
			char_widths.push_back(1.0);

			accesskit_node_set_character_lengths(ae->node, char_lengths.size(), char_lengths.ptr());
			accesskit_node_set_character_positions(ae->node, char_positions.size(), char_positions.ptr());
			accesskit_node_set_character_widths(ae->node, char_widths.size(), char_widths.ptr());
		} else {
			accesskit_node_set_value(ae->node, "");
		}
		accesskit_node_set_text_direction(ae->node, ACCESSKIT_TEXT_DIRECTION_LEFT_TO_RIGHT);

		accesskit_rect rect;
		rect.x0 = run_off_x;
		rect.y0 = 0;
		rect.x1 = run_off_x + 1;
		rect.y1 = text_height;
		accesskit_node_set_bounds(ae->node, rect);
	}

	// Sort runs in logical order.
	struct RunCompare {
		_FORCE_INLINE_ bool operator()(const AccessibilityElement *l, const AccessibilityElement *r) const {
			return l->run.x < r->run.x;
		}
	};
	text_elements.sort_custom<RunCompare>();
	for (int i = 0; i < text_elements.size(); i++) {
		RID rid = rid_owner.make_rid(text_elements[i]);
		root_ae->children.push_back(rid);
		wd->update.insert(rid);

		// Link adjacent TextRuns on the same line.
		if (i > 0) {
			RID prev_rid = root_ae->children[i - 1];
			AccessibilityElement *prev_ae = rid_owner.get_or_null(prev_rid);
			accesskit_node_set_previous_on_line(text_elements[i]->node, (accesskit_node_id)prev_rid.get_id());
			accesskit_node_set_next_on_line(prev_ae->node, (accesskit_node_id)rid.get_id());
		}
	}

	return root_rid;
}

bool AccessibilityServerAccessKit::has_element(const RID &p_id) const {
	return rid_owner.owns(p_id);
}

void AccessibilityServerAccessKit::_free_recursive(WindowData *p_wd, const RID &p_id) {
	if (p_wd && p_wd->update.has(p_id)) {
		p_wd->update.erase(p_id);
	}
	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	for (const RID &rid : ae->children) {
		_free_recursive(p_wd, rid);
	}
	if (ae->node) {
		accesskit_node_free(ae->node);
	}
	memdelete(ae);
	rid_owner.free(p_id);
}

void AccessibilityServerAccessKit::free_element(const RID &p_id) {
	ERR_FAIL_COND_MSG(in_accessibility_update, "Element can't be removed inside NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	if (ae) {
		WindowData *wd = windows.getptr(ae->window_id);
		AccessibilityElement *parent_ae = rid_owner.get_or_null(ae->parent);
		if (parent_ae) {
			parent_ae->children.erase(p_id);
		}
		_free_recursive(wd, p_id);
	}
}

void AccessibilityServerAccessKit::element_set_meta(const RID &p_id, const Variant &p_meta) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	ae->meta = p_meta;
}

Variant AccessibilityServerAccessKit::element_get_meta(const RID &p_id) const {
	const AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL_V(ae, Variant());
	return ae->meta;
}

void AccessibilityServerAccessKit::update_set_focus(const RID &p_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	if (p_id.is_valid() && rid_owner.owns(p_id)) {
		focus = p_id;
	} else {
		focus = RID();
	}
}

RID AccessibilityServerAccessKit::get_window_root(DisplayServerEnums::WindowID p_window_id) const {
	const WindowData *wd = windows.getptr(p_window_id);
	ERR_FAIL_NULL_V(wd, RID());

	return wd->root_id;
}

accesskit_tree_update *AccessibilityServerAccessKit::_accessibility_build_tree_update(void *p_user_data) {
	DisplayServerEnums::WindowID window_id = (DisplayServerEnums::WindowID)(size_t)p_user_data;

	ERR_FAIL_COND_V(!static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows.has(window_id), nullptr);
	WindowData &wd = static_cast<AccessibilityServerAccessKit *>(get_singleton())->windows[window_id];

	static_cast<AccessibilityServerAccessKit *>(get_singleton())->in_accessibility_update = true;
	if (static_cast<AccessibilityServerAccessKit *>(get_singleton())->update_cb.is_valid()) {
		static_cast<AccessibilityServerAccessKit *>(get_singleton())->update_cb.call(window_id);
	}
	static_cast<AccessibilityServerAccessKit *>(get_singleton())->in_accessibility_update = false;

	AccessibilityElement *focus_ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(static_cast<AccessibilityServerAccessKit *>(get_singleton())->focus);
	uint32_t update_size = wd.update.size();

	accesskit_node_id ac_focus = (accesskit_node_id)wd.root_id.get_id();
	if (focus_ae && focus_ae->window_id == window_id) {
		ac_focus = (accesskit_node_id) static_cast<AccessibilityServerAccessKit *>(get_singleton())->focus.get_id();
	}
	accesskit_tree_update *tree_update = (update_size > 0) ? accesskit_tree_update_with_capacity_and_focus(update_size, ac_focus) : accesskit_tree_update_with_focus(ac_focus);
	for (const RID &rid : wd.update) {
		AccessibilityElement *ae = static_cast<AccessibilityServerAccessKit *>(get_singleton())->rid_owner.get_or_null(rid);
		if (ae && ae->node) {
			for (const RID &child_rid : ae->children) {
				accesskit_node_push_child(ae->node, (accesskit_node_id)child_rid.get_id());
			}
			accesskit_tree_update_push_node(tree_update, (accesskit_node_id)rid.get_id(), ae->node);
			ae->node = nullptr;
		}
	}
	wd.update.clear();

	return tree_update;
}

void AccessibilityServerAccessKit::update_if_active(const Callable &p_callable) {
	ERR_FAIL_COND(!p_callable.is_valid());
	update_cb = p_callable;
	for (KeyValue<DisplayServerEnums::WindowID, WindowData> &window : windows) {
#ifdef WINDOWS_ENABLED
		accesskit_windows_queued_events *events = accesskit_windows_subclassing_adapter_update_if_active(window.value.adapter, _accessibility_build_tree_update, (void *)(size_t)window.key);
		if (events) {
			accesskit_windows_queued_events_raise(events);
		}
#endif
#ifdef MACOS_ENABLED
		accesskit_macos_queued_events *events = accesskit_macos_subclassing_adapter_update_if_active(window.value.adapter, _accessibility_build_tree_update, (void *)(size_t)window.key);
		if (events) {
			accesskit_macos_queued_events_raise(events);
		}
#endif
#ifdef LINUXBSD_ENABLED
		accesskit_unix_adapter_update_if_active(window.value.adapter, _accessibility_build_tree_update, (void *)(size_t)window.key);
#endif
	}
	update_cb = Callable();
}

_FORCE_INLINE_ void AccessibilityServerAccessKit::_ensure_node(const RID &p_id, AccessibilityElement *p_ae) {
	if (unlikely(!p_ae->node)) {
		WindowData *wd = windows.getptr(p_ae->window_id);
		ERR_FAIL_NULL(wd);

		wd->update.insert(p_id);
		p_ae->node = accesskit_node_new(p_ae->role);

		// Re-apply stored name if any, so nodes recreated by _ensure_node
		// retain their label even if the caller doesn't re-set all properties.
		String full_name = (p_ae->name + " " + p_ae->name_extra_info).strip_edges();
		if (!full_name.is_empty()) {
			accesskit_node_set_label(p_ae->node, full_name.utf8().ptr());
		}
	}
}

void AccessibilityServerAccessKit::set_window_rect(DisplayServerEnums::WindowID p_window_id, const Rect2 &p_rect_out, const Rect2 &p_rect_in) {
#ifdef LINUXBSD_ENABLED
	const WindowData *wd = windows.getptr(p_window_id);
	ERR_FAIL_NULL(wd);

	accesskit_rect outer_bounds = { p_rect_out.position.x, p_rect_out.position.y, p_rect_out.position.x + p_rect_out.size.width, p_rect_out.position.y + p_rect_out.size.height };
	accesskit_rect inner_bounds = { p_rect_in.position.x, p_rect_in.position.y, p_rect_in.position.x + p_rect_in.size.width, p_rect_in.position.y + p_rect_in.size.height };
	accesskit_unix_adapter_set_root_window_bounds(wd->adapter, outer_bounds, inner_bounds);
#endif
}

void AccessibilityServerAccessKit::set_window_focused(DisplayServerEnums::WindowID p_window_id, bool p_focused) {
	const WindowData *wd = windows.getptr(p_window_id);
	ERR_FAIL_NULL(wd);

#ifdef LINUXBSD_ENABLED
	accesskit_unix_adapter_update_window_focus_state(wd->adapter, p_focused);
#endif
#ifdef MACOS_ENABLED
	accesskit_macos_queued_events *events = accesskit_macos_subclassing_adapter_update_view_focus_state(wd->adapter, p_focused);
	if (events != nullptr) {
		accesskit_macos_queued_events_raise(events);
	}
#endif
	// Note: On Windows, the subclassing adapter takes care of this.
}

void AccessibilityServerAccessKit::update_set_role(const RID &p_id, AccessibilityServerEnums::AccessibilityRole p_role) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	if (ae->role == _accessibility_role(p_role)) {
		return;
	}
	ae->role = _accessibility_role(p_role);
	_ensure_node(p_id, ae);

	accesskit_node_set_role(ae->node, ae->role);
}

void AccessibilityServerAccessKit::update_set_name(const RID &p_id, const String &p_name) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	ae->name = p_name;
	String full_name = (ae->name + " " + ae->name_extra_info).strip_edges();
	if (!full_name.is_empty()) {
		accesskit_node_set_label(ae->node, full_name.utf8().ptr());
	} else {
		accesskit_node_clear_label(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_braille_label(const RID &p_id, const String &p_name) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_name.is_empty()) {
		accesskit_node_set_braille_label(ae->node, p_name.utf8().ptr());
	} else {
		accesskit_node_clear_braille_label(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_braille_role_description(const RID &p_id, const String &p_description) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_description.is_empty()) {
		accesskit_node_set_braille_role_description(ae->node, p_description.utf8().ptr());
	} else {
		accesskit_node_clear_braille_role_description(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_extra_info(const RID &p_id, const String &p_name_extra_info) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	ae->name_extra_info = p_name_extra_info;
	String full_name = (ae->name + " " + ae->name_extra_info).strip_edges();
	if (!full_name.is_empty()) {
		accesskit_node_set_label(ae->node, full_name.utf8().ptr());
	} else {
		accesskit_node_clear_label(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_description(const RID &p_id, const String &p_description) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_description.is_empty()) {
		accesskit_node_set_description(ae->node, p_description.utf8().ptr());
	} else {
		accesskit_node_clear_description(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_value(const RID &p_id, const String &p_value) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_value.is_empty()) {
		Vector<uint8_t> ch_length;
		ae->value = p_value;
		accesskit_node_set_value(ae->node, p_value.utf8(&ch_length).ptr());
		accesskit_node_set_character_lengths(ae->node, ch_length.size(), ch_length.ptr());
	} else {
		ae->value = String();
		accesskit_node_clear_value(ae->node);
		accesskit_node_clear_character_lengths(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_tooltip(const RID &p_id, const String &p_tooltip) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_tooltip.is_empty()) {
		accesskit_node_set_tooltip(ae->node, p_tooltip.utf8().ptr());
	} else {
		accesskit_node_clear_tooltip(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_bounds(const RID &p_id, const Rect2 &p_rect) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_rect rect;
	rect.x0 = p_rect.position.x;
	rect.y0 = p_rect.position.y;
	rect.x1 = p_rect.position.x + p_rect.size.x;
	rect.y1 = p_rect.position.y + p_rect.size.y;
	accesskit_node_set_bounds(ae->node, rect);
}

void AccessibilityServerAccessKit::update_set_transform(const RID &p_id, const Transform2D &p_transform) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_affine transform = { p_transform.columns[0][0], p_transform.columns[0][1], p_transform.columns[1][0], p_transform.columns[1][1], p_transform.columns[2][0], p_transform.columns[2][1] };
	accesskit_node_set_transform(ae->node, transform);
}

void AccessibilityServerAccessKit::update_add_child(const RID &p_id, const RID &p_child_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_child_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_child(ae->node, (accesskit_node_id)p_child_id.get_id());
}

void AccessibilityServerAccessKit::update_add_related_controls(const RID &p_id, const RID &p_related_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_related_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_controlled(ae->node, (accesskit_node_id)p_related_id.get_id());
}

void AccessibilityServerAccessKit::update_add_related_details(const RID &p_id, const RID &p_related_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_related_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_detail(ae->node, (accesskit_node_id)p_related_id.get_id());
}

void AccessibilityServerAccessKit::update_add_related_described_by(const RID &p_id, const RID &p_related_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_related_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_described_by(ae->node, (accesskit_node_id)p_related_id.get_id());
}

void AccessibilityServerAccessKit::update_add_related_flow_to(const RID &p_id, const RID &p_related_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_related_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_flow_to(ae->node, (accesskit_node_id)p_related_id.get_id());
}

void AccessibilityServerAccessKit::update_add_related_labeled_by(const RID &p_id, const RID &p_related_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_related_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_labelled_by(ae->node, (accesskit_node_id)p_related_id.get_id());
}

void AccessibilityServerAccessKit::update_add_related_radio_group(const RID &p_id, const RID &p_related_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_related_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_push_to_radio_group(ae->node, (accesskit_node_id)p_related_id.get_id());
}

void AccessibilityServerAccessKit::update_set_active_descendant(const RID &p_id, const RID &p_other_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_other_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_set_active_descendant(ae->node, (accesskit_node_id)p_other_id.get_id());
}

void AccessibilityServerAccessKit::update_set_next_on_line(const RID &p_id, const RID &p_other_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_other_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_set_next_on_line(ae->node, (accesskit_node_id)p_other_id.get_id());
}

void AccessibilityServerAccessKit::update_set_previous_on_line(const RID &p_id, const RID &p_other_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_other_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_set_previous_on_line(ae->node, (accesskit_node_id)p_other_id.get_id());
}

void AccessibilityServerAccessKit::update_set_member_of(const RID &p_id, const RID &p_group_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_group_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_set_member_of(ae->node, (accesskit_node_id)p_group_id.get_id());
}

void AccessibilityServerAccessKit::update_set_in_page_link_target(const RID &p_id, const RID &p_other_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_other_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_set_in_page_link_target(ae->node, (accesskit_node_id)p_other_id.get_id());
}

void AccessibilityServerAccessKit::update_set_error_message(const RID &p_id, const RID &p_other_id) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *other_ae = rid_owner.get_or_null(p_other_id);
	ERR_FAIL_NULL(other_ae);
	ERR_FAIL_COND(other_ae->window_id != ae->window_id);
	_ensure_node(p_id, ae);

	accesskit_node_set_error_message(ae->node, (accesskit_node_id)p_other_id.get_id());
}

void AccessibilityServerAccessKit::update_set_live(const RID &p_id, AccessibilityServerEnums::AccessibilityLiveMode p_live) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	switch (p_live) {
		case AccessibilityServerEnums::AccessibilityLiveMode::LIVE_OFF: {
			accesskit_node_set_live(ae->node, ACCESSKIT_LIVE_OFF);
		} break;
		case AccessibilityServerEnums::AccessibilityLiveMode::LIVE_POLITE: {
			accesskit_node_set_live(ae->node, ACCESSKIT_LIVE_POLITE);
		} break;
		case AccessibilityServerEnums::AccessibilityLiveMode::LIVE_ASSERTIVE: {
			accesskit_node_set_live(ae->node, ACCESSKIT_LIVE_ASSERTIVE);
		} break;
	}
}

void AccessibilityServerAccessKit::update_add_action(const RID &p_id, AccessibilityServerEnums::AccessibilityAction p_action, const Callable &p_callable) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	ae->actions[_accessibility_action(p_action)] = p_callable;

	accesskit_node_add_action(ae->node, _accessibility_action(p_action));
}

void AccessibilityServerAccessKit::update_add_custom_action(const RID &p_id, int p_action_id, const String &p_action_description) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_action_description.is_empty()) {
		accesskit_custom_action *ca = accesskit_custom_action_new(p_action_id);
		accesskit_custom_action_set_description(ca, p_action_description.utf8().ptr());
		accesskit_node_push_custom_action(ae->node, ca);
	} else {
		String cs_name = vformat("Custom Action %d", p_action_id);
		accesskit_custom_action *ca = accesskit_custom_action_new(p_action_id);
		accesskit_custom_action_set_description(ca, cs_name.utf8().ptr());
		accesskit_node_push_custom_action(ae->node, ca);
	}
}

void AccessibilityServerAccessKit::update_set_table_row_count(const RID &p_id, int p_count) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_row_count(ae->node, p_count);
}

void AccessibilityServerAccessKit::update_set_table_column_count(const RID &p_id, int p_count) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_column_count(ae->node, p_count);
}

void AccessibilityServerAccessKit::update_set_table_row_index(const RID &p_id, int p_index) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_row_index(ae->node, p_index);
}

void AccessibilityServerAccessKit::update_set_table_column_index(const RID &p_id, int p_index) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_column_index(ae->node, p_index);
}

void AccessibilityServerAccessKit::update_set_table_cell_position(const RID &p_id, int p_row_index, int p_column_index) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_row_index(ae->node, p_row_index);
	accesskit_node_set_column_index(ae->node, p_column_index);
}

void AccessibilityServerAccessKit::update_set_table_cell_span(const RID &p_id, int p_row_span, int p_column_span) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_row_span(ae->node, p_row_span);
	accesskit_node_set_column_span(ae->node, p_column_span);
}

void AccessibilityServerAccessKit::update_set_list_item_count(const RID &p_id, int p_size) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_size_of_set(ae->node, p_size);
}

void AccessibilityServerAccessKit::update_set_list_item_index(const RID &p_id, int p_index) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_position_in_set(ae->node, p_index);
}

void AccessibilityServerAccessKit::update_set_list_item_level(const RID &p_id, int p_level) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_level(ae->node, p_level);
}

void AccessibilityServerAccessKit::update_set_list_item_selected(const RID &p_id, bool p_selected) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_selected(ae->node, p_selected);
}

void AccessibilityServerAccessKit::update_set_list_item_expanded(const RID &p_id, bool p_expanded) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_expanded(ae->node, p_expanded);
}

void AccessibilityServerAccessKit::update_set_popup_type(const RID &p_id, AccessibilityServerEnums::AccessibilityPopupType p_popup) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	switch (p_popup) {
		case AccessibilityServerEnums::AccessibilityPopupType::POPUP_MENU: {
			accesskit_node_set_has_popup(ae->node, ACCESSKIT_HAS_POPUP_MENU);
		} break;
		case AccessibilityServerEnums::AccessibilityPopupType::POPUP_LIST: {
			accesskit_node_set_has_popup(ae->node, ACCESSKIT_HAS_POPUP_LISTBOX);
		} break;
		case AccessibilityServerEnums::AccessibilityPopupType::POPUP_TREE: {
			accesskit_node_set_has_popup(ae->node, ACCESSKIT_HAS_POPUP_TREE);
		} break;
		case AccessibilityServerEnums::AccessibilityPopupType::POPUP_DIALOG: {
			accesskit_node_set_has_popup(ae->node, ACCESSKIT_HAS_POPUP_DIALOG);
		} break;
	}
}

void AccessibilityServerAccessKit::update_set_checked(const RID &p_id, bool p_checekd) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (p_checekd) {
		accesskit_node_set_toggled(ae->node, ACCESSKIT_TOGGLED_TRUE);
	} else {
		accesskit_node_set_toggled(ae->node, ACCESSKIT_TOGGLED_FALSE);
	}
}

void AccessibilityServerAccessKit::update_set_num_value(const RID &p_id, double p_position) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_numeric_value(ae->node, p_position);
	ae->value = p_position;
}

void AccessibilityServerAccessKit::update_set_num_range(const RID &p_id, double p_min, double p_max) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_min_numeric_value(ae->node, p_min);
	accesskit_node_set_max_numeric_value(ae->node, p_max);
}

void AccessibilityServerAccessKit::update_set_num_step(const RID &p_id, double p_step) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_numeric_value_step(ae->node, p_step);
}

void AccessibilityServerAccessKit::update_set_num_jump(const RID &p_id, double p_jump) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_numeric_value_jump(ae->node, p_jump);
}

void AccessibilityServerAccessKit::update_set_scroll_x(const RID &p_id, double p_position) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_scroll_x(ae->node, p_position);
}

void AccessibilityServerAccessKit::update_set_scroll_x_range(const RID &p_id, double p_min, double p_max) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_scroll_x_min(ae->node, p_min);
	accesskit_node_set_scroll_x_max(ae->node, p_max);
}

void AccessibilityServerAccessKit::update_set_scroll_y(const RID &p_id, double p_position) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_scroll_y(ae->node, p_position);
}

void AccessibilityServerAccessKit::update_set_scroll_y_range(const RID &p_id, double p_min, double p_max) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_scroll_y_min(ae->node, p_min);
	accesskit_node_set_scroll_y_max(ae->node, p_max);
}

void AccessibilityServerAccessKit::update_set_text_decorations(const RID &p_id, bool p_underline, bool p_strikethrough, bool p_overline, const Color &p_color) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_color color;
	color.red = p_color.get_r8();
	color.blue = p_color.get_b8();
	color.green = p_color.get_g8();
	color.alpha = p_color.get_a8();

	if (p_underline) {
		accesskit_node_set_underline(ae->node, { ACCESSKIT_TEXT_DECORATION_STYLE_SOLID, color });
	} else {
		accesskit_node_clear_underline(ae->node);
	}
	if (p_overline) {
		accesskit_node_set_overline(ae->node, { ACCESSKIT_TEXT_DECORATION_STYLE_SOLID, color });
	} else {
		accesskit_node_clear_overline(ae->node);
	}
	if (p_strikethrough) {
		accesskit_node_set_strikethrough(ae->node, { ACCESSKIT_TEXT_DECORATION_STYLE_SOLID, color });
	} else {
		accesskit_node_clear_strikethrough(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_text_align(const RID &p_id, HorizontalAlignment p_align) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	switch (p_align) {
		case HORIZONTAL_ALIGNMENT_LEFT: {
			accesskit_node_set_text_align(ae->node, ACCESSKIT_TEXT_ALIGN_LEFT);
		} break;
		case HORIZONTAL_ALIGNMENT_CENTER: {
			accesskit_node_set_text_align(ae->node, ACCESSKIT_TEXT_ALIGN_RIGHT);
		} break;
		case HORIZONTAL_ALIGNMENT_RIGHT: {
			accesskit_node_set_text_align(ae->node, ACCESSKIT_TEXT_ALIGN_CENTER);
		} break;
		case HORIZONTAL_ALIGNMENT_FILL: {
			accesskit_node_set_text_align(ae->node, ACCESSKIT_TEXT_ALIGN_JUSTIFY);
		} break;
	}
}

void AccessibilityServerAccessKit::update_set_text_selection(const RID &p_id, const RID &p_text_start_id, int p_start_char, const RID &p_text_end_id, int p_end_char) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	AccessibilityElement *start_ae = rid_owner.get_or_null(p_text_start_id);
	ERR_FAIL_NULL(start_ae);
	ERR_FAIL_COND(start_ae->window_id != ae->window_id);
	AccessibilityElement *end_ae = rid_owner.get_or_null(p_text_end_id);
	ERR_FAIL_NULL(end_ae);
	ERR_FAIL_COND(end_ae->window_id != ae->window_id);

	int start_pos = p_start_char;
	int end_pos = p_end_char;
	RID start_rid;
	RID end_rid;
	for (const RID &rid : start_ae->children) {
		const AccessibilityElement *child_ae = rid_owner.get_or_null(rid);
		if (child_ae && child_ae->role == ACCESSKIT_ROLE_TEXT_RUN) {
			if (p_start_char >= child_ae->run.x && p_start_char <= child_ae->run.y) {
				start_rid = rid;
				start_pos = p_start_char - child_ae->run.x;
				break;
			}
		}
	}
	for (const RID &rid : end_ae->children) {
		const AccessibilityElement *child_ae = rid_owner.get_or_null(rid);
		if (child_ae && child_ae->role == ACCESSKIT_ROLE_TEXT_RUN) {
			if (p_end_char >= child_ae->run.x && p_end_char <= child_ae->run.y) {
				end_rid = rid;
				end_pos = p_end_char - child_ae->run.x;
				break;
			}
		}
	}
	ERR_FAIL_COND(start_rid.is_null() && end_rid.is_null());
	_ensure_node(p_id, ae);

	accesskit_text_selection sel;
	sel.anchor.node = (accesskit_node_id)start_rid.get_id();
	sel.anchor.character_index = start_pos;
	sel.focus.node = (accesskit_node_id)end_rid.get_id();
	sel.focus.character_index = end_pos;
	accesskit_node_set_text_selection(ae->node, sel);
}

void AccessibilityServerAccessKit::update_set_flag(const RID &p_id, AccessibilityServerEnums::AccessibilityFlags p_flag, bool p_value) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (p_value) {
		ae->flags |= (1ULL << (uint64_t)p_flag);
	} else {
		ae->flags &= ~(1ULL << (uint64_t)p_flag);
	}
	switch (p_flag) {
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_HIDDEN: {
			if (p_value) {
				accesskit_node_set_hidden(ae->node);
			} else {
				accesskit_node_clear_hidden(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_MULTISELECTABLE: {
			if (p_value) {
				accesskit_node_set_multiselectable(ae->node);
			} else {
				accesskit_node_clear_multiselectable(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_REQUIRED: {
			if (p_value) {
				accesskit_node_set_required(ae->node);
			} else {
				accesskit_node_clear_required(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_VISITED: {
			if (p_value) {
				accesskit_node_set_visited(ae->node);
			} else {
				accesskit_node_clear_visited(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_BUSY: {
			if (p_value) {
				accesskit_node_set_busy(ae->node);
			} else {
				accesskit_node_clear_busy(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_MODAL: {
			if (p_value) {
				accesskit_node_set_modal(ae->node);
			} else {
				accesskit_node_clear_modal(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_TOUCH_PASSTHROUGH: {
			if (p_value) {
				accesskit_node_set_touch_transparent(ae->node);
			} else {
				accesskit_node_clear_touch_transparent(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_READONLY: {
			if (p_value) {
				accesskit_node_set_read_only(ae->node);
			} else {
				accesskit_node_clear_read_only(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_DISABLED: {
			if (p_value) {
				accesskit_node_set_disabled(ae->node);
			} else {
				accesskit_node_clear_disabled(ae->node);
			}
		} break;
		case AccessibilityServerEnums::AccessibilityFlags::FLAG_CLIPS_CHILDREN: {
			if (p_value) {
				accesskit_node_set_clips_children(ae->node);
			} else {
				accesskit_node_clear_clips_children(ae->node);
			}
		} break;
	}
}

void AccessibilityServerAccessKit::update_set_classname(const RID &p_id, const String &p_classname) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_classname.is_empty()) {
		accesskit_node_set_class_name(ae->node, p_classname.utf8().ptr());
	} else {
		accesskit_node_clear_class_name(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_placeholder(const RID &p_id, const String &p_placeholder) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_placeholder.is_empty()) {
		accesskit_node_set_placeholder(ae->node, p_placeholder.utf8().ptr());
	} else {
		accesskit_node_clear_placeholder(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_language(const RID &p_id, const String &p_language) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_node_set_language(ae->node, p_language.utf8().ptr());
}

void AccessibilityServerAccessKit::update_set_text_orientation(const RID &p_id, bool p_vertical) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (p_vertical) {
		accesskit_node_set_text_direction(ae->node, ACCESSKIT_TEXT_DIRECTION_TOP_TO_BOTTOM);
	} else {
		accesskit_node_set_text_direction(ae->node, ACCESSKIT_TEXT_DIRECTION_LEFT_TO_RIGHT);
	}
}

void AccessibilityServerAccessKit::update_set_list_orientation(const RID &p_id, bool p_vertical) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (p_vertical) {
		accesskit_node_set_orientation(ae->node, ACCESSKIT_ORIENTATION_VERTICAL);
	} else {
		accesskit_node_set_orientation(ae->node, ACCESSKIT_ORIENTATION_HORIZONTAL);
	}
}

void AccessibilityServerAccessKit::update_set_shortcut(const RID &p_id, const String &p_shortcut) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_shortcut.is_empty()) {
		accesskit_node_set_keyboard_shortcut(ae->node, p_shortcut.utf8().ptr());
	} else {
		accesskit_node_clear_keyboard_shortcut(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_url(const RID &p_id, const String &p_url) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_url.is_empty()) {
		accesskit_node_set_url(ae->node, p_url.utf8().ptr());
	} else {
		accesskit_node_clear_url(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_role_description(const RID &p_id, const String &p_description) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_description.is_empty()) {
		accesskit_node_set_role_description(ae->node, p_description.utf8().ptr());
	} else {
		accesskit_node_clear_role_description(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_state_description(const RID &p_id, const String &p_description) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	if (!p_description.is_empty()) {
		accesskit_node_set_state_description(ae->node, p_description.utf8().ptr());
	} else {
		accesskit_node_clear_state_description(ae->node);
	}
}

void AccessibilityServerAccessKit::update_set_color_value(const RID &p_id, const Color &p_color) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	ae->value = p_color;

	accesskit_color color;
	color.red = p_color.get_r8();
	color.blue = p_color.get_b8();
	color.green = p_color.get_g8();
	color.alpha = p_color.get_a8();

	accesskit_node_set_color_value(ae->node, color);
}

void AccessibilityServerAccessKit::update_set_background_color(const RID &p_id, const Color &p_color) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_color color;
	color.red = p_color.get_r8();
	color.blue = p_color.get_b8();
	color.green = p_color.get_g8();
	color.alpha = p_color.get_a8();

	accesskit_node_set_background_color(ae->node, color);
}

void AccessibilityServerAccessKit::update_set_foreground_color(const RID &p_id, const Color &p_color) {
	ERR_FAIL_COND_MSG(!in_accessibility_update, "Accessibility updates are only allowed inside the NOTIFICATION_ACCESSIBILITY_UPDATE notification.");

	AccessibilityElement *ae = rid_owner.get_or_null(p_id);
	ERR_FAIL_NULL(ae);
	_ensure_node(p_id, ae);

	accesskit_color color;
	color.red = p_color.get_r8();
	color.blue = p_color.get_b8();
	color.green = p_color.get_g8();
	color.alpha = p_color.get_a8();

	accesskit_node_set_foreground_color(ae->node, color);
}

AccessibilityServer *AccessibilityServerAccessKit::create_func(Error &r_error) {
	print_verbose("Accessibility: AccessKit driver loaded.");
	r_error = OK;
	return memnew(AccessibilityServerAccessKit);
}

AccessibilityServerAccessKit::AccessibilityServerAccessKit() {
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_UNKNOWN] = ACCESSKIT_ROLE_UNKNOWN;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_DEFAULT_BUTTON] = ACCESSKIT_ROLE_DEFAULT_BUTTON;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_AUDIO] = ACCESSKIT_ROLE_AUDIO;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_VIDEO] = ACCESSKIT_ROLE_VIDEO;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_STATIC_TEXT] = ACCESSKIT_ROLE_LABEL;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_CONTAINER] = ACCESSKIT_ROLE_GENERIC_CONTAINER;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_PANEL] = ACCESSKIT_ROLE_PANE;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_BUTTON] = ACCESSKIT_ROLE_BUTTON;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_LINK] = ACCESSKIT_ROLE_LINK;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_CHECK_BOX] = ACCESSKIT_ROLE_CHECK_BOX;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_RADIO_BUTTON] = ACCESSKIT_ROLE_RADIO_BUTTON;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_CHECK_BUTTON] = ACCESSKIT_ROLE_SWITCH;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_SCROLL_BAR] = ACCESSKIT_ROLE_SCROLL_BAR;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_SCROLL_VIEW] = ACCESSKIT_ROLE_SCROLL_VIEW;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_SPLITTER] = ACCESSKIT_ROLE_SPLITTER;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_SLIDER] = ACCESSKIT_ROLE_SLIDER;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_SPIN_BUTTON] = ACCESSKIT_ROLE_SPIN_BUTTON;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_PROGRESS_INDICATOR] = ACCESSKIT_ROLE_PROGRESS_INDICATOR;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TEXT_FIELD] = ACCESSKIT_ROLE_TEXT_INPUT;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_MULTILINE_TEXT_FIELD] = ACCESSKIT_ROLE_MULTILINE_TEXT_INPUT;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_COLOR_PICKER] = ACCESSKIT_ROLE_COLOR_WELL;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TABLE] = ACCESSKIT_ROLE_TABLE;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_CELL] = ACCESSKIT_ROLE_CELL;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_ROW] = ACCESSKIT_ROLE_ROW;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_ROW_GROUP] = ACCESSKIT_ROLE_ROW_GROUP;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_ROW_HEADER] = ACCESSKIT_ROLE_ROW_HEADER;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_COLUMN_HEADER] = ACCESSKIT_ROLE_COLUMN_HEADER;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TREE] = ACCESSKIT_ROLE_TREE;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TREE_ITEM] = ACCESSKIT_ROLE_TREE_ITEM;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_LIST] = ACCESSKIT_ROLE_LIST;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_LIST_ITEM] = ACCESSKIT_ROLE_LIST_ITEM;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_LIST_BOX] = ACCESSKIT_ROLE_LIST_BOX;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_LIST_BOX_OPTION] = ACCESSKIT_ROLE_LIST_BOX_OPTION;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TAB_BAR] = ACCESSKIT_ROLE_TAB_LIST;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TAB] = ACCESSKIT_ROLE_TAB;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TAB_PANEL] = ACCESSKIT_ROLE_TAB_PANEL;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_MENU_BAR] = ACCESSKIT_ROLE_MENU_BAR;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_MENU] = ACCESSKIT_ROLE_MENU;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_MENU_ITEM] = ACCESSKIT_ROLE_MENU_ITEM;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_MENU_ITEM_CHECK_BOX] = ACCESSKIT_ROLE_MENU_ITEM_CHECK_BOX;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_MENU_ITEM_RADIO] = ACCESSKIT_ROLE_MENU_ITEM_RADIO;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_IMAGE] = ACCESSKIT_ROLE_IMAGE;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_WINDOW] = ACCESSKIT_ROLE_WINDOW;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TITLE_BAR] = ACCESSKIT_ROLE_TITLE_BAR;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_DIALOG] = ACCESSKIT_ROLE_DIALOG;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TOOLTIP] = ACCESSKIT_ROLE_TOOLTIP;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_REGION] = ACCESSKIT_ROLE_REGION;
	role_map[AccessibilityServerEnums::AccessibilityRole::ROLE_TEXT_RUN] = ACCESSKIT_ROLE_TEXT_RUN;

	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_CLICK] = ACCESSKIT_ACTION_CLICK;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_FOCUS] = ACCESSKIT_ACTION_FOCUS;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_BLUR] = ACCESSKIT_ACTION_BLUR;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_COLLAPSE] = ACCESSKIT_ACTION_COLLAPSE;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_EXPAND] = ACCESSKIT_ACTION_EXPAND;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_DECREMENT] = ACCESSKIT_ACTION_DECREMENT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_INCREMENT] = ACCESSKIT_ACTION_INCREMENT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_HIDE_TOOLTIP] = ACCESSKIT_ACTION_HIDE_TOOLTIP;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SHOW_TOOLTIP] = ACCESSKIT_ACTION_SHOW_TOOLTIP;
	//action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_INVALIDATE_TREE] = ACCESSKIT_ACTION_INVALIDATE_TREE;
	//action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_LOAD_INLINE_TEXT_BOXES] = ACCESSKIT_ACTION_LOAD_INLINE_TEXT_BOXES;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SET_TEXT_SELECTION] = ACCESSKIT_ACTION_SET_TEXT_SELECTION;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_REPLACE_SELECTED_TEXT] = ACCESSKIT_ACTION_REPLACE_SELECTED_TEXT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_BACKWARD] = ACCESSKIT_ACTION_SCROLL_UP;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_DOWN] = ACCESSKIT_ACTION_SCROLL_DOWN;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_FORWARD] = ACCESSKIT_ACTION_SCROLL_DOWN;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_LEFT] = ACCESSKIT_ACTION_SCROLL_LEFT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_RIGHT] = ACCESSKIT_ACTION_SCROLL_RIGHT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_UP] = ACCESSKIT_ACTION_SCROLL_UP;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_INTO_VIEW] = ACCESSKIT_ACTION_SCROLL_INTO_VIEW;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SCROLL_TO_POINT] = ACCESSKIT_ACTION_SCROLL_TO_POINT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SET_SCROLL_OFFSET] = ACCESSKIT_ACTION_SET_SCROLL_OFFSET;
	//action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT] = ACCESSKIT_ACTION_SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SET_VALUE] = ACCESSKIT_ACTION_SET_VALUE;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU] = ACCESSKIT_ACTION_SHOW_CONTEXT_MENU;
	action_map[AccessibilityServerEnums::AccessibilityAction::ACTION_CUSTOM] = ACCESSKIT_ACTION_CUSTOM_ACTION;
}

AccessibilityServerAccessKit::~AccessibilityServerAccessKit() {}

void AccessibilityServerAccessKit::register_create_func() {
	register_create_function("accesskit", create_func);
}

#endif // ACCESSKIT_ENABLED