pidgin/gtkimhtml.c

changeset 16143
6393e5b11ff5
parent 15931
716b5fac1895
child 16144
4e022531d1c9
--- 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, &amp, &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, "&gt;", 4)) {
-		*replace = ">";
-		*length = 4;
-	} else if (!g_ascii_strncasecmp (string, "&nbsp;", 6)) {
-		*replace = " ";
-		*length = 6;
-	} else if (!g_ascii_strncasecmp (string, "&copy;", 6)) {
-		*replace = "©";
-		*length = 6;
-	} else if (!g_ascii_strncasecmp (string, "&quot;", 6)) {
-		*replace = "\"";
-		*length = 6;
-	} else if (!g_ascii_strncasecmp (string, "&reg;", 5)) {
-		*replace = "®";
-		*length = 5;
-	} else if (!g_ascii_strncasecmp (string, "&apos;", 6)) {
-		*replace = "\'";
-		*length = 6;
-	} else if (*(string + 1) == '#') {
-		guint pound = 0;
-		if ((sscanf (string, "&#%u;", &pound) == 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, &amp, &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);

mercurial