From: billh Date: Wed, 18 Dec 2002 15:28:41 +0000 (+0000) Subject: Added new, more efficient screen review API to AccessibleText. X-Git-Tag: AT_SPI2_ATK_2_12_0~1287 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git;a=commitdiff_plain;h=d96e0663b52f9cad54bbfe89335e08a7f908d795 Added new, more efficient screen review API to AccessibleText. See bug 100944. git-svn-id: http://svn.gnome.org/svn/at-spi/trunk@390 e2bd861d-eb25-0410-b326-f6ed22b6b98c --- diff --git a/ChangeLog b/ChangeLog index 10f872b..e383dee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,59 @@ +2002-12-17 Bill Haneman * cspi/spi_accessible.c (spi_state_to_corba): rename. diff --git a/NEWS b/NEWS index b73df4d..6e7869b 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,14 @@ (top) in HEAD: +What's new in at-spi-1.1.8: + +* Added getRangeExtents() and getBoundedRanges() API for more + efficient screen review [100944]. + +What's new in at-spi-1.1.7: + +* Added spi_keymask values for Mod4 and Mod5. +* Performance improvements and bugfixes from Michael. What's new in at-spi-1.1.6: diff --git a/configure.in b/configure.in index cc4e46c..2148189 100644 --- a/configure.in +++ b/configure.in @@ -2,9 +2,9 @@ AC_INIT(idl/Accessibility.idl) AT_SPI_MAJOR_VERSION=1 AT_SPI_MINOR_VERSION=1 -AT_SPI_MICRO_VERSION=7 +AT_SPI_MICRO_VERSION=8 AT_SPI_INTERFACE_AGE=0 -AT_SPI_BINARY_AGE=7 +AT_SPI_BINARY_AGE=8 AT_SPI_VERSION="$AT_SPI_MAJOR_VERSION.$AT_SPI_MINOR_VERSION.$AT_SPI_MICRO_VERSION" AM_INIT_AUTOMAKE(at-spi, $AT_SPI_VERSION) AC_SUBST(AT_SPI_MAJOR_VERSION) diff --git a/cspi/spi.h b/cspi/spi.h index 2b3a511..ac93bcf 100644 --- a/cspi/spi.h +++ b/cspi/spi.h @@ -59,6 +59,17 @@ typedef enum } AccessibleTextBoundaryType; /* + * Enumerated type for text bounds clipping types + */ +typedef enum +{ + SPI_TEXT_CLIP_NONE, + SPI_TEXT_CLIP_MIN, + SPI_TEXT_CLIP_MAX, + SPI_TEXT_CLIP_BOTH +} AccessibleTextClipType; + +/* * * Enumerated type for relation types * @@ -138,6 +149,22 @@ typedef enum { /** + * AccessibleTextRange: + * @start: the first nominal character position within the range. + * @end: the first nominal character position following the range. + * @content: The actual text content between @start and @end, as a UTF-8 string. + * + * Structure which encapsulates a text range - must be associated with an + * AccessibleText-implementing object. + **/ +typedef struct _AccessibleTextRange +{ + long int start; + long int end; + char *contents; +} AccessibleTextRange; + +/** * AccessibleKeySet: * @keysyms: * @keycodes: @@ -752,6 +779,29 @@ AccessibleText_getCharacterExtents (AccessibleText *obj, long int *height, AccessibleCoordType type); +void +AccessibleText_getRangeExtents (AccessibleText *obj, + long int startOffset, + long int endOffset, + long int *x, + long int *y, + long int *width, + long int *height, + AccessibleCoordType type); + +AccessibleTextRange ** +AccessibleText_getBoundedRanges (AccessibleText *obj, + long int x, + long int y, + long int width, + long int height, + AccessibleCoordType type, + AccessibleTextClipType clipTypeX, + AccessibleTextClipType clipTypeY); + +void +AccessibleTextRange_freeRanges (AccessibleTextRange **ranges); + long AccessibleText_getOffsetAtPoint (AccessibleText *obj, long int x, diff --git a/cspi/spi_text.c b/cspi/spi_text.c index e1b57ad..7579bd0 100644 --- a/cspi/spi_text.c +++ b/cspi/spi_text.c @@ -62,6 +62,50 @@ get_accessible_text_boundary_type (AccessibleTextBoundaryType type) return Accessibility_TEXT_BOUNDARY_CHAR; } +static Accessibility_TEXT_CLIP_TYPE +get_accessible_text_clip_type (AccessibleTextClipType type) +{ + switch (type) + { + case SPI_TEXT_CLIP_NONE: + return Accessibility_TEXT_CLIP_NONE; + break; + case SPI_TEXT_CLIP_MIN: + return Accessibility_TEXT_CLIP_MIN; + break; + case SPI_TEXT_CLIP_MAX: + return Accessibility_TEXT_CLIP_MAX; + break; + } + return Accessibility_TEXT_CLIP_BOTH; +} + +static AccessibleTextRange ** +get_accessible_text_ranges_from_range_seq (Accessibility_Text_RangeList *range_seq) +{ + AccessibleTextRange **ranges = NULL; + AccessibleTextRange *array = NULL; + int i; + if (range_seq && range_seq->_length > 0) + { + ranges = g_new0 (AccessibleTextRange *, range_seq->_length + 1); + } + array = g_new0 (AccessibleTextRange, range_seq->_length); + for (i = 0; i < range_seq->_length; i++) + { + AccessibleTextRange *range; + range = &array[i]; + range->start = range_seq->_buffer[i].startOffset; + range->end = range_seq->_buffer[i].endOffset; + range->contents = CORBA_string_dup (range_seq->_buffer[i].content); + ranges[i] = range; + } + ranges[i] = NULL; /* null-terminated list! */ + CORBA_free (range_seq); + + return ranges; +} + /** * AccessibleText_ref: @@ -539,6 +583,135 @@ AccessibleText_getOffsetAtPoint (AccessibleText *obj, } /** + * AccessibleText_getRangeExtents: + * @obj: a pointer to the #AccessibleText object on which to operate. + * @startOffset: an integer indicating the offset of the first text character for + * whom boundary information is requested. + * @endOffset: an integer indicating the offset of the text character + * after the last character for whom boundary information is requested. + * @x: a pointer to a long integer into which the nominal x coordinate + * of the corresponding bounding box will be returned. + * @y:a pointer to a long integer into which the nominal y coordinate + * of the corresponding bounding box will be returned. + * @width:a pointer to a long integer into which the width + * of the corresponding bounding box will be returned. + * @height: a pointer to a long integer into which the height + * of the corresponding bounding box will be returned. + * @type: an #AccessibleCoordType indicating the coordinate system to use + * for the returned values. + * + * Get the bounding box for text within a range in an #AccessibleText object. + * + * Returns: the bounding-box extents of the specified text range, + * in the specified coordinate system. + * + **/ +void +AccessibleText_getRangeExtents (AccessibleText *obj, + long int startOffset, + long int endOffset, + long int *x, + long int *y, + long int *width, + long int *height, + AccessibleCoordType type) +{ + CORBA_long retX, retY, retWidth, retHeight; + + if (obj == NULL) + { + *x = *y = -1; + *width = *height = -1; + return; + } + + Accessibility_Text_getRangeExtents (CSPI_OBJREF (obj), + startOffset, + endOffset, + &retX, + &retY, + &retWidth, + &retHeight, + type, cspi_ev ()); + + if (!cspi_check_ev ("getRangeExtents")) + { + *x = *y = -1; + *width = *height = -1; + } + else + { + *x = retX; + *y = retY; + *width = retWidth; + *height = retHeight; + } +} + +/** + * AccessibleText_getBoundedRanges: + * @obj: a pointer to the #AccessibleText object on which to operate. + * @x: the 'starting' x coordinate of the bounding box. + * @y: the 'starting' y coordinate of the bounding box. + * @width: the x extent of the bounding box. + * @height: the y extent of the bounding box. + * @type: an #AccessibleCoordType indicating the coordinate system to use + * for the returned values. + * @clipTypeX: an #AccessibleTextClipType indicating how to treat characters that + * intersect the bounding box's x extents. + * @clipTypeY: an #AccessibleTextClipType indicating how to treat characters that + * intersect the bounding box's y extents. + * + * Get the ranges of text from an #AccessibleText object which lie within the + * bounds defined by (@x, @y) and (@x+@width, @y+@height). + * + * Returns: a null-terminated list of pointers to AccessibleTextRange structs + * detailing the bounded text. + **/ +AccessibleTextRange ** +AccessibleText_getBoundedRanges (AccessibleText *obj, + long int x, + long int y, + long int width, + long int height, + AccessibleCoordType type, + AccessibleTextClipType clipTypeX, + AccessibleTextClipType clipTypeY) +{ + Accessibility_Text_RangeList *range_seq; + + cspi_return_val_if_fail (obj != NULL, NULL); + + range_seq = + Accessibility_Text_getBoundedRanges (CSPI_OBJREF (obj), + x, y, width, height, + type, + get_accessible_text_clip_type (clipTypeX), + get_accessible_text_clip_type (clipTypeY), + cspi_ev ()); + + cspi_return_val_if_ev ("getBoundedRanges", NULL); + + return get_accessible_text_ranges_from_range_seq (range_seq); +} + +/** + * AccessibleTextRange_freeRanges: + * @ranges: a pointer to an array of AccessibleTextRange structs. + * + * Free the memory used by a list of AccessibleTextRange structs. + * The argument passed in should be an array of pointers + * AccessibleTextRange structs. + **/ +void +AccessibleTextRange_freeRanges (AccessibleTextRange **ranges) +{ + /* this was a contiguously allocated block, only free the first element */ + g_free (ranges[0]); + g_free (ranges); +} + +/** * AccessibleText_getNSelections: * @obj: a pointer to the #AccessibleText object on which to operate. * diff --git a/idl/Accessibility_Text.idl b/idl/Accessibility_Text.idl index 268eb35..49fe577 100644 --- a/idl/Accessibility_Text.idl +++ b/idl/Accessibility_Text.idl @@ -32,7 +32,31 @@ module Accessibility { TEXT_BOUNDARY_LINE_END }; + /** + * TEXT_CLIP_TYPE: + * CLIP_MIN means text clipped by min coordinate is omitted, + * CLIP_MAX clips text interescted by the max coord, and CLIP_BOTH + * will retain only text falling fully within the min/max bounds. + * + **/ + enum TEXT_CLIP_TYPE { + TEXT_CLIP_NONE, + TEXT_CLIP_MIN, + TEXT_CLIP_MAX, + TEXT_CLIP_BOTH + }; + interface Text : Bonobo::Unknown { + + struct Range { + long startOffset; + long endOffset; + string content; + any data; + }; + + typedef sequence RangeList; + readonly attribute long characterCount; readonly attribute long caretOffset; string getText (in long startOffset, in long endOffset); @@ -48,13 +72,21 @@ module Accessibility { */ string getAttributes (in long offset, out long startOffset, out long endOffset); - void getCharacterExtents (in long offset, out long x, out long y, out long length, out long width, in short coordType); + void getCharacterExtents (in long offset, out long x, out long y, out long width, out long height, in short coordType); long getOffsetAtPoint (in long x, in long y, in short coordType); long getNSelections (); void getSelection (in long selectionNum, out long startOffset, out long endOffset); boolean addSelection (in long startOffset, in long endOffset); boolean removeSelection (in long selectionNum); boolean setSelection (in long selectionNum, in long startOffset, in long endOffset); + void getRangeExtents (in long startOffset, in long endOffset, + out long x, out long y, + out long width, out long height, in short coordType); + RangeList getBoundedRanges (in long x, in long y, + in long width, in long height, + in short coordType, + in TEXT_CLIP_TYPE xClipType, + in TEXT_CLIP_TYPE yClipType); /** * unImplemented: * @@ -64,7 +96,5 @@ module Accessibility { void unImplemented2 (); void unImplemented3 (); void unImplemented4 (); - void unImplemented7 (); - void unImplemented8 (); }; }; diff --git a/libspi/text.c b/libspi/text.c index 8aa5764..c8e6d1c 100644 --- a/libspi/text.c +++ b/libspi/text.c @@ -32,6 +32,63 @@ /* Our parent Gtk object type */ #define PARENT_TYPE SPI_TYPE_BASE +typedef struct { + gint x; + gint y; + gint w; + gint h; +} SpiTextRect; + +static SpiTextRect * +_spi_text_rect_union (SpiTextRect *aggregate, SpiTextRect *subrect) +{ + if (subrect != NULL) + { + /* 'normalize' subrect */ + if (subrect->w < 0) + { + subrect->x += subrect->w; + subrect->w *= -1; + } + if (subrect->h < 0) + { + subrect->y += subrect->h; + subrect->h *= -1; + } + if (aggregate == NULL) + { + aggregate = g_new (SpiTextRect, 1); + memcpy (aggregate, subrect, sizeof (SpiTextRect)); + } + else + { + gint ax2 = aggregate->x + aggregate->w; + gint ay2 = aggregate->y + aggregate->h; + gint sx2 = subrect->x + subrect->w; + gint sy2 = subrect->y + subrect->h; + if (subrect->x < aggregate->x) + { + aggregate->w += (aggregate->x - subrect->x); + aggregate->x = subrect->x; + } + if (sx2 > ax2) + { + aggregate->w += (sx2 - ax2); + } + if (subrect->y < aggregate->y) + { + aggregate->h += (aggregate->y - subrect->y); + aggregate->y = subrect->y; + } + if (sy2 > ay2) + { + aggregate->h += (sy2 - ay2); + } + } + } + return aggregate; +} + static AtkText * get_text_from_servant (PortableServer_Servant servant) { @@ -390,6 +447,165 @@ impl_setCaretOffset (PortableServer_Servant servant, return atk_text_set_caret_offset (text, value); } +#define SPI_TEXT_MIN_RANGE_FOR_LINE_CHECK 6 + +static void +impl_getRangeExtents(PortableServer_Servant servant, + const CORBA_long startOffset, + const CORBA_long endOffset, + CORBA_long * x, CORBA_long * y, + CORBA_long * width, + CORBA_long * height, + const CORBA_short coordType, + CORBA_Environment * ev) +{ + AtkText *text = get_text_from_servant (servant); + SpiTextRect cbounds, bounds; + int i; + + g_return_if_fail (text != NULL); + + /* no equivalent ATK API yet, must do the hard way. :-( */ + for (i = startOffset; i > endOffset; i++) + { + atk_text_get_character_extents (text, i, + &cbounds.x, &cbounds.y, &cbounds.w, &cbounds.h, + (AtkCoordType) coordType); + _spi_text_rect_union (&bounds, &cbounds); + } + + *x = bounds.x; + *y = bounds.y; + *width = bounds.w; + *height = bounds.h; +} + +static Accessibility_Text_RangeList * +_spi_text_range_seq_from_gslist (GSList *range_list) +{ + Accessibility_Text_RangeList *rangeList = + Accessibility_Text_RangeList__alloc (); + int i, len = g_slist_length (range_list); + GSList *list = range_list; + + rangeList->_length = len; + rangeList->_buffer = Accessibility_Text_RangeList_allocbuf (len); + for (i = 0; i < len; ++i) + { + memcpy (&rangeList->_buffer[i], list->data, sizeof (Accessibility_Text_Range)); + spi_init_any_nil (&rangeList->_buffer[i].data); + g_free (list->data); + list = g_slist_next (range_list); + } + g_slist_free (range_list); + + return rangeList; +} + +static gboolean +_spi_bounds_contain (SpiTextRect *clip, SpiTextRect *cbounds, + Accessibility_TEXT_CLIP_TYPE xClipType, + Accessibility_TEXT_CLIP_TYPE yClipType) +{ + gint clipx2 = clip->x + clip->w; + gint clipy2 = clip->y + clip->h; + gint charx2 = cbounds->x + cbounds->w; + gint chary2 = cbounds->y + cbounds->h; + gboolean x_min_ok, y_min_ok, x_max_ok, y_max_ok; + + x_min_ok = (cbounds->x >= clip->x) || + ((charx2 >= clip->x) && + ((xClipType == Accessibility_TEXT_CLIP_NONE) || + (xClipType == Accessibility_TEXT_CLIP_MAX))); + x_max_ok = (charx2 <= clipx2) || + ((cbounds->x <= clipx2) && + ((xClipType == Accessibility_TEXT_CLIP_NONE) || + (xClipType == Accessibility_TEXT_CLIP_MIN))); + y_min_ok = (cbounds->y >= clip->y) || + ((chary2 >= clip->y) && + ((yClipType == Accessibility_TEXT_CLIP_NONE) || + (yClipType == Accessibility_TEXT_CLIP_MAX))); + y_max_ok = (chary2 <= clipy2) || + ((cbounds->y <= clipy2) && + ((yClipType == Accessibility_TEXT_CLIP_NONE) || + (yClipType == Accessibility_TEXT_CLIP_MIN))); + + if (x_min_ok && y_min_ok && x_max_ok && y_max_ok) + return TRUE; + else + return FALSE; +} + +Accessibility_Text_RangeList * +impl_getBoundedRanges(PortableServer_Servant servant, + const CORBA_long x, + const CORBA_long y, + const CORBA_long width, + const CORBA_long height, + const CORBA_short coordType, + const Accessibility_TEXT_CLIP_TYPE xClipType, + const Accessibility_TEXT_CLIP_TYPE yClipType, + CORBA_Environment * ev) +{ + AtkText *text = get_text_from_servant (servant); + GSList *range_list = NULL; + SpiTextRect clip; + int startOffset = 0, endOffset = atk_text_get_character_count (text); + int curr_offset; + gint minLineStart, minLineEnd, maxLineStart, maxLineEnd; + long bounds_min_offset; + + clip.x = x; + clip.y = y; + clip.w = width; + clip.h = height; + + /* for horizontal text layouts, at least, the following check helps. */ + bounds_min_offset = atk_text_get_offset_at_point (text, x, y, + (AtkCoordType) coordType); + atk_text_get_text_at_offset (text, bounds_min_offset, + ATK_TEXT_BOUNDARY_LINE_START, + &minLineStart, &minLineEnd); + atk_text_get_text_at_offset (text, bounds_min_offset, + ATK_TEXT_BOUNDARY_LINE_START, + &maxLineStart, &maxLineEnd); + startOffset = MIN (minLineStart, maxLineStart); + endOffset = MIN (minLineEnd, maxLineEnd); + + curr_offset = startOffset; + + while (curr_offset < endOffset) + { + int offset = startOffset; + SpiTextRect cbounds; + while (curr_offset < endOffset) + { + atk_text_get_character_extents (text, curr_offset, + &cbounds.x, &cbounds.y, + &cbounds.w, &cbounds.h, + (AtkCoordType) coordType); + if (!_spi_bounds_contain (&clip, &cbounds, xClipType, yClipType)) + break; + curr_offset++; + } + /* add the range to our list */ + if (curr_offset > offset) + { + Accessibility_Text_Range *range = g_malloc (sizeof (Accessibility_Text_Range)); + char *s; + range->startOffset = offset; + range->endOffset = curr_offset; + s = atk_text_get_text (text, offset, curr_offset); + range->content = CORBA_string_dup (s ? s : ""); + range_list = g_slist_append (range_list, range); + offset = curr_offset; + } + offset++; + } + return _spi_text_range_seq_from_gslist (range_list); /* frees the GSList too */ +} + + static void spi_text_class_init (SpiTextClass *klass) { @@ -413,6 +629,8 @@ spi_text_class_init (SpiTextClass *klass) epv->removeSelection = impl_removeSelection; epv->setSelection = impl_setSelection; epv->setCaretOffset = impl_setCaretOffset; + epv->getRangeExtents = impl_getRangeExtents; + epv->getBoundedRanges = impl_getBoundedRanges; } static void diff --git a/registryd/deviceeventcontroller.c b/registryd/deviceeventcontroller.c index c51fff3..f872562 100644 --- a/registryd/deviceeventcontroller.c +++ b/registryd/deviceeventcontroller.c @@ -190,8 +190,6 @@ spi_dec_set_unlatch_pending (SpiDEController *controller, unsigned mask) priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask; } -static gint poll_count = 0; - static gboolean spi_dec_button_update_and_emit (SpiDEController *controller, guint mask_return) @@ -327,7 +325,6 @@ spi_dec_mouse_check (SpiDEController *controller, Accessibility_Event e; CORBA_Environment ev; int win_x_return,win_y_return; - int poll_count_modulus = 10; unsigned int mask_return; Window root_return, child_return; Display *display = spi_get_display (); @@ -349,20 +346,17 @@ spi_dec_mouse_check (SpiDEController *controller, while (spi_dec_button_update_and_emit (controller, mask_return)); } - if (poll_count++ == poll_count_modulus) { - poll_count = 0; - e.type = "mouse:abs"; - e.source = BONOBO_OBJREF (controller->registry->desktop); - e.detail1 = *x; - e.detail2 = *y; - spi_init_any_nil (&e.any_data); - CORBA_exception_init (&ev); - Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), - &e, - &ev); - } if (*x != last_mouse_pos->x || *y != last_mouse_pos->y) { + e.type = "mouse:abs"; + e.source = BONOBO_OBJREF (controller->registry->desktop); + e.detail1 = *x; + e.detail2 = *y; + spi_init_any_nil (&e.any_data); + CORBA_exception_init (&ev); + Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry), + &e, + &ev); e.type = "mouse:rel"; e.source = BONOBO_OBJREF (controller->registry->desktop); e.detail1 = *x - last_mouse_pos->x;