--- a/pidgin/gtkimhtml.c Fri Apr 13 02:43:11 2007 +0000 +++ b/pidgin/gtkimhtml.c Fri Apr 13 04:13:24 2007 +0000 @@ -100,7 +100,6 @@ static void delete_cb(GtkTextBuffer *buffer, GtkTextIter *iter, GtkTextIter *end, GtkIMHtml *imhtml); static void insert_ca_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextChildAnchor *arg2, gpointer user_data); static void gtk_imhtml_apply_tags_on_insert(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end); -static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter); static void gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data); static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); @@ -1736,7 +1735,7 @@ GtkSmileyTree *t = tree; const gchar *x = text; gint len = 0; - gchar *amp; + const gchar *amp; gint alen; while (*x) { @@ -1745,7 +1744,7 @@ if (!t->values) break; - if(*x == '&' && gtk_imhtml_is_amp_escape(x, &, &alen)) { + if(*x == '&' && (amp = purple_markup_detect_entity(x, &alen))) { gboolean matched = TRUE; /* Make sure all chars of the unescaped value match */ while (*(amp + 1)) { @@ -1928,62 +1927,6 @@ static gboolean -gtk_imhtml_is_amp_escape (const gchar *string, - gchar **replace, - gint *length) -{ - static char buf[7]; - g_return_val_if_fail (string != NULL, FALSE); - g_return_val_if_fail (replace != NULL, FALSE); - g_return_val_if_fail (length != NULL, FALSE); - - if (!g_ascii_strncasecmp (string, "&", 5)) { - *replace = "&"; - *length = 5; - } else if (!g_ascii_strncasecmp (string, "<", 4)) { - *replace = "<"; - *length = 4; - } else if (!g_ascii_strncasecmp (string, ">", 4)) { - *replace = ">"; - *length = 4; - } else if (!g_ascii_strncasecmp (string, " ", 6)) { - *replace = " "; - *length = 6; - } else if (!g_ascii_strncasecmp (string, "©", 6)) { - *replace = "©"; - *length = 6; - } else if (!g_ascii_strncasecmp (string, """, 6)) { - *replace = "\""; - *length = 6; - } else if (!g_ascii_strncasecmp (string, "®", 5)) { - *replace = "®"; - *length = 5; - } else if (!g_ascii_strncasecmp (string, "'", 6)) { - *replace = "\'"; - *length = 6; - } else if (*(string + 1) == '#') { - guint pound = 0; - if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { - int buflen; - if (*(string + 3 + (gint)log10 (pound)) != ';') - return FALSE; - buflen = g_unichar_to_utf8((gunichar)pound, buf); - buf[buflen] = '\0'; - *replace = buf; - *length = 2; - while (isdigit ((gint) string [*length])) (*length)++; - if (string [*length] == ';') (*length)++; - } else { - return FALSE; - } - } else { - return FALSE; - } - - return TRUE; -} - -static gboolean gtk_imhtml_is_tag (const gchar *string, gchar **tag, gint *len, @@ -2084,7 +2027,7 @@ gchar *e, *a; gchar *val; gint len; - gchar *c; + const gchar *c; GString *ret; while (g_ascii_strncasecmp (t, opt, strlen (opt))) { @@ -2120,7 +2063,7 @@ ret = g_string_new(""); e = val; while(*e) { - if(gtk_imhtml_is_amp_escape(e, &c, &len)) { + if((c = purple_markup_detect_entity(e, &len))) { ret = g_string_append(ret, c); e += len; } else { @@ -2134,71 +2077,6 @@ return g_string_free(ret, FALSE); } -/* Inline CSS Support - Douglas Thrift */ -static gchar* -gtk_imhtml_get_css_opt (gchar *style, - const gchar *opt) -{ - gchar *t = style; - gchar *e, *a; - gchar *val; - gint len; - gchar *c; - GString *ret; - - while (g_ascii_strncasecmp (t, opt, strlen (opt))) { -/* gboolean quote = FALSE; */ - if (*t == '\0') break; - while (*t && !((*t == ' ') /*&& !quote*/)) { -/* if (*t == '\"') - quote = ! quote; */ - t++; - } - while (*t && (*t == ' ')) t++; - } - - if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { - t += strlen (opt); - while (*t && (*t == ' ')) t++; - if (!*t) - return NULL; - } else { - return NULL; - } - -/* if ((*t == '\"') || (*t == '\'')) { - e = a = ++t; - while (*e && (*e != *(t - 1))) e++; - if (*e == '\0') { - return NULL; - } else - val = g_strndup(a, e - a); - } else { - e = a = t; - while (*e && !isspace ((gint) *e)) e++; - val = g_strndup(a, e - a); - }*/ - - e = a = t; - while (*e && *e != ';') e++; - val = g_strndup(a, e - a); - - ret = g_string_new(""); - e = val; - while(*e) { - if(gtk_imhtml_is_amp_escape(e, &c, &len)) { - ret = g_string_append(ret, c); - e += len; - } else { - ret = g_string_append_c(ret, *e); - e++; - } - } - g_free(val); - - return g_string_free(ret, FALSE); -} - static const char *accepted_protocols[] = { "http://", "https://", @@ -2369,7 +2247,7 @@ gint tlen, smilelen, wpos=0; gint type; const gchar *c; - gchar *amp; + const gchar *amp; gint len_protocol; guint bold = 0, @@ -2382,6 +2260,9 @@ pre = 0; gboolean br = FALSE; + gboolean align_right = FALSE; + gboolean rtl_direction = FALSE; + gint align_line = 0; GSList *fonts = NULL; GObject *object; @@ -2748,28 +2629,32 @@ * font-size * text-decoration: underline * font-weight: bold + * direction: rtl + * text-align: right * * TODO: * background-color * font-style */ { - gchar *style, *color, *background, *family, *size; + gchar *style, *color, *background, *family, *size, *direction, *alignment; gchar *textdec, *weight; GtkIMHtmlFontDetail *font, *oldfont = NULL; style = gtk_imhtml_get_html_opt (tag, "style="); if (!style) break; - color = gtk_imhtml_get_css_opt (style, "color:"); - background = gtk_imhtml_get_css_opt (style, "background:"); - family = gtk_imhtml_get_css_opt (style, - "font-family:"); - size = gtk_imhtml_get_css_opt (style, "font-size:"); - textdec = gtk_imhtml_get_css_opt (style, "text-decoration:"); - weight = gtk_imhtml_get_css_opt (style, "font-weight:"); - - if (!(color || family || size || background || textdec || weight)) { + color = purple_markup_get_css_property (style, "color"); + background = purple_markup_get_css_property (style, "background"); + family = purple_markup_get_css_property (style, "font-family"); + size = purple_markup_get_css_property (style, "font-size"); + textdec = purple_markup_get_css_property (style, "text-decoration"); + weight = purple_markup_get_css_property (style, "font-weight"); + direction = purple_markup_get_css_property (style, "direction"); + alignment = purple_markup_get_css_property (style, "text-align"); + + + if (!(color || family || size || background || textdec || weight || direction || alignment)) { g_free(style); break; } @@ -2779,6 +2664,27 @@ ws[0] = '\0'; wpos = 0; /* NEW_BIT (NEW_TEXT_BIT); */ + /* Bi-Directional text support */ + if(direction && (!strncasecmp(direction, "RTL", 3))) { + rtl_direction = TRUE; + /* insert RLE character to set direction */ + ws[wpos++] = 0xE2; + ws[wpos++] = 0x80; + ws[wpos++] = 0xAB; + ws[wpos] = '\0'; + gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); + ws[0] = '\0'; wpos = 0; + } + if(direction) + g_free(direction); + + if(alignment && (!strncasecmp(alignment, "RIGHT", 5))) { + align_right = TRUE; + align_line = gtk_text_iter_get_line(iter); + } + if(alignment) + g_free(alignment); + font = g_new0 (GtkIMHtmlFontDetail, 1); if (fonts) oldfont = fonts->data; @@ -2987,7 +2893,7 @@ pos += smilelen; wpos = 0; ws[0] = 0; - } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { + } else if (*c == '&' && (amp = purple_markup_detect_entity(c, &tlen))) { while(*amp) { ws [wpos++] = *amp++; } @@ -3035,6 +2941,32 @@ /* NEW_BIT(NEW_TEXT_BIT); */ + if(align_right) { + /* insert RLM+LRM at beginning of the line to set alignment */ + GtkTextIter line_iter; + line_iter = *iter; + gtk_text_iter_set_line(&line_iter, align_line); + /* insert RLM character to set alignment */ + ws[wpos++] = 0xE2; + ws[wpos++] = 0x80; + ws[wpos++] = 0x8F; + + if(!rtl_direction) + { + /* insert LRM character to set direction */ + /* (alignment=right and direction=LTR) */ + ws[wpos++] = 0xE2; + ws[wpos++] = 0x80; + ws[wpos++] = 0x8E; + } + + ws[wpos] = '\0'; + gtk_text_buffer_insert(imhtml->text_buffer, &line_iter, ws, wpos); + gtk_text_buffer_get_end_iter(gtk_text_iter_get_buffer(&line_iter), iter); + ws[0] = '\0'; + wpos = 0; + } + while (fonts) { GtkIMHtmlFontDetail *font = fonts->data; fonts = g_slist_remove (fonts, font); @@ -4626,7 +4558,8 @@ char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) { gunichar c; - GtkTextIter iter, nextiter; + GtkTextIter iter, next_iter, non_neutral_iter; + gboolean is_rtl_message = FALSE; GString *str = g_string_new(""); GSList *tags, *sl; GQueue *q, *r; @@ -4637,8 +4570,17 @@ gtk_text_iter_order(start, end); - nextiter = iter = *start; - gtk_text_iter_forward_char(&nextiter); + non_neutral_iter = next_iter = iter = *start; + gtk_text_iter_forward_char(&next_iter); + + /* Bi-directional text support */ + /* Get to the first non-neutral character */ + while((PANGO_DIRECTION_NEUTRAL == pango_unichar_direction(gtk_text_iter_get_char(&non_neutral_iter))) + && gtk_text_iter_forward_char(&non_neutral_iter)); + if(PANGO_DIRECTION_RTL == pango_unichar_direction(gtk_text_iter_get_char(&non_neutral_iter))) { + is_rtl_message = TRUE; + g_string_append(str, "<SPAN style=\"direction:rtl;text-align:right;\">"); + } /* First add the tags that are already in progress (we don't care about non-printing tags)*/ tags = gtk_text_iter_get_tags(start); @@ -4692,7 +4634,7 @@ for (sl = tags; sl; sl = sl->next) { tag = sl->data; /** don't worry about non-printing tags ending */ - if (tag_ends_here(tag, &iter, &nextiter) && strlen(tag_to_html_end(tag)) > 0) { + if (tag_ends_here(tag, &iter, &next_iter) && strlen(tag_to_html_end(tag)) > 0) { GtkTextTag *tmp; @@ -4700,7 +4642,7 @@ if (tmp == NULL) break; - if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0) + if (!tag_ends_here(tmp, &iter, &next_iter) && strlen(tag_to_html_end(tmp)) > 0) g_queue_push_tail(r, tmp); g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); } @@ -4719,12 +4661,16 @@ g_slist_free(tags); gtk_text_iter_forward_char(&iter); - gtk_text_iter_forward_char(&nextiter); + gtk_text_iter_forward_char(&next_iter); } while ((tag = g_queue_pop_tail(q))) g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); + /* Bi-directional text support - close tags */ + if(is_rtl_message) + g_string_append(str, "</SPAN>"); + g_queue_free(q); g_queue_free(r); return g_string_free(str, FALSE);