+ }
+ return string->str;
+ g_string_free (string, FALSE);
+
+}
+
+
+/*
+ * Note: this routine shouldn't have to do as much as it currently does,
+ * but at the moment it works around a pango?/gail? bug which
+ * causes WORD boundary type queries to return incorrect strings.
+ */
+static char *
+string_strip_newlines (char *s, long offset, long *start_offset, long *end_offset)
+{
+ int i;
+ char *word_start = s;
+ /* FIXME: potential memory leak here */
+ for (i=0; s && s[i]; ++i)
+ {
+ if (s [i] == '\n' && i > (offset - *start_offset) ) {
+ s [i] = '\0';
+ *end_offset = *start_offset + i;
+ return word_start;
+ } else if (s [i] == '\n') {
+ word_start = &s[i + 1];
+ }
+ }
+ return word_start;
+}
+
+static char*
+text_chunk_get_clipped_string (TextChunk *chunk)
+{
+ char *s, *string = "";
+ int i;
+ long start = chunk->start_offset, end = chunk->end_offset;
+ long word_start, word_end, range_end;
+ BoundaryRect start_bounds, end_bounds;
+ gboolean start_inside, end_inside;
+ if (!chunk->text_bounds.isClipped)
+ string = chunk->string;
+ else if (chunk->source) {
+#ifdef CLIP_DEBUG
+ fprintf (stderr, "clipping %s\n", chunk->string);
+#endif
+ /* while words at offset lie within the bounds, add them */
+ do {
+ s = AccessibleText_getTextAtOffset (chunk->source,
+ start,
+ SPI_TEXT_BOUNDARY_WORD_START,
+ &word_start,
+ &word_end);
+ range_end = word_end;
+ s = string_strip_newlines (s, start, &word_start, &word_end);
+ AccessibleText_getCharacterExtents (chunk->source,
+ word_start,
+ &start_bounds.x,
+ &start_bounds.y,
+ &start_bounds.width,
+ &start_bounds.height,
+ SPI_COORD_TYPE_SCREEN);
+ AccessibleText_getCharacterExtents (chunk->source,
+ word_end - 1,
+ &end_bounds.x,
+ &end_bounds.y,
+ &end_bounds.width,
+ &end_bounds.height,
+ SPI_COORD_TYPE_SCREEN);
+ start_inside = BOUNDS_CONTAIN_X_BOUNDS (chunk->text_bounds,
+ start_bounds);
+ end_inside = BOUNDS_CONTAIN_X_BOUNDS (chunk->text_bounds,
+ end_bounds);
+ if (start_inside && end_inside) {
+ /* word is contained in bounds */
+ string = g_strconcat (string, s, NULL);
+ } else if (start_inside || end_inside) {
+ /* one end of word is in */
+ if (word_end > end) word_end = end;
+ s = text_chunk_get_clipped_substring_by_char (
+ chunk,
+ MAX (word_start, chunk->start_offset),
+ MIN (word_end, chunk->end_offset));
+ string = g_strconcat (string, s, NULL);
+ } else {
+ }
+ start = range_end;
+ } while (start < chunk->end_offset);