+
+/*
+ * Note: this routine shouldn't have to do as much as it currently does,
+ * but at the moment it works around another bug (probably one in this
+ * code).
+ */
+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 *
+string_guess_clip (TextChunk *chunk)
+{
+ BoundaryRect b;
+ char *s = NULL, *sp = chunk->string, *ep;
+ long start_offset, end_offset, len;
+ if (sp) {
+ AccessibleComponent *component =
+ Accessible_getComponent (chunk->source);
+ ep = sp + (strlen (sp));
+ len = g_utf8_strlen (chunk->string, -1);
+ if (component) {
+ AccessibleComponent_getExtents (component,
+ &b.x, &b.y,
+ &b.width, &b.height,
+ SPI_COORD_TYPE_SCREEN);
+ start_offset = len * (chunk->text_bounds.x - b.x) / b.width;
+ end_offset = len * (chunk->text_bounds.x +
+ chunk->text_bounds.width - b.x) / b.width;
+ fprintf (stderr, "String len %d, clipped to %d-%d\n",
+ len, start_offset, end_offset);
+ len = end_offset - start_offset;
+ sp = g_utf8_offset_to_pointer (chunk->string, start_offset);
+ ep = g_utf8_offset_to_pointer (chunk->string, end_offset);
+ }
+ s = g_new0 (char, ep - sp + 1);
+ s = g_utf8_strncpy (s, sp, len);
+ s [sp - ep] = '\0';
+ g_assert (g_utf8_validate (s, -1, NULL));
+ }
+ return s;
+}
+
+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 || !chunk->string)
+ string = chunk->string;
+ else if (chunk->source && Accessible_isText (chunk->source)) {
+ /* while words at offset lie within the bounds, add them */
+ AccessibleText *text = Accessible_getText (chunk->source);
+#ifdef CLIP_DEBUG
+ fprintf (stderr, "clipping %s\n", chunk->string);
+#endif
+ do {
+ s = AccessibleText_getTextAtOffset (text,
+ start,
+ SPI_TEXT_BOUNDARY_WORD_END,
+ &word_start,
+ &word_end);
+ range_end = word_end;
+ s = string_strip_newlines (s, start, &word_start, &word_end);
+ AccessibleText_getCharacterExtents (text,
+ word_start,
+ &start_bounds.x,
+ &start_bounds.y,
+ &start_bounds.width,
+ &start_bounds.height,
+ SPI_COORD_TYPE_SCREEN);
+ AccessibleText_getCharacterExtents (text,
+ 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);
+ } else { /* we're clipped, but don't implement AccessibleText :-( */
+ /* guess for now, maybe we can do better someday */
+ string = string_guess_clip (chunk);
+ }
+ return string;
+}
+
+
+static char*
+text_chunk_pad_string (TextChunk *chunk, char *string, glong offset, const char *pad_chars)
+{
+ char *s = "";
+ char *cp;
+ char startbuf[6], padbuf[6], endbuf[6];
+ int pixels_per_column = 6;
+ /* this is an arbitrary pixel-to-textcolumn mapping at present */
+ glong end_padding;
+ gint howmany;
+ howmany = g_unichar_to_utf8 (g_utf8_get_char (pad_chars), startbuf);
+ startbuf[howmany] = '\0';
+ g_assert (howmany < 7 && howmany > 0);
+ cp = g_utf8_find_next_char (pad_chars, NULL);
+ howmany = g_unichar_to_utf8 (g_utf8_get_char (cp), padbuf);
+ padbuf[howmany] = '\0';
+ g_assert (howmany < 7 && howmany > 0);
+ cp = g_utf8_find_next_char (cp, NULL);
+ howmany = g_unichar_to_utf8 (g_utf8_get_char (cp), endbuf);
+ endbuf[howmany] = '\0';
+ g_assert (howmany < 7 && howmany > 0);
+ end_padding = chunk->clip_bounds.x / pixels_per_column;
+ while (offset < end_padding - 1) {
+ s = g_strconcat (s, padbuf, NULL); /* could be more efficient */
+ ++offset;
+ }
+ s = g_strconcat (s, startbuf, string, NULL);
+ offset += g_utf8_strlen (string, -1) + 1;
+ end_padding = chunk->text_bounds.x / pixels_per_column;
+ while (offset < end_padding) {
+ s = g_strconcat (s, padbuf, NULL); /* could be more efficient */
+ ++offset;
+ }
+ end_padding = (chunk->clip_bounds.x + chunk->clip_bounds.width) /
+ pixels_per_column;
+ while (offset < end_padding - 1) {
+ s = g_strconcat (s, padbuf, NULL); /* could be more efficient */
+ ++offset;
+ }
+ s = g_strconcat (s, endbuf, NULL);
+ return s;
+}
+
+static char*
+text_chunk_to_string (TextChunk *chunk, glong offset)
+{
+ char *s = NULL;
+ if (chunk->string) {
+ s = text_chunk_get_clipped_string (chunk);
+ if (chunk->clip_bounds.role == SPI_ROLE_PUSH_BUTTON) {
+ s = text_chunk_pad_string (chunk, s, offset, "[ ]");
+ } else if (chunk->clip_bounds.role == SPI_ROLE_FRAME) {
+ s = text_chunk_pad_string (chunk, s, offset, "| |");
+ } else if (chunk->clip_bounds.role == SPI_ROLE_TEXT) {
+ s = text_chunk_pad_string (chunk, s, offset, "\" \"");
+ } else {
+ s = text_chunk_pad_string (chunk, s, offset, " ");
+ }
+ }
+ return s;
+}
+