[evolution/webkit: 177/196] Fix printing of text/html emails (support external CSS, load images)



commit 21297ad9f0abd006db39b27a08e17da9d3087547
Author: Dan VrÃtil <dvratil redhat com>
Date:   Thu Mar 1 18:35:15 2012 +0100

    Fix printing of text/html emails (support external CSS, load images)

 mail/e-mail-display.c |    9 ++
 mail/e-mail-display.h |    4 +
 mail/e-mail-printer.c |   67 ++++++++++++----
 mail/em-format-html.c |  204 ++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 248 insertions(+), 36 deletions(-)
---
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index cd1d02c..48bb2c4 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -1581,3 +1581,12 @@ e_mail_display_load_images (EMailDisplay * display)
         display->priv->force_image_load = TRUE;
         e_web_view_reload (E_WEB_VIEW (display));
 }
+
+void
+e_mail_display_set_force_load_images (EMailDisplay *display,
+                                      gboolean force_load_images)
+{
+        g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+        display->priv->force_image_load = force_load_images;
+}
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 37a1c8c..0cf9645 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -96,6 +96,10 @@ gchar*			e_mail_display_get_selection_plain_text
 
 void                    e_mail_display_load_images      (EMailDisplay *display);
 
+void                    e_mail_display_set_force_load_images
+                                                        (EMailDisplay *display,
+                                                         gboolean force_load_images);
+
 G_END_DECLS
 
 #endif /* E_MAIL_DISPLAY_H */
diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c
index 3396769..d5638ab 100644
--- a/mail/e-mail-printer.c
+++ b/mail/e-mail-printer.c
@@ -31,6 +31,7 @@
 
 #include "e-mail-printer.h"
 #include "em-format-html-print.h"
+#include "e-mail-display.h"
 
 static gpointer parent_class = NULL;
 
@@ -49,6 +50,8 @@ enum {
 struct _EMailPrinterPrivate {
 	EMFormatHTMLPrint *efhp;
 
+        gboolean export_mode;
+
 	GtkListStore *headers;
 
 	WebKitWebView *webview; /* WebView to print from */
@@ -147,13 +150,44 @@ emp_printing_done (GtkPrintOperation *operation,
 }
 
 static void
-emp_run_print_operation (EMailPrinter *emp,
-			 gboolean export)
+emp_start_printing (GObject *object,
+                    GParamSpec *pspec,
+                    gpointer user_data)
+{
+        WebKitWebView *web_view;
+        WebKitWebFrame *frame;
+        WebKitLoadStatus load_status;
+        EMailPrinter *emp = user_data;
+
+        web_view = WEBKIT_WEB_VIEW (object);
+        load_status = webkit_web_view_get_load_status (web_view);
+
+        if (load_status != WEBKIT_LOAD_FINISHED)
+                return;
+
+        frame = webkit_web_view_get_main_frame (web_view);
+
+        if (emp->priv->export_mode) {
+                gtk_print_operation_set_export_filename (
+                        emp->priv->operation,
+                        emp->priv->efhp->export_filename);
+                webkit_web_frame_print_full (
+                        frame, emp->priv->operation,
+                        GTK_PRINT_OPERATION_ACTION_EXPORT, NULL);
+        } else {
+                webkit_web_frame_print_full
+                (frame, emp->priv->operation,
+                 GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL);
+        }
+
+}
+
+static void
+emp_run_print_operation (EMailPrinter *emp)
 {
 	EMFormat *emf;
 	SoupSession *session;
 	GHashTable *formatters;
-	WebKitWebFrame *frame;
 	gchar *mail_uri;
 
 	emf = EM_FORMAT (emp->priv->efhp);
@@ -169,12 +203,17 @@ emp_run_print_operation (EMailPrinter *emp,
 	/* Print_layout is a special EMPart created by EMFormatHTMLPrint */
         if (emp->priv->uri)
                 g_free (emp->priv->uri);
-        emp->priv->uri = g_strconcat (mail_uri, "?part_id=print_layout", NULL);
+
+        emp->priv->uri = g_strconcat (mail_uri, "?part_id=print_layout&__evo-load-images=1", NULL);
 
         if (emp->priv->webview == NULL) {
-		emp->priv->webview = WEBKIT_WEB_VIEW (e_web_view_new ());
+		emp->priv->webview = g_object_new (E_TYPE_MAIL_DISPLAY, NULL);
                 e_web_view_set_enable_frame_flattening (E_WEB_VIEW (emp->priv->webview), FALSE);
+                e_mail_display_set_force_load_images (
+                                E_MAIL_DISPLAY (emp->priv->webview), TRUE);
                 g_object_ref_sink (emp->priv->webview);
+                g_signal_connect (emp->priv->webview, "notify::load-status",
+                        G_CALLBACK (emp_start_printing), emp);
 
                 w({
                         GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -186,16 +225,10 @@ emp_run_print_operation (EMailPrinter *emp,
                 });
 	}
 
-        webkit_web_view_load_uri (emp->priv->webview, emp->priv->uri);
-
-	frame = webkit_web_view_get_main_frame (emp->priv->webview);
+	e_mail_display_set_formatter (E_MAIL_DISPLAY (emp->priv->webview),
+                                      (EMFormatHTML *) emp->priv->efhp);
 
-	if (export) {
-		gtk_print_operation_set_export_filename (emp->priv->operation, emp->priv->efhp->export_filename);
-		webkit_web_frame_print_full (frame, emp->priv->operation, GTK_PRINT_OPERATION_ACTION_EXPORT, NULL);
-	} else {
-		webkit_web_frame_print_full (frame, emp->priv->operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, NULL);
-	}
+        webkit_web_view_load_uri (emp->priv->webview, emp->priv->uri);
 
 	g_free (mail_uri);
 }
@@ -764,7 +797,7 @@ e_mail_printer_new (EMFormatHTML* source)
 
 void
 e_mail_printer_print (EMailPrinter *emp,
-		      gboolean export,
+		      gboolean export_mode,
 		      GCancellable *cancellable)
 {
 	g_return_if_fail (E_IS_MAIL_PRINTER (emp));
@@ -782,11 +815,13 @@ e_mail_printer_print (EMailPrinter *emp,
         g_signal_connect (emp->priv->operation, "draw-page",
                 G_CALLBACK (emp_draw_footer), NULL);
 
+        emp->priv->export_mode = export_mode;
+
         if (cancellable)
                 g_signal_connect_swapped (cancellable, "cancelled",
 		        G_CALLBACK (gtk_print_operation_cancel), emp->priv->operation);
 
-	emp_run_print_operation (emp, export);
+	emp_run_print_operation (emp);
 }
 
 const gchar*
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index cde3b16..02f1bb3 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -730,6 +730,65 @@ efh_write_text_plain (EMFormat *emf,
 	camel_stream_write_string (stream, "</div></div>\n", cancellable, NULL);
 }
 
+static gchar*
+get_tag (const gchar *tag_name,
+	 gchar *opening,
+	 gchar *closing)
+{
+	gchar *t;
+	gboolean has_end;
+
+	for (t = closing - 1; t != opening; t--) {
+		if (*t != ' ')
+			break;
+	}
+
+	/* Not a pair tag */
+	if (*t == '/')
+		return g_strndup (opening, closing - opening + 1);
+
+	for (t = closing; t && *t; t++) {
+		if (*t == '<')
+			break;
+	}
+
+	do {
+		if (*t == '/') {
+			has_end = TRUE;
+			break;
+		}
+
+		if (*t == '>') {
+			has_end = FALSE;
+			break;
+		}
+
+		t++;
+
+	} while (t && *t);
+
+	/* Broken HTML? */
+	if (!has_end)
+		return g_strndup (opening, closing - opening + 1);
+
+	do {
+		if ((*t != ' ') && (*t != '/'))
+			break;
+
+                t++;
+	} while (t && *t);
+
+	if (g_strncasecmp (t, tag_name, strlen (tag_name)) == 0) {
+
+		closing = strstr (t, ">");
+
+		return g_strndup (opening, closing - opening + strlen(tag_name));
+	}
+
+	/* Broken HTML? */
+	return g_strndup (opening, closing - opening + 1);
+}
+
 static void
 efh_write_text_html (EMFormat *emf,
 		     EMFormatPURI *puri,
@@ -746,31 +805,136 @@ efh_write_text_html (EMFormat *emf,
                 em_format_format_text (emf, stream,
                         (CamelDataWrapper *) puri->part, cancellable);
 
-        } else {
-                gchar *str;
-                gchar *uri;
+        } else if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) {
+		GString *string;
+		CamelDataWrapper *dw;
+		GByteArray *ba;
+		gchar *pos;
+		GList *tags, *iter;
+		gboolean valid;
+		gchar *tag;
+		const gchar *document_end;
+		gint length;
+		gint i;
+
+		dw = camel_medium_get_content ((CamelMedium *) puri->part);
+		ba = camel_data_wrapper_get_byte_array (dw);
+
+		string = g_string_new_len ((gchar *) ba->data, ba->len);
+
+		tags = NULL;
+		pos = string->str;
+		valid = FALSE;
+		do {
+			gchar *closing;
+			gchar *opening;
+
+			pos = strstr (pos + 1, "<");
+			if (!pos)
+				break;
 
-                uri = em_format_build_mail_uri (emf->folder, emf->message_uid,
-                        "part_id", G_TYPE_STRING, puri->uri,
-                        "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW,
-                        NULL);
+			opening = pos;
+			closing = strstr (pos, ">");
 
-                str = g_strdup_printf (
-                        "<div class=\"part-container\" style=\"border: solid #%06x 1px; "
-                        "background-color: #%06x;\">"
-                        "<div class=\"part-container-inner-margin\">\n"
-                        "<iframe width=\"100%%\" height=\"auto\""
-                        " frameborder=\"0\" src=\"%s\"></iframe>"
+			/* Find where the actual tag name begins */
+			for (tag = pos + 1; tag && *tag; tag++) {
+				if (*tag != ' ')
+					break;
+			}
+
+			if (g_ascii_strncasecmp (tag, "style", 5) == 0) {
+				tags = g_list_append (
+					tags,
+					get_tag ("style", opening, closing));
+			} else if (g_ascii_strncasecmp (tag, "script", 6) == 0) {
+				tags = g_list_append (
+					tags,
+                                        get_tag ("script", opening, closing));
+			} else if (g_ascii_strncasecmp (tag, "link", 4) == 0) {
+				tags = g_list_append (
+					tags,
+                                        get_tag ("link", opening, closing));
+			} else if (g_ascii_strncasecmp (tag, "body", 4) == 0) {
+				valid = TRUE;
+				break;
+			}
+
+		} while (TRUE);
+
+		/* Something's wrong, let's write the entire HTML and hope
+		 * that WebKit can handle it */
+		if (!valid) {
+			EMFormatWriterInfo i = *info;
+			i.mode = EM_FORMAT_WRITE_MODE_RAW;
+			efh_write_text_html (emf, puri, stream, &i, cancellable);
+			return;
+		}
+
+		/*	        include the "body" as well -----v */
+		g_string_erase (string, 0, tag - string->str + 4);
+		g_string_prepend (string, "<div ");
+
+		for (iter = tags; iter; iter = iter->next) {
+			g_string_prepend (string, iter->data);
+		}
+
+		g_list_free_full (tags, g_free);
+
+		/* that's reversed </body></html>... */
+		document_end = ">lmth/<>ydob/<";
+		length = strlen (document_end);
+		tag = string->str + string->len - 1;
+		i = 0;
+		valid = FALSE;
+		while (i < length - 1) {
+
+			if (g_ascii_isspace (*tag)) {
+				tag--;
+				continue;
+			}
+
+			if (*tag == document_end[i]) {
+				tag--;
+				i++;
+				valid = TRUE;
+				continue;
+			}
+
+			valid = FALSE;
+		}
+
+		if (valid)
+			g_string_truncate (string, tag - string->str);
+
+		camel_stream_write_string (stream, string->str, cancellable, NULL);
+
+		g_string_free (string, TRUE);
+	} else {
+		gchar *str;
+		gchar *uri;
+
+		uri = em_format_build_mail_uri (
+                                emf->folder, emf->message_uid,
+				"part_id", G_TYPE_STRING, puri->uri,
+				"mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW,
+                                NULL);
+
+		str = g_strdup_printf (
+			"<div class=\"part-container\" style=\"border-color: #%06x; "
+			"background-color: #%06x;\">"
+			"<div class=\"part-container-inner-margin\">\n"
+			"<iframe width=\"100%%\" height=\"auto\""
+			" frameborder=\"0\" src=\"%s\"></iframe>"
                         "</div></div>",
                         e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]),
                         e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]),
-                        uri);
+			uri);
 
-                camel_stream_write_string (stream, str, cancellable, NULL);
+		camel_stream_write_string (stream, str, cancellable, NULL);
 
-                g_free (str);
-                g_free (uri);
-        }
+		g_free (str);
+		g_free (uri);
+	}
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]