# UNDF: UNDF-2026-000001208 # UNDF: UNDF-2026-XXXXXXXXX --- a/libview/ev-page-accessible.c +++ b/libview/ev-page-accessible.c @@ -95,6 +95,8 @@ static void ev_page_accessible_get_children (EvPageAccessible *self) { EvView *view; + GHashTable *link_set = NULL; + GHashTable *image_set = NULL; + GHashTable *field_set = NULL; EvMappingList *images; EvMappingList *links; EvMappingList *fields; @@ -121,20 +123,56 @@ ev_page_accessible_get_children (EvPageAccessible *self) children = g_list_concat (children, g_list_copy (ev_mapping_list_get_list (images))); children = g_list_concat (children, g_list_copy (ev_mapping_list_get_list (fields))); + /* Build O(1) pointer-keyed lookup tables so our per-element + * classification below is O(1) rather than O(N) per call. + * Previously ev_mapping_list_find() was called up to 3 times per + * element, each doing a full GList scan: O(N^2) total. + */ + if (links) { + GList *l; + link_set = g_hash_table_new (g_direct_hash, g_direct_equal); + for (l = ev_mapping_list_get_list (links); l; l = l->next) { + EvMapping *m = (EvMapping *)l->data; + g_hash_table_insert (link_set, m->data, m); + } + } + if (images) { + GList *l; + image_set = g_hash_table_new (g_direct_hash, g_direct_equal); + for (l = ev_mapping_list_get_list (images); l; l = l->next) { + EvMapping *m = (EvMapping *)l->data; + g_hash_table_insert (image_set, m->data, m); + } + } + if (fields) { + GList *l; + field_set = g_hash_table_new (g_direct_hash, g_direct_equal); + for (l = ev_mapping_list_get_list (fields); l; l = l->next) { + EvMapping *m = (EvMapping *)l->data; + g_hash_table_insert (field_set, m->data, m); + } + } + children = g_list_sort (children, (GCompareFunc) compare_mappings); self->priv->children = g_ptr_array_new_full (g_list_length (children), (GDestroyNotify) g_object_unref); for (list = children; list && list->data; list = list->next) { EvMapping *mapping = list->data; AtkObject *child = NULL; - if (links && ev_mapping_list_find (links, mapping->data)) { + if (link_set && g_hash_table_lookup (link_set, mapping->data)) { EvLinkAccessible *link = ev_link_accessible_new (self, EV_LINK (mapping->data), &mapping->area); AtkHyperlink *atk_link = atk_hyperlink_impl_get_hyperlink (ATK_HYPERLINK_IMPL (link)); child = atk_hyperlink_get_object (atk_link, 0); - } else if (images && ev_mapping_list_find (images, mapping->data)) + } else if (image_set && g_hash_table_lookup (image_set, mapping->data)) child = ATK_OBJECT (ev_image_accessible_new (self, EV_IMAGE (mapping->data), &mapping->area)); - else if (fields && ev_mapping_list_find (fields, mapping->data)) + else if (field_set && g_hash_table_lookup (field_set, mapping->data)) child = ATK_OBJECT (ev_form_field_accessible_new (self, EV_FORM_FIELD (mapping->data), &mapping->area)); if (child) g_ptr_array_add (self->priv->children, child); } g_list_free (children); + + if (link_set) + g_hash_table_destroy (link_set); + if (image_set) + g_hash_table_destroy (image_set); + if (field_set) + g_hash_table_destroy (field_set); }