diff options
Diffstat (limited to 'widgets/text')
-rw-r--r-- | widgets/text/e-text.c | 264 |
1 files changed, 95 insertions, 169 deletions
diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c index 4fc8437732..349b2d40b8 100644 --- a/widgets/text/e-text.c +++ b/widgets/text/e-text.c @@ -950,200 +950,126 @@ text_draw_with_objects (ETextModel *model, } } -#define IS_BREAKCHAR(text,c) ((text)->break_characters && g_utf8_strchr ((text)->break_characters, (c))) -/* Splits the text of the text item into lines */ -static void -split_into_lines (EText *text) +typedef void (*LineSplitterFn) (int line_num, const char *start, int length, gpointer user_data); + +#define IS_BREAK_CHAR(break_chars, c) (g_unichar_isspace (c) || ((break_chars) && g_utf8_strchr ((break_chars), (c)))) + +static gint +line_splitter (ETextModel *model, EFont *font, EFontStyle style, + const char *break_characters, + gboolean wrap_lines, double clip_width, gint max_lines, + LineSplitterFn split_cb, gpointer user_data) { - const char *p, *cp; - struct line *lines; - int len; - int line_num; - const char *laststart; - const char *lastend; + const char *curr; + const char *text; const char *linestart; - double clip_width; + const char *last_breakpoint; + gint line_count = 0; + gunichar unival; + if (max_lines < 1) + max_lines = G_MAXINT; - if (text->text == NULL) - return; + text = e_text_model_get_text (model); + linestart = NULL; + last_breakpoint = text; - /* Free old array of lines */ - e_text_free_lines(text); + for (curr = text; curr && *curr && line_count < max_lines; curr = g_utf8_next_char (curr)) { - /* First, count the number of lines */ + unival = g_utf8_get_char (curr); - lastend = text->text; - laststart = text->text; - linestart = text->text; + if (linestart == NULL) + linestart = curr; - clip_width = text->clip_width; - if (clip_width >= 0 && text->draw_borders) { - clip_width -= 6; - if (clip_width < 0) - clip_width = 0; - } + if (unival == '\n') { /* We always break on newline */ - cp = text->text; - - for (p = e_unicode_get_utf8 (cp, &unival); (unival && p); cp = p, p = e_unicode_get_utf8 (p, &unival)) { - if (text->line_wrap - && (g_unichar_isspace (unival) || unival == '\n') - && e_text_model_get_object_at_pointer (text->model, cp) == -1) { /* don't break mid-object */ - if (laststart != lastend - && clip_width < text_width_with_objects (text->model, - text->font, text->style, - linestart, cp - linestart)) { - text->num_lines ++; - - linestart = laststart; - laststart = p; - lastend = cp; - } else if (g_unichar_isspace (unival)) { - laststart = p; - lastend = cp; - } - } else if (text->line_wrap - && IS_BREAKCHAR (text, unival)) { + if (split_cb) + split_cb (line_count, linestart, curr - linestart, user_data); + ++line_count; + linestart = NULL; + + } else if (wrap_lines) { - if (laststart != lastend - && g_utf8_pointer_to_offset (linestart, cp) != 1 - && clip_width < text_width_with_objects (text->model, - text->font, text->style, - linestart, p - linestart)) { - text->num_lines ++; + if (clip_width < text_width_with_objects (model, font, style, linestart, curr - linestart) + && last_breakpoint > linestart) { - linestart = laststart; - laststart = p; - lastend = p; - } else { - laststart = p; - lastend = p; + if (split_cb) + split_cb (line_count, linestart, last_breakpoint - linestart, user_data); + ++line_count; + linestart = NULL; + curr = last_breakpoint; + + } else if (IS_BREAK_CHAR (break_characters, unival) + && e_text_model_get_object_at_pointer (model, curr) == -1) { /* don't break mid-object */ + last_breakpoint = curr; } } + } - if (unival == '\n') { - text->num_lines ++; + /* Handle any leftover text. */ + if (linestart) { + + if (clip_width < text_width_with_objects (model, font, style, linestart, strlen (linestart)) + && last_breakpoint > linestart) { - lastend = p; - laststart = p; - linestart = p; - } - } + if (split_cb) + split_cb (line_count, linestart, last_breakpoint - linestart, user_data); - if ( text->line_wrap - && p - && laststart != lastend - && clip_width < text_width_with_objects (text->model, - text->font, text->style, - linestart, cp - linestart)) { - text->num_lines ++; - } + ++line_count; + linestart = g_utf8_next_char (last_breakpoint); + } - text->num_lines++; + if (split_cb) + split_cb (line_count, linestart, strlen (linestart), user_data); + ++line_count; - if ( (!text->editing) && text->max_lines != -1 && text->num_lines > text->max_lines ) { - text->num_lines = text->max_lines; } + + return line_count; +} - /* Allocate array of lines and calculate split positions */ - - text->lines = lines = g_new0 (struct line, text->num_lines); - len = 0; - line_num = 1; - lastend = text->text; - laststart = text->text; - - cp = text->text; - - for (p = e_unicode_get_utf8 (cp, &unival); p && unival && line_num < text->num_lines; cp = p, p = e_unicode_get_utf8 (p, &unival)) { - gboolean handled = FALSE; - - if (len == 0) - lines->text = cp; - if (text->line_wrap - && (g_unichar_isspace (unival) || unival == '\n') - && e_text_model_get_object_at_pointer (text->model, cp) == -1) { /* don't break mid-object */ - if (clip_width < text_width_with_objects (text->model, - text->font, text->style, - lines->text, cp - lines->text) - && laststart != lastend) { - - lines->length = lastend - lines->text; - - lines++; - line_num++; - len = cp - laststart; - lines->text = laststart; - laststart = p; - lastend = cp; - } else if (g_unichar_isspace (unival)) { - laststart = p; - lastend = cp; - len ++; - } - handled = TRUE; - } else if (text->line_wrap - && IS_BREAKCHAR(text, unival) - && e_text_model_get_object_at_pointer (text->model, cp) == -1) { - if (laststart != lastend - && g_utf8_pointer_to_offset (lines->text, cp) != 1 - && clip_width < text_width_with_objects (text->model, - text->font, text->style, - lines->text, p - lines->text)) { - - lines->length = lastend - lines->text; - - lines++; - line_num++; - len = p - laststart; - lines->text = laststart; - laststart = p; - lastend = p; - } else { - laststart = p; - lastend = p; - len ++; - } - } - if (line_num >= text->num_lines) - break; - if (unival == '\n') { +static void +line_split_cb (int line_num, const char *start, int length, gpointer user_data) +{ + EText *text = user_data; + struct line *line = &((struct line *)text->lines)[line_num]; - lines->length = cp - lines->text; - - lines++; - line_num++; - len = 0; - lastend = p; - laststart = p; - handled = TRUE; - } - if (!handled) - len++; - } + line->text = start; + line->length = length; +} + +static void +split_into_lines (EText *text) +{ + double clip_width; - if ( line_num < text->num_lines && text->line_wrap ) { - if (clip_width < text_width_with_objects (text->model, - text->font, text->style, - lines->text, cp - lines->text) - && laststart != lastend ) { + if (text->text == NULL) + return; - lines->length = lastend - lines->text; + /* Free old array of lines */ + e_text_free_lines (text); - lines++; - line_num++; - len = cp - laststart; - lines->text = laststart; - laststart = p; - lastend = cp; - } - } - - if (len == 0) - lines->text = cp; - lines->length = strlen (lines->text); + clip_width = text->clip_width; + if (clip_width >= 0 && text->draw_borders) { + clip_width -= 6; + if (clip_width < 0) + clip_width = 0; + } + + /* First, count the number of lines */ + text->num_lines = line_splitter (text->model, text->font, text->style, + text->break_characters, + text->line_wrap, text->clip_width, -1, + NULL, NULL); + + /* Allocate our array of lines */ + text->lines = g_new0 (struct line, text->num_lines); + + text->num_lines = line_splitter (text->model, text->font, text->style, + text->break_characters, + text->line_wrap, text->clip_width, text->num_lines, + line_split_cb, text); } /* Convenience function to set the text's GC's foreground color */ |