Merge branch 'a11y-text-work2' into 'main'

a11y: Add gtk_accessible_text_get_extents

See merge request GNOME/gtk!7006
This commit is contained in:
Matthias Clasen 2024-04-03 22:55:30 +00:00
commit bacdc735a4
8 changed files with 280 additions and 2 deletions

View File

@ -330,11 +330,85 @@ accessible_text_handle_method (GDBusConnection *connection,
} }
else if (g_strcmp0 (method_name, "GetCharacterExtents") == 0) else if (g_strcmp0 (method_name, "GetCharacterExtents") == 0)
{ {
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); int offset;
unsigned int coords_type;
graphene_rect_t extents;
graphene_point_t point;
int x, y, w, h;
GtkNative *native;
double nx, ny;
g_variant_get (parameters, "(iu)", &offset, &coords_type);
if (coords_type != ATSPI_COORD_TYPE_WINDOW)
{
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_NOT_SUPPORTED,
"Unsupported coordinate space");
return;
}
native = gtk_widget_get_native (GTK_WIDGET (accessible));
gtk_native_get_surface_transform (native, &nx, &ny);
if (!gtk_accessible_text_get_extents (accessible_text, offset, offset + 1, &extents) ||
!gtk_widget_compute_point (GTK_WIDGET (accessible), GTK_WIDGET (native), &extents.origin, &point))
{
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Failed to get extents");
return;
}
x = floor (point.x + nx);
y = floor (point.y + ny);
w = ceilf (extents.size.width) - x;
h = ceilf (extents.size.height) - y;
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(iiii)", x, y, w, h));
} }
else if (g_strcmp0 (method_name, "GetRangeExtents") == 0) else if (g_strcmp0 (method_name, "GetRangeExtents") == 0)
{ {
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); int start, end;
guint coords_type;
graphene_rect_t extents;
graphene_point_t point;
int x, y, w, h;
GtkNative *native;
double nx, ny;
g_variant_get (parameters, "(iiu)", &start, &end, &coords_type);
if (coords_type != ATSPI_COORD_TYPE_WINDOW)
{
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_NOT_SUPPORTED,
"Unsupported coordinate space");
return;
}
native = gtk_widget_get_native (GTK_WIDGET (accessible));
gtk_native_get_surface_transform (native, &nx, &ny);
if (!gtk_accessible_text_get_extents (accessible_text, start, end, &extents) ||
!gtk_widget_compute_point (GTK_WIDGET (accessible), GTK_WIDGET (native), &extents.origin, &point))
{
g_dbus_method_invocation_return_error_literal (invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Failed to get extents");
return;
}
x = floor (point.x + nx);
y = floor (point.y + ny);
w = ceilf (extents.size.width) - x;
h = ceilf (extents.size.height) - y;
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(iiii)", x, y, w, h));
} }
else if (g_strcmp0 (method_name, "GetBoundedRanges") == 0) else if (g_strcmp0 (method_name, "GetBoundedRanges") == 0)
{ {

View File

@ -426,6 +426,35 @@ gtk_accessible_text_get_attributes_run (GtkAccessibleText *self,
return TRUE; return TRUE;
} }
/*< private >
* gtk_accessible_text_get_extents:
* @self: a `GtkAccessibleText`
* @start: start offset, in characters
* @end: end offset, in characters
* @extents: (out caller-allocates): return location for the extents
*
* Obtains the extents of a range of text, in widget coordinates.
*
* Returns: true if the extents were filled in, false otherwise
*
* Since: 4.16
*/
gboolean
gtk_accessible_text_get_extents (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents)
{
g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), FALSE);
g_return_val_if_fail (start <= end, FALSE);
g_return_val_if_fail (extents != NULL, FALSE);
if (GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_extents != NULL)
return GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_extents (self, start, end, extents);
return FALSE;
}
/** /**
* gtk_accessible_text_update_caret_position: * gtk_accessible_text_update_caret_position:
* @self: the accessible object * @self: the accessible object

View File

@ -11,6 +11,7 @@
#endif #endif
#include <gtk/gtkaccessible.h> #include <gtk/gtkaccessible.h>
#include <graphene.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -255,6 +256,24 @@ struct _GtkAccessibleTextInterface
void (* get_default_attributes) (GtkAccessibleText *self, void (* get_default_attributes) (GtkAccessibleText *self,
char ***attribute_names, char ***attribute_names,
char ***attribute_values); char ***attribute_values);
/**
* GtkAccessibleTextInterface::get_extents:
* @self: the accessible object
* @start: the start offset, in characters
* @end: the end offset, in characters,
* @extents (out caller-allocates): return location for the extents
*
* Obtains the extents of a range of text, in widget coordinates.
*
* Returns: true if the extents were filled in, false otherwise
*
* Since: 4.16
*/
gboolean (* get_extents) (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents);
}; };
GDK_AVAILABLE_IN_4_14 GDK_AVAILABLE_IN_4_14

View File

@ -52,4 +52,10 @@ gtk_accessible_text_get_attributes_run (GtkAccessibleText *self,
char ***attribute_names, char ***attribute_names,
char ***attribute_values); char ***attribute_values);
gboolean
gtk_accessible_text_get_extents (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents);
G_END_DECLS G_END_DECLS

View File

@ -1435,6 +1435,39 @@ gtk_inscription_accessible_text_get_default_attributes (GtkAccessibleText *sel
*attribute_values = values; *attribute_values = values;
} }
static gboolean
gtk_inscription_accessible_text_get_extents (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents)
{
GtkInscription *inscription = GTK_INSCRIPTION (self);
PangoLayout *layout;
const char *text;
float lx, ly;
cairo_region_t *range_clip;
cairo_rectangle_int_t clip_rect;
int range[2];
layout = inscription->layout;
text = inscription->text;
gtk_inscription_get_layout_location (inscription, &lx, &ly);
range[0] = g_utf8_pointer_to_offset (text, text + start);
range[1] = g_utf8_pointer_to_offset (text, text + end);
range_clip = gdk_pango_layout_get_clip_region (layout, lx, ly, range, 1);
cairo_region_get_extents (range_clip, &clip_rect);
cairo_region_destroy (range_clip);
extents->origin.x = clip_rect.x;
extents->origin.y = clip_rect.y;
extents->size.width = clip_rect.width;
extents->size.height = clip_rect.height;
return TRUE;
}
static void static void
gtk_inscription_accessible_text_init (GtkAccessibleTextInterface *iface) gtk_inscription_accessible_text_init (GtkAccessibleTextInterface *iface)
{ {
@ -1444,6 +1477,7 @@ gtk_inscription_accessible_text_init (GtkAccessibleTextInterface *iface)
iface->get_selection = gtk_inscription_accessible_text_get_selection; iface->get_selection = gtk_inscription_accessible_text_get_selection;
iface->get_attributes = gtk_inscription_accessible_text_get_attributes; iface->get_attributes = gtk_inscription_accessible_text_get_attributes;
iface->get_default_attributes = gtk_inscription_accessible_text_get_default_attributes; iface->get_default_attributes = gtk_inscription_accessible_text_get_default_attributes;
iface->get_extents = gtk_inscription_accessible_text_get_extents;
} }
/* }}} */ /* }}} */

View File

@ -6179,6 +6179,39 @@ gtk_label_accessible_text_get_attributes (GtkAccessibleText *self,
return TRUE; return TRUE;
} }
static gboolean
gtk_label_accessible_text_get_extents (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents)
{
GtkLabel *label = GTK_LABEL (self);
PangoLayout *layout;
const char *text;
float lx, ly;
cairo_region_t *range_clip;
cairo_rectangle_int_t clip_rect;
int range[2];
layout = label->layout;
text = label->text;
get_layout_location (label, &lx, &ly);
range[0] = g_utf8_pointer_to_offset (text, text + start);
range[1] = g_utf8_pointer_to_offset (text, text + end);
range_clip = gdk_pango_layout_get_clip_region (layout, lx, ly, range, 1);
cairo_region_get_extents (range_clip, &clip_rect);
cairo_region_destroy (range_clip);
extents->origin.x = clip_rect.x;
extents->origin.y = clip_rect.y;
extents->size.width = clip_rect.width;
extents->size.height = clip_rect.height;
return TRUE;
}
static void static void
gtk_label_accessible_text_init (GtkAccessibleTextInterface *iface) gtk_label_accessible_text_init (GtkAccessibleTextInterface *iface)
{ {
@ -6188,6 +6221,7 @@ gtk_label_accessible_text_init (GtkAccessibleTextInterface *iface)
iface->get_selection = gtk_label_accessible_text_get_selection; iface->get_selection = gtk_label_accessible_text_get_selection;
iface->get_attributes = gtk_label_accessible_text_get_attributes; iface->get_attributes = gtk_label_accessible_text_get_attributes;
iface->get_default_attributes = gtk_label_accessible_text_get_default_attributes; iface->get_default_attributes = gtk_label_accessible_text_get_default_attributes;
iface->get_extents = gtk_label_accessible_text_get_extents;
} }
/* }}} */ /* }}} */

View File

@ -7555,6 +7555,38 @@ gtk_text_accessible_text_get_default_attributes (GtkAccessibleText *self,
*attribute_values = values; *attribute_values = values;
} }
static gboolean
gtk_text_accessible_text_get_extents (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents)
{
PangoLayout *layout = gtk_text_get_layout (GTK_TEXT (self));
const char *text;
int lx, ly;
int range[2];
cairo_region_t *range_clip;
cairo_rectangle_int_t clip_rect;
layout = gtk_text_get_layout (GTK_TEXT (self));
text = gtk_entry_buffer_get_text (get_buffer (GTK_TEXT (self)));
get_layout_position (GTK_TEXT (self), &lx, &ly);
range[0] = g_utf8_pointer_to_offset (text, text + start);
range[1] = g_utf8_pointer_to_offset (text, text + end);
range_clip = gdk_pango_layout_get_clip_region (layout, lx, ly, range, 1);
cairo_region_get_extents (range_clip, &clip_rect);
cairo_region_destroy (range_clip);
extents->origin.x = clip_rect.x;
extents->origin.y = clip_rect.y;
extents->size.width = clip_rect.width;
extents->size.height = clip_rect.height;
return TRUE;
}
static void static void
gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface) gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface)
{ {
@ -7564,6 +7596,7 @@ gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface)
iface->get_selection = gtk_text_accessible_text_get_selection; iface->get_selection = gtk_text_accessible_text_get_selection;
iface->get_attributes = gtk_text_accessible_text_get_attributes; iface->get_attributes = gtk_text_accessible_text_get_attributes;
iface->get_default_attributes = gtk_text_accessible_text_get_default_attributes; iface->get_default_attributes = gtk_text_accessible_text_get_default_attributes;
iface->get_extents = gtk_text_accessible_text_get_extents;
} }
/* vim:set foldmethod=marker expandtab: */ /* vim:set foldmethod=marker expandtab: */

View File

@ -10685,6 +10685,54 @@ gtk_text_view_accessible_text_get_default_attributes (GtkAccessibleText *self,
g_hash_table_unref (attrs); g_hash_table_unref (attrs);
} }
static gboolean
gtk_text_view_accessible_text_get_extents (GtkAccessibleText *self,
unsigned int start,
unsigned int end,
graphene_rect_t *extents)
{
GtkTextBuffer *buffer;
GtkTextIter start_iter, end_iter;
cairo_region_t *region;
GdkRectangle rect;
buffer = get_buffer (GTK_TEXT_VIEW (self));
gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
region = cairo_region_create ();
do
{
gtk_text_view_get_iter_location (GTK_TEXT_VIEW (self), &start_iter, &rect);
cairo_region_union_rectangle (region, &rect);
gtk_text_iter_forward_to_line_end (&start_iter);
gtk_text_iter_order (&start_iter, &end_iter);
gtk_text_view_get_iter_location (GTK_TEXT_VIEW (self), &end_iter, &rect);
cairo_region_union_rectangle (region, &rect);
gtk_text_iter_forward_line (&start_iter);
}
while (gtk_text_iter_compare (&start_iter, &end_iter) < 0);
cairo_region_get_extents (region, &rect);
cairo_region_destroy (region);
gtk_text_view_buffer_to_window_coords (GTK_TEXT_VIEW (self),
GTK_TEXT_WINDOW_TEXT,
rect.x, rect.y,
&rect.x, &rect.y);
_text_window_to_widget_coords (GTK_TEXT_VIEW (self), &rect.x, &rect.y);
extents->origin.x = rect.x;
extents->origin.y = rect.y;
extents->size.width = rect.width;
extents->size.height = rect.height;
return TRUE;
}
static void static void
gtk_text_view_accessible_text_init (GtkAccessibleTextInterface *iface) gtk_text_view_accessible_text_init (GtkAccessibleTextInterface *iface)
{ {
@ -10694,6 +10742,7 @@ gtk_text_view_accessible_text_init (GtkAccessibleTextInterface *iface)
iface->get_selection = gtk_text_view_accessible_text_get_selection; iface->get_selection = gtk_text_view_accessible_text_get_selection;
iface->get_attributes = gtk_text_view_accessible_text_get_attributes; iface->get_attributes = gtk_text_view_accessible_text_get_attributes;
iface->get_default_attributes = gtk_text_view_accessible_text_get_default_attributes; iface->get_default_attributes = gtk_text_view_accessible_text_get_default_attributes;
iface->get_extents = gtk_text_view_accessible_text_get_extents;
} }
/* }}} */ /* }}} */