[evolution/webkit: 7/33] Port EMFormatHTML to WebKit



commit e8f9c908031a154217b0111c02858e3f9f25b1c7
Author: Dan VrÃtil <dvratil redhat com>
Date:   Tue Jul 26 17:57:42 2011 +0200

    Port EMFormatHTML to WebKit
    
    EMFormatHTML is now able to display any kind of emails in WebKit webview.
    Some functionaliy is solved by using JavaScript (height of iframe with
    text/html part, automatic jump to beginning of email).
    Embedded GtkWidgets (attachments bar, etc)  should work, but this feature
    was not tested due to WebKit bug #63451.
    This port is not completely asynchronous, additional resources (text/html
    parts, embedded images) are being parsed and formatted synchronously (in
    the main loop), because as of now WebKit does not provide any means to
    change content of a resource asynchronously.

 data/webview.css              |    5 +
 mail/Makefile.am              |    4 +-
 mail/e-mail-display.c         |   17 --
 mail/e-mail-reader.c          |   14 +-
 mail/em-format-html-display.c |   63 ++---
 mail/em-format-html.c         |  615 +++++++++++++++++++++++++----------------
 mail/em-format-html.h         |    6 +-
 mail/em-html-stream.c         |  182 ------------
 mail/em-html-stream.h         |   77 -----
 widgets/misc/e-web-view.c     |  234 ++++++++++++++++
 widgets/misc/e-web-view.h     |   28 ++-
 11 files changed, 678 insertions(+), 567 deletions(-)
---
diff --git a/data/webview.css b/data/webview.css
index 346c28a..1f87964 100644
--- a/data/webview.css
+++ b/data/webview.css
@@ -16,3 +16,8 @@ th {
 .header {
   color: #7f7f7f;
 }
+
+.pre {
+  font-family: monospace;
+  font-size: 0.8em;
+}
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 97a2fe3..878e361 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -93,7 +93,7 @@ mailinclude_HEADERS =					\
 	em-format-html.h				\
 	em-format-html-display.h			\
 	em-format-html-print.h				\
-	em-html-stream.h				\
+	em-junk.h					\
 	em-search-context.h				\
 	em-subscription-editor.h			\
 	em-sync-stream.h				\
@@ -166,7 +166,7 @@ libevolution_mail_la_SOURCES =				\
 	em-format-html.c				\
 	em-format-html-display.c			\
 	em-format-html-print.c				\
-	em-html-stream.c				\
+	em-junk.c					\
 	em-search-context.c				\
 	em-subscription-editor.c			\
 	em-sync-stream.c				\
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index aa3c4bd..5838923 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -215,22 +215,6 @@ mail_display_style_set (GtkWidget *widget,
 }
 
 static void
-mail_display_load_string (EWebView *web_view,
-                          const gchar *string)
-{
-	EMailDisplayPrivate *priv;
-
-	priv = E_MAIL_DISPLAY (web_view)->priv;
-	g_return_if_fail (priv->formatter != NULL);
-
-	if (em_format_busy (EM_FORMAT (priv->formatter)))
-		return;
-
-	/* Chain up to parent's load_string() method. */
-	E_WEB_VIEW_CLASS (parent_class)->load_string (web_view, string);
-}
-
-static void
 mail_display_url_requested (GtkHTML *html,
                             const gchar *uri,
                             GtkHTMLStream *stream)
@@ -356,7 +340,6 @@ mail_display_class_init (EMailDisplayClass *class)
 	widget_class->style_set = mail_display_style_set;
 
 	web_view_class = E_WEB_VIEW_CLASS (class);
-	web_view_class->load_string = mail_display_load_string;
 	web_view_class->process_mailto = mail_display_process_mailto;
 
 	html_class = GTK_HTML_CLASS (class);
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 430f71d..7d475c9 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2653,17 +2653,25 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 			EMailReaderClosure *closure;
 			GCancellable *cancellable;
 			EActivity *activity;
-			gchar *string;
+			gchar *string, *html;
 
 			string = g_strdup_printf (
 				_("Retrieving message '%s'"), cursor_uid);
+
+			html = g_strdup_printf ("<html><head></head><body>"
+						"<table width=\"100%%\" height=\"100%%\"><tr>"
+						"<td valign=\"middle\" align=\"center\"><h5>%s</h5></td>"
+						"</tr></table>"
+						"</body></html>",
+						string);
 #if HAVE_CLUTTER
 			if (!e_shell_get_express_mode (e_shell_get_default ()))
-				e_web_view_load_string (web_view, string);
+				e_web_view_load_string (web_view, html);
 #else
-			e_web_view_load_string (web_view, string);
+			e_web_view_load_string (web_view, html);
 #endif
 			g_free (string);
+			g_free (html);
 
 			activity = e_mail_reader_new_activity (reader);
 			cancellable = e_activity_get_cancellable (activity);
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index dcaafed..ad3f162 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -38,9 +38,6 @@
 #undef interface
 #endif
 
-#include <gtkhtml/gtkhtml.h>
-#include <gtkhtml/gtkhtml-embedded.h>
-
 #include <glib/gi18n.h>
 
 #include <e-util/e-util.h>
@@ -109,8 +106,8 @@ static const gchar *smime_sign_colour[5] = {
 
 static void efhd_attachment_frame (EMFormat *emf, CamelStream *stream, EMFormatPURI *puri, GCancellable *cancellable);
 static void efhd_message_add_bar (EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
-static gboolean efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
-static gboolean efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *object);
+static GtkWidget* efhd_attachment_button (EMFormatHTML *efh, EMFormatHTMLPObject *pobject);
+static GtkWidget* efhd_attachment_optional (EMFormatHTML *efh, EMFormatHTMLPObject *object);
 static void efhd_free_attach_puri_data (EMFormatPURI *puri);
 
 struct _attach_puri {
@@ -122,12 +119,7 @@ struct _attach_puri {
 
 	/* for the > and V buttons */
 	GtkWidget *forward, *down;
-	/* currently no way to correlate this data to the frame :( */
-	GtkHTML *frame;
-	guint shown : 1;
-
-	/* Embedded Frame */
-	GtkHTMLEmbedded *html;
+	guint shown:1;
 
 	/* Attachment */
 	EAttachment *attachment;
@@ -350,12 +342,10 @@ efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
 	gtk_widget_show (po->widget);
 }
 
-static gboolean
+static GtkWidget*
 efhd_xpkcs7mime_button (EMFormatHTML *efh,
-                        GtkHTMLEmbedded *eb,
                         EMFormatHTMLPObject *pobject)
 {
-	GtkWidget *container;
 	GtkWidget *widget;
 	struct _smime_pobject *po = (struct _smime_pobject *) pobject;
 	const gchar *icon_name;
@@ -366,23 +356,17 @@ efhd_xpkcs7mime_button (EMFormatHTML *efh,
 	else
 		icon_name = smime_encrypt_table[po->valid->encrypt.status].icon;
 
-	container = GTK_WIDGET (eb);
-
 	widget = gtk_button_new ();
 	g_signal_connect (
 		widget, "clicked",
 		G_CALLBACK (efhd_xpkcs7mime_validity_clicked), pobject);
-	gtk_container_add (GTK_CONTAINER (container), widget);
 	gtk_widget_show (widget);
 
-	container = widget;
-
 	widget = gtk_image_new_from_icon_name (
 		icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
-	gtk_container_add (GTK_CONTAINER (container), widget);
 	gtk_widget_show (widget);
 
-	return TRUE;
+	return widget;
 }
 
 static gboolean
@@ -483,7 +467,7 @@ efhd_format_attachment (EMFormat *emf,
 		"<tr><td></td><tr>"
 		"</table>"
 		"</td>"
-		"<td><object classid=\"%s\"></object></td>"
+		"<td><object data=\"%s\" type=\"application/x-gtk-widget\"></object></td>"
 		"<td><table width=3 cellspacing=0 cellpadding=0>"
 		"<tr><td></td></tr>"
 		"</table></td>"
@@ -575,7 +559,7 @@ efhd_format_optional (EMFormat *emf,
 		buffer,
 		"</font></h3></td></tr></table>\n"
 		"<table cellspacing=0 cellpadding=0><tr>"
-		"<td><object classid=\"%s\"></object>"
+		"<td><object data=\"%s\" type=\"application/x-gtk-widget\"></object>"
 		"</td></tr></table>" EM_FORMAT_HTML_VPAD,
 		classid);
 
@@ -624,7 +608,7 @@ efhd_format_secure (EMFormat *emf,
 		pobj->object.free = efhd_xpkcs7mime_free;
 		g_string_append_printf (
 			buffer,
-			"<td valign=center><object classid=\"%s\">"
+			"<td valign=center><object data=\"%s\" type=\"application/x-gtk-widget\">"
 			"</object></td><td width=100%% valign=center>",
 			classid);
 		g_free (classid);
@@ -1115,10 +1099,9 @@ attachment_button_realized (GtkWidget *widget)
 /* ********************************************************************** */
 
 /* attachment button callback */
-static gboolean
+static GtkWidget*
 efhd_attachment_button (EMFormatHTML *efh,
-                        GtkHTMLEmbedded *eb,
-                        EMFormatHTMLPObject *pobject)
+						EMFormatHTMLPObject *pobject)
 {
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh;
 	struct _attach_puri *info;
@@ -1156,7 +1139,7 @@ efhd_attachment_button (EMFormatHTML *efh,
 
 	if (!info || info->forward) {
 		g_warning ("unable to expand the attachment\n");
-		return TRUE;
+		return NULL;
 	}
 
 	attachment = info->attachment;
@@ -1192,7 +1175,6 @@ efhd_attachment_button (EMFormatHTML *efh,
 	e_attachment_button_set_attachment (
 		E_ATTACHMENT_BUTTON (widget), attachment);
 	gtk_widget_set_can_focus (widget, TRUE);
-	gtk_container_add (GTK_CONTAINER (eb), widget);
 	gtk_widget_show (widget);
 
 	/* FIXME Not sure why the expanded callback can't just use
@@ -1208,13 +1190,14 @@ efhd_attachment_button (EMFormatHTML *efh,
 	/* If the button is created, then give it focus after
 	 * it is realized, so that user can use arrow keys to scroll
 	 * message */
+	 /* WEBKIT: Is this still needed? */
 	if (efhd->priv->attachment_expanded || e_attachment_button_get_expanded (E_ATTACHMENT_BUTTON (widget))) {
 		g_signal_connect (
 			widget, "realize",
 			G_CALLBACK (attachment_button_realized), NULL);
 	}
 
-	return TRUE;
+	return widget;
 }
 
 static void
@@ -1264,9 +1247,8 @@ efhd_bar_resize (EMFormatHTML *efh,
 	}
 }
 
-static gboolean
+static GtkWidget*
 efhd_add_bar (EMFormatHTML *efh,
-              GtkHTMLEmbedded *eb,
               EMFormatHTMLPObject *pobject)
 {
 	EMFormatHTMLDisplayPrivate *priv;
@@ -1282,17 +1264,16 @@ efhd_add_bar (EMFormatHTML *efh,
 	priv = EM_FORMAT_HTML_DISPLAY (efh)->priv;
 
 	widget = e_mail_attachment_bar_new ();
-	gtk_container_add (GTK_CONTAINER (eb), widget);
 
 	g_hash_table_insert (priv->attachment_views, g_strdup (strchr (pobject->classid, ':') + 1), widget);
 	g_object_weak_ref (G_OBJECT (widget), efhd_attachment_view_gone_cb, efh);
 	gtk_widget_hide (widget);
 
 	g_signal_connect_swapped (
-		eb, "size-allocate",
+		widget, "size-allocate",
 		G_CALLBACK (efhd_bar_resize), efh);
 
-	return TRUE;
+	return widget;
 }
 
 static void
@@ -1317,7 +1298,7 @@ efhd_message_add_bar (EMFormat *emf,
 		classid, part, efhd_add_bar);
 
 	content = g_strdup_printf (
-		"<td><object classid=\"%s\"></object></td>", classid);
+		"<td><object data=\"%s\" type=\"application/x-gtk-widget\"></object></td>", classid);
 	camel_stream_write_string (stream, content, NULL, NULL);
 	g_free (content);
 
@@ -1353,10 +1334,9 @@ efhd_resize (GtkWidget *w,
 }
 
 /* optional render attachment button callback */
-static gboolean
+static GtkWidget*
 efhd_attachment_optional (EMFormatHTML *efh,
-                          GtkHTMLEmbedded *eb,
-                          EMFormatHTMLPObject *pobject)
+						  EMFormatHTMLPObject *pobject)
 {
 	struct _attach_puri *info;
 	GtkWidget *hbox, *vbox, *button, *mainbox, *scroll, *label, *img;
@@ -1373,7 +1353,7 @@ efhd_attachment_optional (EMFormatHTML *efh,
 	info = (struct _attach_puri *) em_format_find_puri ((EMFormat *) efh, pobject->classid);
 	if (!info || info->forward) {
 		g_warning ("unable to expand the attachment\n");
-		return TRUE;
+		return NULL;
 	}
 
 	scroll = gtk_scrolled_window_new (NULL, NULL);
@@ -1447,10 +1427,9 @@ efhd_attachment_optional (EMFormatHTML *efh,
 		gtk_widget_hide (scroll);
 
 	gtk_widget_show (vbox);
-	gtk_container_add (GTK_CONTAINER (eb), vbox);
 	info->handle = NULL;
 
-	return TRUE;
+	return view;
 }
 
 static void
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index c2e13be..18ce462 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -51,21 +51,17 @@
 
 #include <shell/e-shell.h>
 
-#include <gtkhtml/gtkhtml.h>
-#include <gtkhtml/gtkhtml-stream.h>
-
 #include <glib/gi18n.h>
 
 #include "e-mail-enumtypes.h"
 #include "em-format-html.h"
-#include "em-html-stream.h"
 #include "em-utils.h"
 #include "mail-config.h"
 #include "mail-mt.h"
 
 #define d(x)
 
-#define EFM_MESSAGE_START_ANAME "evolution#message#start"
+#define EFM_MESSAGE_START_ANAME "evolution_message_start"
 #define EFH_MESSAGE_START "<A name=\"" EFM_MESSAGE_START_ANAME "\"></A>"
 
 struct _EMFormatHTMLCache {
@@ -118,7 +114,26 @@ enum {
 	PROP_HEADERS_COLLAPSABLE
 };
 
-static void efh_gtkhtml_destroy(GtkHTML *html, EMFormatHTML *efh);
+
+static void	emfh_format_email		(struct _EMFormatHTMLJob *job,
+	       	   				 GCancellable *cancellable);
+
+static gboolean	efh_display_formatted_data	(gpointer data);
+
+static GtkWidget* efh_create_plugin_widget	(WebKitWebView *web_view,
+						 gchar *mime_type,
+						 gchar *uri,
+						 GHashTable *param,
+						 gpointer user_data);
+static void	efh_webview_frame_created	(WebKitWebView *web_view,
+						 WebKitWebFrame *frame,
+						 gpointer user_data);
+static void	efh_resource_requested		(WebKitWebView *web_view,
+						 WebKitWebFrame *frame,
+						 WebKitWebResource *resource,
+						 WebKitNetworkRequest *request,
+						 WebKitNetworkResponse *reponse,
+						 gpointer user_data);
 
 static void	efh_format_message		(EMFormat *emf,
 						 CamelStream *stream,
@@ -151,7 +166,6 @@ struct _format_msg {
 
 	EMFormatHTML *format;
 	EMFormat *format_source;
-	EMHTMLStream *estream;
 	CamelFolder *folder;
 	gchar *uid;
 	CamelMimeMessage *message;
@@ -170,11 +184,9 @@ efh_format_exec (struct _format_msg *m,
                  GError **error)
 {
 	EMFormat *format;
-	CamelStream *stream;
 	struct _EMFormatHTMLJob *job;
 	GNode *puri_level;
 	CamelURL *base;
-	gchar *content;
 
 	if (m->format->priv->web_view == NULL) {
 		m->cancelled = TRUE;
@@ -182,62 +194,19 @@ efh_format_exec (struct _format_msg *m,
 	}
 
 	format = EM_FORMAT (m->format);
-	stream = CAMEL_STREAM (m->estream);
-
-	content = g_strdup_printf (
-		"<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"
-		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n</head>\n"
-		"<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6>\n",
-		e_color_to_value (
-			&m->format->priv->colors[
-			EM_FORMAT_HTML_COLOR_BODY]),
-		e_color_to_value (
-			&m->format->priv->colors[
-			EM_FORMAT_HTML_COLOR_HEADER]));
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
-
-	/* <insert top-header stuff here> */
-
-	if (format->mode == EM_FORMAT_MODE_SOURCE) {
-		em_format_format_source (
-			format, stream,
-			(CamelMimePart *) m->message, cancellable);
-	} else {
-		const EMFormatHandler *handle;
-		const gchar *mime_type;
-
-		mime_type = "x-evolution/message/prefix";
-		handle = em_format_find_handler (format, mime_type);
-
-		if (handle != NULL)
-			handle->handler (
-				format, stream,
-				CAMEL_MIME_PART (m->message), handle,
-				cancellable, FALSE);
-
-		mime_type = "x-evolution/message/rfc822";
-		handle = em_format_find_handler (format, mime_type);
-
-		if (handle != NULL)
-			handle->handler (
-				format, stream,
-				CAMEL_MIME_PART (m->message), handle,
-				cancellable, FALSE);
-	}
-
-	camel_stream_flush (stream, cancellable, NULL);
 
 	puri_level = format->pending_uri_level;
 	base = format->base;
 
 	do {
-		/* now dispatch any added tasks ... */
+		d(printf("processing job\n"));
+
 		g_mutex_lock (m->format->priv->lock);
 		while ((job = g_queue_pop_head (&m->format->priv->pending_jobs))) {
+
 			g_mutex_unlock (m->format->priv->lock);
 
-			/* This is an implicit check to see if the gtkhtml has been destroyed */
+			/* This is an implicit check to see if the webview has been destroyed */
 			if (m->format->priv->web_view == NULL)
 				g_cancellable_cancel (cancellable);
 
@@ -245,41 +214,27 @@ efh_format_exec (struct _format_msg *m,
 			format->pending_uri_level = job->puri_level;
 			if (job->base)
 				format->base = job->base;
+			/* Call the job's callback, usually a parser */
 			job->callback (job, cancellable);
 			format->base = base;
 
-			/* clean up the job */
-			g_object_unref (job->stream);
-			if (job->base)
-				camel_url_free (job->base);
-			g_free (job);
+			/* Display stream created by the callback and free
+			   the job struct */
+			g_idle_add(efh_display_formatted_data, job);
 
 			g_mutex_lock (m->format->priv->lock);
 		}
 		g_mutex_unlock (m->format->priv->lock);
 
-		if (m->estream) {
-			/* Closing this base stream can queue more jobs, so we need
-			 * to check the list again after we've finished */
-			d(printf("out of jobs, closing root stream\n"));
-			camel_stream_write_string (
-				(CamelStream *) m->estream,
-				"</body>\n</html>\n", cancellable, NULL);
-			camel_stream_close ((CamelStream *) m->estream, cancellable, NULL);
-			if (g_cancellable_is_cancelled (cancellable)) {
-				m->cancelled = TRUE;
-				m->estream->sync.cancel = TRUE;
-			}
-			g_object_unref (m->estream);
-			m->estream = NULL;
-		}
-
 	} while (!g_queue_is_empty (&m->format->priv->pending_jobs));
 
 	d(printf("out of jobs, done\n"));
 
 	format->pending_uri_level = puri_level;
+
 	m->cancelled = m->cancelled || g_cancellable_is_cancelled (cancellable);
+
+	m->format->priv->format_id = -1;
 }
 
 static void
@@ -298,12 +253,6 @@ efh_format_free (struct _format_msg *m)
 {
 	d(printf("formatter freed\n"));
 	g_object_unref (m->format);
-	if (m->estream) {
-		camel_stream_close ((CamelStream *) m->estream, NULL, NULL);
-		if (m->cancelled)
-			m->estream->sync.cancel = TRUE;
-		g_object_unref (m->estream);
-	}
 	if (m->folder)
 		g_object_unref (m->folder);
 	g_free (m->uid);
@@ -322,14 +271,46 @@ static MailMsgInfo efh_format_info = {
 };
 
 static gboolean
+efh_display_formatted_data (gpointer data)
+{
+	/* This is an idle callback */
+
+	struct _EMFormatHTMLJob *job = data;
+	EWebView *web_view = job->format->priv->web_view;
+	GByteArray *ba;
+	gchar *content;
+
+	if (web_view == NULL)
+		goto cleanup;
+
+	d(printf("displaying messsage\n"));
+
+	ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (job->stream));
+
+	content = g_strndup ((gchar*) ba->data, ba->len);
+	e_web_view_load_string (web_view, content);
+
+	g_free (content);
+
+cleanup:
+	/* Clean up the job */
+	g_object_unref (job->stream);
+	if (job->base)
+		camel_url_free (job->base);
+	g_free (job);
+
+	return FALSE;
+}
+
+static gboolean
 efh_format_timeout (struct _format_msg *m)
 {
-	GtkHTMLStream *hstream;
 	EMFormatHTML *efh = m->format;
+	EMFormat *emf = EM_FORMAT (efh);
 	struct _EMFormatHTMLPrivate *p = efh->priv;
 	EWebView *web_view;
 
-	web_view = em_format_html_get_web_view (m->format);
+	web_view = em_format_html_get_web_view (efh);
 
 	if (web_view == NULL) {
 		mail_msg_unref (m);
@@ -344,60 +325,55 @@ efh_format_timeout (struct _format_msg *m)
 
 	g_return_val_if_fail (g_queue_is_empty (&p->pending_jobs), FALSE);
 
-	d(printf(" ready to go, firing off format thread\n"));
-
 	/* call super-class to kick it off */
 	/* FIXME Not passing a GCancellable here. */
 	EM_FORMAT_CLASS (parent_class)->format_clone (
-		EM_FORMAT (efh), m->folder, m->uid,
+		emf, m->folder, m->uid,
 		m->message, m->format_source, NULL);
-	em_format_html_clear_pobject (m->format);
+	em_format_html_clear_pobject (efh);
 
 	/* FIXME: method off EMFormat? */
-	if (((EMFormat *) efh)->valid) {
-		camel_cipher_validity_free (((EMFormat *) efh)->valid);
-		((EMFormat *) efh)->valid = NULL;
-		((EMFormat *) efh)->valid_parent = NULL;
+	if (emf->valid) {
+		camel_cipher_validity_free (emf->valid);
+		emf->valid = NULL;
+		emf->valid_parent = NULL;
 	}
 
 	if (m->message == NULL) {
-		hstream = gtk_html_begin (GTK_HTML (web_view));
-		gtk_html_stream_close (hstream, GTK_HTML_STREAM_OK);
 		mail_msg_unref (m);
 		p->last_part = NULL;
 	} else {
+		struct _EMFormatHTMLJob *job;
+
+		/* Queue a job for parsing the email main content */
+		job = em_format_html_job_new (efh, emfh_format_email, m->message);
+		job->stream = camel_stream_mem_new ();
+		em_format_html_job_queue (efh, job);
+
 		efh->state = EM_FORMAT_HTML_STATE_RENDERING;
 #if HAVE_CLUTTER
 		if (p->last_part != m->message && !e_shell_get_express_mode (e_shell_get_default ())) {
 #else
 		if (p->last_part != m->message) {
 #endif
-			hstream = gtk_html_begin (GTK_HTML (web_view));
-			gtk_html_stream_printf (hstream, "<h5>%s</h5>", _("Formatting Message..."));
-			gtk_html_stream_close (hstream, GTK_HTML_STREAM_OK);
-		}
-
-		hstream = NULL;
-		m->estream = (EMHTMLStream *) em_html_stream_new (
-			GTK_HTML (web_view), hstream);
+			gchar *str = g_strdup_printf ("<html><head></head><body>"
+						      "<table width=\"100%%\" height=\"100%%\"><tr>"
+						      "<td valign=\"middle\" align=\"center\"><h5>%s</h5></td>"
+						      "</tr></table>"
+						      "</body></html>", _("Formatting Message..."));
+			e_web_view_load_string (web_view, str);
+			g_free (str);
 
-		if (p->last_part == m->message) {
-			em_html_stream_set_flags (m->estream,
-						  GTK_HTML_BEGIN_KEEP_SCROLL | GTK_HTML_BEGIN_KEEP_IMAGES
-						  | GTK_HTML_BEGIN_BLOCK_UPDATES | GTK_HTML_BEGIN_BLOCK_IMAGES);
-		} else {
-			/* clear cache of inline-scanned text parts */
 			g_hash_table_remove_all (p->text_inline_parts);
 
 			p->last_part = m->message;
 		}
 
-		efh->priv->format_id = m->base.seq;
 		mail_msg_unordered_push (m);
 	}
 
-	efh->priv->format_timeout_id = 0;
-	efh->priv->format_timeout_msg = NULL;
+	p->format_timeout_id = 0;
+	p->format_timeout_msg = NULL;
 
 	return FALSE;
 }
@@ -410,27 +386,6 @@ efh_free_cache (struct _EMFormatHTMLCache *efhc)
 	g_free (efhc);
 }
 
-static void
-efh_gtkhtml_destroy (GtkHTML *html,
-                     EMFormatHTML *efh)
-{
-	if (efh->priv->format_timeout_id != 0) {
-		g_source_remove (efh->priv->format_timeout_id);
-		efh->priv->format_timeout_id = 0;
-		mail_msg_unref (efh->priv->format_timeout_msg);
-		efh->priv->format_timeout_msg = NULL;
-	}
-
-	/* This probably works ... */
-	if (efh->priv->format_id != -1)
-		mail_msg_cancel (efh->priv->format_id);
-
-	if (efh->priv->web_view != NULL) {
-		g_object_unref (efh->priv->web_view);
-		efh->priv->web_view = NULL;
-	}
-}
-
 static struct _EMFormatHTMLCache *
 efh_insert_cache (EMFormatHTML *efh,
                   const gchar *partid)
@@ -647,13 +602,29 @@ static void
 efh_finalize (GObject *object)
 {
 	EMFormatHTML *efh = EM_FORMAT_HTML (object);
+	EMFormatHTMLPrivate *priv = efh->priv;
 
 	em_format_html_clear_pobject (efh);
-	efh_gtkhtml_destroy (GTK_HTML (efh->priv->web_view), efh);
 
-	g_hash_table_destroy (efh->priv->text_inline_parts);
+	if (priv->format_timeout_id != 0) {
+		g_source_remove (priv->format_timeout_id);
+		priv->format_timeout_id = 0;
+		mail_msg_unref (priv->format_timeout_msg);
+		priv->format_timeout_msg = NULL;
+	}
 
-	g_mutex_free (efh->priv->lock);
+	/* This probably works ... */
+	if (priv->format_id != -1)
+		mail_msg_cancel (priv->format_id);
+
+	if (priv->web_view != NULL) {
+		g_object_unref (priv->web_view);
+		efh->priv->web_view = NULL;
+	}
+
+	g_hash_table_destroy (priv->text_inline_parts);
+
+	g_mutex_free (priv->lock);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -670,8 +641,7 @@ efh_format_clone (EMFormat *emf,
 	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
 	struct _format_msg *m;
 
-	/* How to sub-class ?  Might need to adjust api ... */
-
+	/* No webview, no need to format anything */
 	if (efh->priv->web_view == NULL)
 		return;
 
@@ -738,8 +708,8 @@ efh_format_error (EMFormat *emf,
 
 static void
 efh_format_source (EMFormat *emf,
-                   CamelStream *stream,
-                   CamelMimePart *part,
+		   CamelStream *stream,
+		   CamelMimePart *part,
                    GCancellable *cancellable)
 {
 	CamelStream *filtered_stream;
@@ -757,10 +727,10 @@ efh_format_source (EMFormat *emf,
 	g_object_unref (filter);
 
 	camel_stream_write_string (
-		stream, "<table><tr><td><tt>", cancellable, NULL);
+		stream, "<code class=\"pre\">", cancellable, NULL);
 	em_format_format_text (emf, filtered_stream, dw, cancellable);
 	camel_stream_write_string (
-		stream, "</tt></td></tr></table>", cancellable, NULL);
+		stream, "</code>", cancellable, NULL);
 
 	g_object_unref (filtered_stream);
 }
@@ -1021,18 +991,15 @@ efh_init (EMFormatHTML *efh,
 	web_view = g_object_new (class->html_widget_type, NULL);
 	efh->priv->web_view = g_object_ref_sink (web_view);
 
-#if 0  /* WEBKIT */
-	gtk_html_set_blocking (GTK_HTML (web_view), FALSE);
-	gtk_html_set_caret_first_focus_anchor (
-		GTK_HTML (web_view), EFM_MESSAGE_START_ANAME);
-	gtk_html_set_default_content_type (
-		GTK_HTML (web_view), "text/html; charset=utf-8");
-	e_web_view_set_editable (web_view, FALSE);
-
 	g_signal_connect (
-		web_view, "object-requested",
-		G_CALLBACK (efh_object_requested), efh);
-#endif
+		web_view, "resource-request-starting",
+		G_CALLBACK (efh_resource_requested), efh);
+	g_signal_connect (
+		web_view, "create-plugin-widget",
+		G_CALLBACK (efh_create_plugin_widget), efh);
+	g_signal_connect (
+		web_view, "frame-created",
+		G_CALLBACK (efh_webview_frame_created), efh);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
 	gdk_color_parse ("#eeeeee", color);
@@ -1393,15 +1360,15 @@ em_format_html_add_pobject (EMFormatHTML *efh,
 }
 
 EMFormatHTMLPObject *
-em_format_html_find_pobject (EMFormatHTML *emf,
+em_format_html_find_pobject (EMFormatHTML *efh,
                              const gchar *classid)
 {
 	GList *link;
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (emf), NULL);
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
 	g_return_val_if_fail (classid != NULL, NULL);
 
-	link = g_queue_peek_head_link (&emf->pending_object_list);
+	link = g_queue_peek_head_link (&efh->pending_object_list);
 
 	while (link != NULL) {
 		EMFormatHTMLPObject *pw = link->data;
@@ -1416,15 +1383,15 @@ em_format_html_find_pobject (EMFormatHTML *emf,
 }
 
 EMFormatHTMLPObject *
-em_format_html_find_pobject_func (EMFormatHTML *emf,
+em_format_html_find_pobject_func (EMFormatHTML *efh,
                                   CamelMimePart *part,
                                   EMFormatHTMLPObjectFunc func)
 {
 	GList *link;
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (emf), NULL);
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
 
-	link = g_queue_peek_head_link (&emf->pending_object_list);
+	link = g_queue_peek_head_link (&efh->pending_object_list);
 
 	while (link != NULL) {
 		EMFormatHTMLPObject *pw = link->data;
@@ -1439,13 +1406,13 @@ em_format_html_find_pobject_func (EMFormatHTML *emf,
 }
 
 void
-em_format_html_remove_pobject (EMFormatHTML *emf,
+em_format_html_remove_pobject (EMFormatHTML *efh,
                                EMFormatHTMLPObject *pobject)
 {
-	g_return_if_fail (EM_IS_FORMAT_HTML (emf));
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 	g_return_if_fail (pobject != NULL);
 
-	g_queue_remove (&emf->pending_object_list, pobject);
+	g_queue_remove (&efh->pending_object_list, pobject);
 
 	if (pobject->free != NULL)
 		pobject->free (pobject);
@@ -1455,48 +1422,106 @@ em_format_html_remove_pobject (EMFormatHTML *emf,
 }
 
 void
-em_format_html_clear_pobject (EMFormatHTML *emf)
+em_format_html_clear_pobject (EMFormatHTML *efh)
 {
-	g_return_if_fail (EM_IS_FORMAT_HTML (emf));
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	while (!g_queue_is_empty (&emf->pending_object_list)) {
+	while (!g_queue_is_empty (&efh->pending_object_list)) {
 		EMFormatHTMLPObject *pobj;
 
-		pobj = g_queue_pop_head (&emf->pending_object_list);
-		em_format_html_remove_pobject (emf, pobj);
+		pobj = g_queue_pop_head (&efh->pending_object_list);
+		em_format_html_remove_pobject (efh, pobj);
 	}
 }
 
 struct _EMFormatHTMLJob *
-em_format_html_job_new (EMFormatHTML *emfh,
+em_format_html_job_new (EMFormatHTML *efh,
                         void (*callback) (struct _EMFormatHTMLJob *job,
                                           GCancellable *cancellable),
                         gpointer data)
 {
+	EMFormat *emf = EM_FORMAT (efh);
 	struct _EMFormatHTMLJob *job = g_malloc0 (sizeof (*job));
 
-	job->format = emfh;
-	job->puri_level = ((EMFormat *) emfh)->pending_uri_level;
+	job->format = efh;
+	job->puri_level = emf->pending_uri_level;
 	job->callback = callback;
 	job->u.data = data;
-	if (((EMFormat *) emfh)->base)
-		job->base = camel_url_copy (((EMFormat *) emfh)->base);
+
+	if (emf->base)
+		job->base = camel_url_copy (emf->base);
 
 	return job;
 }
 
 void
-em_format_html_job_queue (EMFormatHTML *emfh,
+em_format_html_job_queue (EMFormatHTML *efh,
                           struct _EMFormatHTMLJob *job)
 {
-	g_mutex_lock (emfh->priv->lock);
-	g_queue_push_tail (&emfh->priv->pending_jobs, job);
-	g_mutex_unlock (emfh->priv->lock);
+	g_mutex_lock (efh->priv->lock);
+	g_queue_push_tail (&efh->priv->pending_jobs, job);
+	g_mutex_unlock (efh->priv->lock);
+
+	/* If no formatting thread is running, then start one */
+	if (efh->priv->format_id == -1) {
+		struct _format_msg *m;
+
+		d(printf("job queued, launching a new formatter thread\n"));
+
+		m = mail_msg_new (&efh_format_info);
+		m->format = g_object_ref (efh);
+
+		mail_msg_unordered_push (m);
+	} else {
+		d(printf("job queued, a formatter thread already running\n"));
+	}
 }
 
 /* ********************************************************************** */
 
 static void
+emfh_format_email (struct _EMFormatHTMLJob *job,
+				   GCancellable *cancellable)
+{
+	EMFormat *format;
+
+	d(printf(" running format_email task\n"));
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	format = EM_FORMAT (job->format);
+
+	if (format->mode == EM_FORMAT_MODE_SOURCE) {
+		em_format_format_source (
+			format, job->stream,
+			CAMEL_MIME_PART (job->u.msg), cancellable);
+	} else {
+		const EMFormatHandler *handle;
+		const gchar *mime_type;
+
+		mime_type = "x-evolution/message/prefix";
+		handle = em_format_find_handler (format, mime_type);
+
+		if (handle != NULL)
+			handle->handler (
+				format, job->stream,
+				CAMEL_MIME_PART (job->u.msg), handle,
+				cancellable, FALSE);
+
+		mime_type = "x-evolution/message/rfc822";
+		handle = em_format_find_handler (format, mime_type);
+
+		if (handle != NULL)
+			handle->handler (
+				format, job->stream,
+				CAMEL_MIME_PART (job->u.msg), handle,
+				cancellable, FALSE);
+	}
+}
+
+#if 0 /* WEBKIT */
+
+static void
 emfh_getpuri (struct _EMFormatHTMLJob *job,
               GCancellable *cancellable)
 {
@@ -1587,7 +1612,7 @@ emfh_gethttp (struct _EMFormatHTMLJob *job,
 				pc_complete = ((nread * 100) / total);
 				camel_operation_progress (cancellable, pc_complete);
 			}
-			d(printf("  read %d bytes\n", n));
+			d(printf("  read %d bytes\n", (int)n));
 			if (costream && camel_stream_write (costream, buffer, n, cancellable, NULL) == -1) {
 				n = -1;
 				break;
@@ -1615,95 +1640,185 @@ badurl:
 	g_free (job->u.uri);
 }
 
-/* ********************************************************************** */
+#endif /* WEBKIT */
 
+/* ********************************************************************** */
 static void
-efh_url_requested (GtkHTML *html, const gchar *url, GtkHTMLStream *handle, EMFormatHTML *efh)
+efh_resource_requested (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebResource *resource,
+			WebKitNetworkRequest *request, WebKitNetworkResponse *response, gpointer user_data)
 {
+	EMFormatHTML *efh = user_data;
 	EMFormatPURI *puri;
-	struct _EMFormatHTMLJob *job = NULL;
+	const gchar *p_uri = webkit_network_request_get_uri (request);
+	const gchar *uri;
+
+	d(printf("URI requested '%s'\n", p_uri));
 
-	d(printf("url requested, html = %p, url '%s'\n", html, url));
+	if (g_str_has_prefix (p_uri, "puri:")) {
+		uri = &p_uri[5];
+	} else {
+		uri = p_uri;
+	}
 
-	puri = em_format_find_visible_puri ((EMFormat *) efh, url);
+	puri = em_format_find_puri (EM_FORMAT (efh), uri);
 	if (puri) {
-		CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *) puri->part);
-		CamelContentType *ct = dw?dw->mime_type:NULL;
-
-		/* GtkHTML only handles text and images.
-		   application/octet-stream parts are the only ones
-		   which are snooped for other content.  So only try
-		   to pass these to it - any other types are badly
-		   formed or intentionally malicious emails.  They
-		   will still show as attachments anyway */
-
-		if (ct && (camel_content_type_is(ct, "text", "*")
-			   || camel_content_type_is(ct, "image", "*")
-			   || camel_content_type_is(ct, "application", "octet-stream"))) {
+		CamelDataWrapper *dw;
+		CamelContentType *ct;
+
+		dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
+		if (!dw) {
+			d(printf("PURI does not contain valid mimepart, skipping\n"));
+			return;
+		}
+
+		ct = camel_data_wrapper_get_mime_type_field (dw);
+
+		if (ct && (camel_content_type_is (ct, "text", "*")
+			   || camel_content_type_is (ct, "image", "*")
+			   || camel_content_type_is (ct, "application", "octet-stream"))) {
+
+			gchar *data, *b64;
+			gchar *cts = camel_data_wrapper_get_mime_type (dw);
+			CamelStream *stream;
+			GByteArray *ba;
+
 			puri->use_count++;
 
-			d(printf(" adding puri job\n"));
-			job = em_format_html_job_new (efh, emfh_getpuri, puri);
+			stream = camel_stream_mem_new ();
+
+			camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
+			ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
+			b64 = g_base64_encode ((guchar*) ba->data, ba->len);
+			if (camel_content_type_is (ct, "text", "*")) {
+				const gchar *charset = camel_content_type_param (ct, "charset");
+				data = g_strdup_printf ("data:%s;charset=%s;base64,%s", cts,
+					charset ? charset : "utf-8", b64);
+			} else {
+				data = g_strdup_printf ("data:%s;base64,%s", cts, b64);
+			}
+
+			webkit_network_request_set_uri (request, data);
+			g_free (b64);
+			g_free (data);
+			g_free (cts);
+			g_object_unref (stream);
+
 		} else {
-			d(printf(" part is unknown type '%s', not using\n", ct?camel_content_type_format(ct):"<unset>"));
-			gtk_html_stream_close (handle, GTK_HTML_STREAM_ERROR);
+			d(printf(" part is unknown type '%s', not using\n", ct ? camel_content_type_format(ct) : "<unset>"));
 		}
-	} else if (g_ascii_strncasecmp(url, "http:", 5) == 0 || g_ascii_strncasecmp(url, "https:", 6) == 0) {
-		d(printf(" adding job, get %s\n", url));
-		job = em_format_html_job_new (efh, emfh_gethttp, g_strdup (url));
-	} else if  (g_str_has_prefix (url, "file://")) {
+	} else if (g_str_has_prefix(uri, "http:") || g_str_has_prefix (uri, "https:")) {
+		d(printf(" Remote URI requetsed, webkit handling it\n"));
+	} else if  (g_str_has_prefix (uri, "file:")) {
 		gchar *data = NULL;
 		gsize length = 0;
 		gboolean status;
 		gchar *path;
 
-		path = g_filename_from_uri (url, NULL, NULL);
-		g_return_if_fail (path != NULL);
+		path = g_filename_from_uri (uri, NULL, NULL);
+		if (!path)
+			return;
+
+		d(printf(" Local URI requested, loading file '%s'\n", path));
 
 		status = g_file_get_contents (path, &data, &length, NULL);
-		if (status)
-			gtk_html_stream_write (handle, data, length);
+		if (status) {
+			gchar *b64, *new_uri;
+			gchar *ct;
 
-		gtk_html_stream_close (handle, status ? GTK_HTML_STREAM_OK : GTK_HTML_STREAM_ERROR);
+			b64 = g_base64_encode ((guchar*) data, length);
+			ct = g_content_type_guess (path, NULL, 0, NULL);
+
+			new_uri =  g_strdup_printf ("data:%s;base64,%s", ct, b64);
+			webkit_network_request_set_uri (request, new_uri);
+
+			g_free (b64);
+			g_free (new_uri);
+			g_free (ct);
+		}
 		g_free (data);
 		g_free (path);
 	} else {
-		d(printf("HTML Includes reference to unknown uri '%s'\n", url));
-		gtk_html_stream_close (handle, GTK_HTML_STREAM_ERROR);
+		d(printf("HTML Includes reference to unknown uri '%s'\n", uri));
 	}
 
-	if (job) {
-		job->stream = em_html_stream_new (html, handle);
-		em_format_html_job_queue (efh, job);
-	}
-
-	g_signal_stop_emission_by_name (html, "url-requested");
+	g_signal_stop_emission_by_name (web_view, "resource-request-starting");
 }
 
-static gboolean
-efh_object_requested (GtkHTML *html,
-                      GtkHTMLEmbedded *eb,
-                      EMFormatHTML *efh)
+static GtkWidget*
+efh_create_plugin_widget (WebKitWebView *web_view,
+						  gchar *mime_type,
+						  gchar *uri,
+						  GHashTable *param,
+						  gpointer user_data)
 {
+	EMFormatHTML *efh = user_data;
 	EMFormatHTMLPObject *pobject;
-	gint res = FALSE;
+	const gchar *classid;
 
-	if (eb->classid == NULL)
-		return FALSE;
+	classid = g_hash_table_lookup (param, "data");
+	if (!classid) {
+		d(printf("Object does not have class-id, bailing.\n"));
+		return NULL;
+	}
 
-	pobject = em_format_html_find_pobject (efh, eb->classid);
+	pobject = em_format_html_find_pobject (efh, classid);
 	if (pobject) {
+		GtkWidget *widget;
+
+		d(printf("Creating widget for object '%s\n'", classid));
+
 		/* This stops recursion of the part */
 		g_queue_remove (&efh->pending_object_list, pobject);
-		res = pobject->func (efh, eb, pobject);
+		widget = pobject->func (efh, pobject);
 		g_queue_push_head (&efh->pending_object_list, pobject);
+
+		return widget;
 	} else {
-		d(printf("HTML Includes reference to unknown object '%s'\n", eb->classid));
+		d(printf("HTML includes reference to unknown object '%s'\n", uri));
+		return NULL;
 	}
+}
+
+static void
+efh_webview_frame_loaded (GObject *object,
+						  GParamSpec *pspec,
+						  gpointer user_data)
+{
+	WebKitWebFrame *frame = WEBKIT_WEB_FRAME (object);
+	WebKitWebView *web_view;
+	const gchar *frame_name;
+	gchar *script;
+	GValue val = {0};
+
+	/* Don't do anything until all content of the frame is loaded*/
+	if (webkit_web_frame_get_load_status (frame) != WEBKIT_LOAD_FINISHED)
+		return;
+
+	web_view = webkit_web_frame_get_web_view (frame);
+	frame_name = webkit_web_frame_get_name (frame);
+
+	/* Get total height of the document inside the frame */
+	e_web_view_frame_exec_script (E_WEB_VIEW (web_view), frame_name, "document.body.offsetHeight;", &val);
 
-	return res;
+	/* Change height of the frame so that entire content is visible */
+	script = g_strdup_printf ("window.document.getElementById(\"%s\").height=%d;", frame_name, (int)g_value_get_double (&val));
+	e_web_view_exec_script (E_WEB_VIEW (web_view), script, NULL);
+	g_free (script);
+}
+
+
+static void
+efh_webview_frame_created (WebKitWebView *web_view,
+						   WebKitWebFrame *frame,
+						   gpointer user_data)
+{
+	if (frame != webkit_web_view_get_main_frame (web_view)) {
+
+		/* Get notified when all content of frame is loaded */
+		g_signal_connect (frame,  "notify::load-status",
+			G_CALLBACK (efh_webview_frame_loaded), NULL);
+	}
 }
-#endif
 
 /* ********************************************************************** */
 #include "em-format/em-inline-filter.h"
@@ -1935,7 +2050,7 @@ efh_text_plain (EMFormat *emf,
 			content = g_strdup_printf (
 				"<div style=\"border: solid #%06x 1px; "
 				"background-color: #%06x; padding: 10px; "
-				"color: #%06x;\">\n<tt>\n" EFH_MESSAGE_START,
+				"color: #%06x;\">\n<div id=\"pre\">\n" EFH_MESSAGE_START,
 				e_color_to_value (
 					&efh->priv->colors[
 					EM_FORMAT_HTML_COLOR_FRAME]),
@@ -1954,7 +2069,7 @@ efh_text_plain (EMFormat *emf,
 				(CamelDataWrapper *) newpart,
 				cancellable);
 			camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL);
-			camel_stream_write_string (stream, "</tt>\n", cancellable, NULL);
+			camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
 			camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
 		} else {
 			g_string_append_printf (emf->part_id, ".inline.%d", i);
@@ -2036,9 +2151,9 @@ efh_write_text_html (EMFormat *emf,
 	fd = dup (STDOUT_FILENO);
 	out = camel_stream_fs_new_with_fd (fd);
 	printf("writing text content to frame '%s'\n", puri->cid);
-	dw = camel_medium_get_content (puri->part);
+	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
 	if (dw)
-		camel_data_wrapper_write_to_stream (dw, out);
+		camel_data_wrapper_write_to_stream_sync (dw, out, NULL, NULL);
 	g_object_unref (out);
 #endif
 	em_format_format_text (
@@ -2102,8 +2217,8 @@ efh_text_html (EMFormat *emf,
 		part, efh_write_text_html);
 	d(printf("adding iframe, location %s\n", cid));
 	content = g_strdup_printf (
-		"<iframe src=\"%s\" frameborder=0 scrolling=no>"
-		"could not get %s</iframe>\n</div>\n", cid, cid);
+		"<iframe name=\"html-frame-%s\" id=\"html-frame-%s\" src=\"puri:%s\" frameborder=0 scrolling=no width=\"100%%\" >" \
+		"Could not get %s</iframe>\n</div>\n", cid, cid, cid, cid);
 	camel_stream_write_string (stream, content, cancellable, NULL);
 	g_free (content);
 	g_free (cid);
@@ -2258,12 +2373,12 @@ efh_message_deliverystatus (EMFormat *emf,
 		CAMEL_STREAM_FILTER (filtered_stream), html_filter);
 	g_object_unref (html_filter);
 
-	camel_stream_write_string (stream, "<tt>\n" EFH_MESSAGE_START, cancellable, NULL);
+	camel_stream_write_string (stream, "<div id=\"pre\">\n" EFH_MESSAGE_START, cancellable, NULL);
 	em_format_format_text (
 		emf, filtered_stream,
 		(CamelDataWrapper *) part, cancellable);
 	camel_stream_flush (filtered_stream, cancellable, NULL);
-	camel_stream_write_string (stream, "</tt>\n", cancellable, NULL);
+	camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
 
 	camel_stream_write_string (stream, "</div>", cancellable, NULL);
 }
@@ -2310,10 +2425,9 @@ emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
 			d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
 			if (puri->func == emfh_write_related) {
 				g_string_printf (format->part_id, "%s", puri->part_id);
-				/* FIXME Not passing a GCancellable here. */
 				em_format_part (
 					format, CAMEL_STREAM (job->stream),
-					puri->part, NULL);
+					puri->part, cancellable);
 			}
 			/* else it was probably added by a previous format this loop */
 		}
@@ -2389,7 +2503,7 @@ efh_multipart_related (EMFormat *emf,
 			g_string_append_printf(emf->part_id, "related.%d", i);
 			em_format_add_puri (emf, sizeof (EMFormatPURI), NULL, body_part, emfh_write_related);
 			g_string_truncate (emf->part_id, partidlen);
-			d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
+			d(printf(" part '%s' added\n", camel_mime_part_get_content_id (body_part)));
 		}
 	}
 
@@ -3204,6 +3318,8 @@ efh_format_headers (EMFormatHTML *efh,
 				emf, sizeof (EMFormatPURI),
 				classid, part, efh_write_image);
 			g_object_unref (part);
+			g_free (classid);
+			g_free (face_header_value);
 		}
 
 		if (have_icon && efh->show_icon) {
@@ -3264,6 +3380,25 @@ efh_format_message (EMFormat *emf,
 
 	buffer = g_string_sized_new (1024);
 
+	g_string_append_printf (buffer,
+		"<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"  \
+		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n" \
+		"<link type=\"text/css\" rel=\"stylesheet\" href=\"file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\n" \
+		"<style type=\"text/css\">\n" \
+		"  table th { color: #000; font-weight: bold; }\n" \
+		"</style>\n" \
+		"<script type=\"text/javascript\">\n" \
+		"function body_loaded() { window.location.hash=\"" EFM_MESSAGE_START_ANAME "\"; }" \
+		"</script>\n" \
+		"</body>\n" \
+		"<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6 onLoad=\"body_loaded();\">",
+		e_color_to_value (
+			&efh->priv->colors[
+			EM_FORMAT_HTML_COLOR_BODY]),
+		e_color_to_value (
+			&efh->priv->colors[
+			EM_FORMAT_HTML_COLOR_HEADER]));
+
 	if (emf->message != (CamelMimeMessage *) part)
 		g_string_append (buffer, "<blockquote>\n");
 
@@ -3289,6 +3424,8 @@ efh_format_message (EMFormat *emf,
 		camel_stream_write_string (
 			stream, "</blockquote>\n", cancellable, NULL);
 
+	camel_stream_write_string (stream, "</body></html", cancellable, NULL);
+
 	camel_cipher_validity_free (emf->valid);
 
 	emf->valid = save;
diff --git a/mail/em-format-html.h b/mail/em-format-html.h
index ab66504..62f5075 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -31,7 +31,6 @@
 #include <em-format/em-format.h>
 #include <mail/e-mail-enums.h>
 #include <misc/e-web-view.h>
-#include <gtkhtml/gtkhtml-embedded.h>
 
 /* Standard GObject macros */
 #define EM_TYPE_FORMAT_HTML \
@@ -136,9 +135,8 @@ struct _EMFormatHTMLJob {
 /* Pending object (classid: url) */
 typedef struct _EMFormatHTMLPObject EMFormatHTMLPObject;
 
-typedef gboolean
+typedef GtkWidget*
 		(*EMFormatHTMLPObjectFunc)	(EMFormatHTML *md,
-						 GtkHTMLEmbedded *eb,
 						 EMFormatHTMLPObject *pobject);
 
 /**
@@ -204,7 +202,7 @@ struct _EMFormatHTMLPObject {
  * Most of these fields are private or read-only.
  *
  * The base HTML formatter object.  This object drives HTML generation
- * into a GtkHTML parser.  It also handles text to HTML conversion,
+ * into a WebKit parser.  It also handles text to HTML conversion,
  * multipart/related objects and inline images.
  **/
 struct _EMFormatHTML {
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index d99fb81..2633b60 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -22,6 +22,8 @@
 
 #include "e-web-view.h"
 
+#include <JavaScriptCore/JavaScript.h>
+
 #include <string.h>
 #include <glib/gi18n-lib.h>
 
@@ -1066,6 +1068,56 @@ web_view_load_string (EWebView *web_view,
 		string, "text/html", "UTF-8", "file://");
 }
 
+static void
+web_view_load_uri (EWebView *web_view,
+		   const gchar *uri)
+{
+	if (uri == NULL)
+		uri = "about:blank";
+
+	webkit_web_view_load_uri (
+		WEBKIT_WEB_VIEW (web_view), uri);
+}
+
+static void
+web_view_frame_load_string (EWebView *web_view,
+			    const gchar *frame_name,
+			    const gchar *string)
+{
+	WebKitWebFrame *main_frame, *frame;
+
+	if (string == NULL)
+		string = "";
+
+	main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+	if (main_frame) {
+		frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+		if (frame)
+			webkit_web_frame_load_string (
+				frame, string, "text/html", "UTF-8", "file://");
+	}
+}
+
+static void
+web_view_frame_load_uri (EWebView *web_view,
+			 const gchar *frame_name,
+			 const gchar *uri)
+{
+	WebKitWebFrame *main_frame, *frame;
+
+	if (uri == NULL)
+		uri = "about:blank";
+
+	main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+	if (main_frame) {
+		frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+		if (frame)
+			webkit_web_frame_load_uri (frame, uri);
+	}
+}
+
 static gboolean
 web_view_popup_event (EWebView *web_view,
                       GdkEventButton *event,
@@ -1366,6 +1418,9 @@ e_web_view_class_init (EWebViewClass *class)
 	class->hovering_over_link = web_view_hovering_over_link;
 	class->link_clicked = web_view_link_clicked;
 	class->load_string = web_view_load_string;
+	class->load_uri = web_view_load_uri;
+	class->frame_load_string = web_view_frame_load_string;
+	class->frame_load_uri = web_view_frame_load_uri;
 	class->popup_event = web_view_popup_event;
 	class->stop_loading = web_view_stop_loading;
 	class->update_actions = web_view_update_actions;
@@ -1758,6 +1813,185 @@ e_web_view_load_string (EWebView *web_view,
 	class->load_string (web_view, string);
 }
 
+void
+e_web_view_load_uri (EWebView *web_view,
+		     const gchar *uri)
+{
+	EWebViewClass *class;
+
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	class = E_WEB_VIEW_GET_CLASS (web_view);
+	g_return_if_fail (class->load_uri != NULL);
+
+	class->load_uri (web_view, uri);
+}
+
+const gchar*
+e_web_view_get_uri (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+	return webkit_web_view_get_uri (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_frame_load_string (EWebView *web_view,
+			      const gchar *frame_name,
+			      const gchar *string)
+{
+	EWebViewClass *class;
+
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+	g_return_if_fail (frame_name != NULL);
+
+	class = E_WEB_VIEW_GET_CLASS (web_view);
+	g_return_if_fail (class->frame_load_string != NULL);
+
+	class->frame_load_string (web_view, frame_name, string);
+}
+
+void
+e_web_view_frame_load_uri (EWebView *web_view,
+			   const gchar *frame_name,
+			   const gchar *uri)
+{
+	EWebViewClass *class;
+
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+	g_return_if_fail (frame_name != NULL);
+
+	class = E_WEB_VIEW_GET_CLASS (web_view);
+	g_return_if_fail (class->frame_load_uri != NULL);
+
+	class->frame_load_uri (web_view, frame_name, uri);
+}
+
+const gchar*
+e_web_view_frame_get_uri (EWebView *web_view,
+			  const gchar *frame_name)
+{
+	WebKitWebFrame *main_frame, *frame;
+
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+	g_return_val_if_fail (frame_name != NULL, NULL);
+
+	main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+	if (main_frame) {
+		frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+		if (frame)
+			return webkit_web_frame_get_uri (frame);
+	}
+
+	return NULL;
+}
+
+gchar*
+e_web_view_get_html (EWebView *web_view)
+{
+	GValue html = {0};
+
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+	if (e_web_view_exec_script (web_view, "return document.documentElement.innerHTML;", &html) == G_TYPE_STRING)
+		return g_strdup (g_value_get_string (&html));
+	else
+		return NULL;
+}
+
+GType
+e_web_view_exec_script (EWebView *web_view, const gchar *script, GValue *value)
+{
+	WebKitWebFrame *main_frame;
+
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), G_TYPE_INVALID);
+	g_return_val_if_fail (script != NULL, G_TYPE_INVALID);
+
+	main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+
+	return e_web_view_frame_exec_script (web_view,
+		webkit_web_frame_get_name (main_frame),
+		script, value);
+}
+
+GType
+e_web_view_frame_exec_script (EWebView *web_view, const gchar *frame_name, const gchar *script, GValue *value)
+{
+	WebKitWebFrame *main_frame, *frame;
+	JSGlobalContextRef context;
+	JSValueRef js_value, error = NULL;
+	JSType js_type;
+	JSStringRef js_script;
+	JSStringRef js_str;
+	size_t str_len;
+	gchar *str;
+
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), G_TYPE_INVALID);
+	g_return_val_if_fail (script != NULL, G_TYPE_INVALID);
+
+	main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+	frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+	context = webkit_web_frame_get_global_context (frame);
+
+	js_script = JSStringCreateWithUTF8CString (script);
+	js_value = JSEvaluateScript (context, js_script, NULL, NULL, 0, &error);
+	JSStringRelease (js_script);
+
+	if (error) {
+		gchar *msg;
+		js_str = JSValueToStringCopy (context, error, NULL);
+		str_len = JSStringGetLength (js_str);
+
+		msg = g_malloc (str_len + 1);
+		JSStringGetUTF8CString (js_str, msg, str_len + 1);
+		JSStringRelease (js_str);
+
+		g_message ("JavaScript Execution Failed: %s", msg);
+		g_free (msg);
+
+		return G_TYPE_INVALID;
+	}
+
+	if (!value)
+		return G_TYPE_NONE;
+
+	js_type = JSValueGetType (context, js_value);
+	switch (js_type) {
+		case kJSTypeBoolean:
+			g_value_init (value, G_TYPE_BOOLEAN);
+			g_value_set_boolean (value, JSValueToBoolean (context, js_value));
+			break;
+		case kJSTypeNumber:
+			g_value_init (value, G_TYPE_DOUBLE);
+			g_value_set_double(value, JSValueToNumber (context, js_value, NULL));
+			break;
+		case kJSTypeString:
+			js_str = JSValueToStringCopy (context, js_value, NULL);
+			str_len = JSStringGetLength (js_str);
+			str = g_malloc (str_len + 1);
+			JSStringGetUTF8CString (js_str, str, str_len + 1);
+			JSStringRelease (js_str);
+			g_value_init (value, G_TYPE_STRING);
+			g_value_set_string (value, str);
+			g_free (str);
+			break;
+		case kJSTypeObject:
+			g_value_init (value, G_TYPE_OBJECT);
+			g_value_set_object (value, JSValueToObject (context, js_value, NULL));
+			break;
+		case kJSTypeNull:
+			g_value_init (value, G_TYPE_POINTER);
+			g_value_set_pointer (value, NULL);
+			break;
+		case kJSTypeUndefined:
+			break;
+	}
+
+	return G_VALUE_TYPE (value);
+}
+
 gboolean
 e_web_view_get_animate (EWebView *web_view)
 {
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index 432dc7e..48a7cc2 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -76,7 +76,14 @@ struct _EWebViewClass {
 						 const gchar *uri);
 	void		(*load_string)		(EWebView *web_view,
 						 const gchar *load_string);
-
+	void		(*load_uri)		(EWebView *web_view,
+						 const gchar *load_uri);
+	void		(*frame_load_string)	(EWebView *web_view,
+						 const gchar *frame_name,
+						 const gchar *string);
+	void		(*frame_load_uri)	(EWebView *web_view,
+						 const gchar *frame_name,
+						 const gchar *uri);
 	/* Signals */
 	gboolean	(*popup_event)		(EWebView *web_view,
 						 GdkEventButton *event,
@@ -94,6 +101,25 @@ GtkWidget *	e_web_view_new			(void);
 void		e_web_view_clear		(EWebView *web_view);
 void		e_web_view_load_string		(EWebView *web_view,
 						 const gchar *string);
+void		e_web_view_load_uri		(EWebView *web_view,
+						 const gchar *uri);
+const gchar*	e_web_view_get_uri		(EWebView *web_view);
+void		e_web_view_frame_load_string	(EWebView *web_view,
+						 const gchar *frame_name,
+						 const gchar *string);
+void		e_web_view_frame_load_uri	(EWebView *web_view,
+						 const gchar *frame_name,
+						 const gchar *uri);
+const gchar*	e_web_view_frame_get_uri	(EWebView *web_view,
+						 const gchar *frame_name);
+GType		e_web_view_exec_script		(EWebView *web_view,
+						 const gchar *script,
+						 GValue *value);
+GType		e_web_view_frame_exec_script	(EWebView *web_view,
+						 const gchar *frame_name,
+						 const gchar *script,
+						 GValue *value);
+gchar *		e_web_view_get_html		(EWebView *web_view);
 gboolean	e_web_view_get_animate		(EWebView *web_view);
 void		e_web_view_set_animate		(EWebView *web_view,
 						 gboolean animate);



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