diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index e194462cb4d..2bece46fed3 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -34,8 +34,10 @@ + Creates a new, empty accessibility sub-element from the shaped text buffer. Sub-elements are freed automatically when the parent element is freed, or can be freed early using the [method accessibility_free_element] method. + If [param is_last_line] is [code]true[/code], no trailing newline is appended to the text content. Set to [code]true[/code] for the last line in multi-line text fields and for single-line text fields. diff --git a/drivers/accesskit/accessibility_driver_accesskit.cpp b/drivers/accesskit/accessibility_driver_accesskit.cpp index fd7695af1c1..0749e873a31 100644 --- a/drivers/accesskit/accessibility_driver_accesskit.cpp +++ b/drivers/accesskit/accessibility_driver_accesskit.cpp @@ -250,7 +250,7 @@ RID AccessibilityDriverAccessKit::accessibility_create_sub_element(const RID &p_ return rid; } -RID AccessibilityDriverAccessKit::accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos) { +RID AccessibilityDriverAccessKit::accessibility_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()); @@ -421,7 +421,7 @@ RID AccessibilityDriverAccessKit::accessibility_create_sub_text_edit_elements(co 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; @@ -432,18 +432,22 @@ RID AccessibilityDriverAccessKit::accessibility_create_sub_text_edit_elements(co text_elements.push_back(ae); - Vector char_lengths; - char_lengths.push_back(1); - accesskit_node_set_value(ae->node, "\n"); - accesskit_node_set_character_lengths(ae->node, char_lengths.size(), char_lengths.ptr()); + if (!p_is_last_line) { + accesskit_node_set_value(ae->node, "\n"); - Vector char_positions; - Vector char_widths; - char_positions.push_back(0.0); - char_widths.push_back(1.0); + Vector char_lengths; + Vector char_positions; + Vector char_widths; + char_lengths.push_back(1); + char_positions.push_back(0.0); + char_widths.push_back(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()); + 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; @@ -461,10 +465,18 @@ RID AccessibilityDriverAccessKit::accessibility_create_sub_text_edit_elements(co } }; text_elements.sort_custom(); - for (AccessibilityElement *text_element : text_elements) { - RID rid = rid_owner.make_rid(text_element); + 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; diff --git a/drivers/accesskit/accessibility_driver_accesskit.h b/drivers/accesskit/accessibility_driver_accesskit.h index 7ba14d8f98e..2349602818c 100644 --- a/drivers/accesskit/accessibility_driver_accesskit.h +++ b/drivers/accesskit/accessibility_driver_accesskit.h @@ -113,7 +113,7 @@ public: RID accessibility_create_element(DisplayServer::WindowID p_window_id, DisplayServer::AccessibilityRole p_role) override; RID accessibility_create_sub_element(const RID &p_parent_rid, DisplayServer::AccessibilityRole p_role, int p_insert_pos = -1) override; - virtual RID accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1) override; + virtual RID accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1, bool p_is_last_line = false) override; bool accessibility_has_element(const RID &p_id) const override; void accessibility_free_element(const RID &p_id) override; diff --git a/misc/extension_api_validation/4.5-stable.expected b/misc/extension_api_validation/4.5-stable.expected index 1ceee9cbc7f..5a8631a1303 100644 --- a/misc/extension_api_validation/4.5-stable.expected +++ b/misc/extension_api_validation/4.5-stable.expected @@ -233,3 +233,10 @@ Validate extension JSON: Error: Field 'classes/EditorExportPreset/methods/get_sc Validate extension JSON: Error: Field 'classes/EditorExportPreset/methods/get_script_export_mode/return_value': type changed value in new API, from "int" to "enum::EditorExportPreset.ScriptExportMode". Change return type from `int` to `EditorExportPreset.ScriptExportMode` enum. Compatibility method registered. + + +GH-113459 +--------- +Validate extension JSON: Error: Field 'classes/DisplayServer/methods/accessibility_create_sub_text_edit_elements/arguments': size changed value in new API, from 4 to 5. + +Optional argument added. Compatibility method registered. diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 332abef942e..a7d9606fa57 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -1311,7 +1311,7 @@ void LineEdit::_notification(int p_what) { float text_off_x = x_ofs + scroll_offset; if (accessibility_text_root_element.is_null()) { - accessibility_text_root_element = DisplayServer::get_singleton()->accessibility_create_sub_text_edit_elements(ae, using_placeholder ? RID() : text_rid, text_height); + accessibility_text_root_element = DisplayServer::get_singleton()->accessibility_create_sub_text_edit_elements(ae, using_placeholder ? RID() : text_rid, text_height, -1, true); } Transform2D text_xform; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1aae07a1fc1..2675c6fe601 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -243,7 +243,8 @@ void TextEdit::Text::update_accessibility(int p_line, RID p_root) { Line &l = text.write[p_line]; if (l.accessibility_text_root_element.is_empty()) { for (int i = 0; i < l.data_buf->get_line_count(); i++) { - RID rid = DisplayServer::get_singleton()->accessibility_create_sub_text_edit_elements(p_root, l.data_buf->get_line_rid(i), max_line_height, p_line); + bool is_last_line = (p_line == text.size() - 1) && (i == l.data_buf->get_line_count() - 1); + RID rid = DisplayServer::get_singleton()->accessibility_create_sub_text_edit_elements(p_root, l.data_buf->get_line_rid(i), max_line_height, p_line, is_last_line); l.accessibility_text_root_element.push_back(rid); } } @@ -738,7 +739,6 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: case NOTIFICATION_ACCESSIBILITY_INVALIDATE: { text.clear_accessibility(); - accessibility_text_root_element_nl = RID(); } break; case NOTIFICATION_ACCESSIBILITY_UPDATE: { @@ -807,9 +807,6 @@ void TextEdit::_notification(int p_what) { } lines_drawn += ac_buf->get_line_count(); } - if (accessibility_text_root_element_nl.is_null()) { - accessibility_text_root_element_nl = DisplayServer::get_singleton()->accessibility_create_sub_text_edit_elements(ae, RID(), get_line_height()); - } // Selection. if (carets.size() > 0) { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index b17e205e3bd..3181ed9ad1e 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -659,8 +659,6 @@ private: bool draw_tabs = false; bool draw_spaces = false; - RID accessibility_text_root_element_nl; - // FIXME: Helper method to draw unfilled rects, should be moved to RenderingServer. void _draw_rect_unfilled(RID p_canvas_item, const Rect2 &p_rect, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false) const; diff --git a/servers/display/display_server.compat.inc b/servers/display/display_server.compat.inc index 165dad94c14..f3f0b482e15 100644 --- a/servers/display/display_server.compat.inc +++ b/servers/display/display_server.compat.inc @@ -38,9 +38,14 @@ Error DisplayServer::_file_dialog_with_options_show_bind_compat_98194(const Stri return file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, MAIN_WINDOW_ID); } +RID DisplayServer::_accessibility_create_sub_text_edit_elements_bind_compat_113459(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos) { + return accessibility_create_sub_text_edit_elements(p_parent_rid, p_shaped_text, p_min_height, p_insert_pos, false); +} + void DisplayServer::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("file_dialog_show", "title", "current_directory", "filename", "show_hidden", "mode", "filters", "callback"), &DisplayServer::_file_dialog_show_bind_compat_98194); ClassDB::bind_compatibility_method(D_METHOD("file_dialog_with_options_show", "title", "current_directory", "root", "filename", "show_hidden", "mode", "filters", "options", "callback"), &DisplayServer::_file_dialog_with_options_show_bind_compat_98194); + ClassDB::bind_compatibility_method(D_METHOD("accessibility_create_sub_text_edit_elements", "parent_rid", "shaped_text", "min_height", "insert_pos"), &DisplayServer::_accessibility_create_sub_text_edit_elements_bind_compat_113459, DEFVAL(-1)); } #endif diff --git a/servers/display/display_server.cpp b/servers/display/display_server.cpp index 097710d8e3a..cfafce58c6e 100644 --- a/servers/display/display_server.cpp +++ b/servers/display/display_server.cpp @@ -648,9 +648,9 @@ RID DisplayServer::accessibility_create_sub_element(const RID &p_parent_rid, Dis } } -RID DisplayServer::accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos) { +RID DisplayServer::accessibility_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) { if (accessibility_driver) { - return accessibility_driver->accessibility_create_sub_text_edit_elements(p_parent_rid, p_shaped_text, p_min_height, p_insert_pos); + return accessibility_driver->accessibility_create_sub_text_edit_elements(p_parent_rid, p_shaped_text, p_min_height, p_insert_pos, p_is_last_line); } else { return RID(); } @@ -1485,7 +1485,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("accessibility_create_element", "window_id", "role"), &DisplayServer::accessibility_create_element); ClassDB::bind_method(D_METHOD("accessibility_create_sub_element", "parent_rid", "role", "insert_pos"), &DisplayServer::accessibility_create_sub_element, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("accessibility_create_sub_text_edit_elements", "parent_rid", "shaped_text", "min_height", "insert_pos"), &DisplayServer::accessibility_create_sub_text_edit_elements, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("accessibility_create_sub_text_edit_elements", "parent_rid", "shaped_text", "min_height", "insert_pos", "is_last_line"), &DisplayServer::accessibility_create_sub_text_edit_elements, DEFVAL(-1), DEFVAL(false)); ClassDB::bind_method(D_METHOD("accessibility_has_element", "id"), &DisplayServer::accessibility_has_element); ClassDB::bind_method(D_METHOD("accessibility_free_element", "id"), &DisplayServer::accessibility_free_element); ClassDB::bind_method(D_METHOD("accessibility_element_set_meta", "id", "meta"), &DisplayServer::accessibility_element_set_meta); diff --git a/servers/display/display_server.h b/servers/display/display_server.h index 9387e06c421..7f301f65d55 100644 --- a/servers/display/display_server.h +++ b/servers/display/display_server.h @@ -50,6 +50,7 @@ class DisplayServer : public Object { mutable HashMap menu_names; RID _get_rid_from_name(NativeMenu *p_nmenu, const String &p_menu_root) const; + RID _accessibility_create_sub_text_edit_elements_bind_compat_113459(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1); #endif LocalVector additional_outputs; @@ -678,7 +679,7 @@ public: virtual RID accessibility_create_element(WindowID p_window_id, DisplayServer::AccessibilityRole p_role); virtual RID accessibility_create_sub_element(const RID &p_parent_rid, DisplayServer::AccessibilityRole p_role, int p_insert_pos = -1); - virtual RID accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1); + virtual RID accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1, bool p_is_last_line = false); virtual bool accessibility_has_element(const RID &p_id) const; virtual void accessibility_free_element(const RID &p_id); @@ -910,7 +911,7 @@ public: virtual RID accessibility_create_element(DisplayServer::WindowID p_window_id, DisplayServer::AccessibilityRole p_role) = 0; virtual RID accessibility_create_sub_element(const RID &p_parent_rid, DisplayServer::AccessibilityRole p_role, int p_insert_pos = -1) = 0; - virtual RID accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1) = 0; + virtual RID accessibility_create_sub_text_edit_elements(const RID &p_parent_rid, const RID &p_shaped_text, float p_min_height, int p_insert_pos = -1, bool p_is_last_line = false) = 0; virtual bool accessibility_has_element(const RID &p_id) const = 0; virtual void accessibility_free_element(const RID &p_id) = 0;