[evolution/webkit: 7/146] Port EMFormatHTML to WebKit
- From: Dan VrÃtil <dvratil src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/webkit: 7/146] Port EMFormatHTML to WebKit
- Date: Thu, 9 Feb 2012 14:19:02 +0000 (UTC)
commit 2d1b9abeaa7981732c0aa4b78d2371bb30325924
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.
addressbook/importers/Makefile.am | 4 -
data/webview.css | 5 +
mail/Makefile.am | 2 -
mail/e-mail-display.c | 18 --
mail/e-mail-reader.c | 14 +-
mail/em-format-html-display.c | 65 ++---
mail/em-format-html.c | 583 ++++++++++++++++++++++---------------
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 ++-
12 files changed, 645 insertions(+), 573 deletions(-)
---
diff --git a/addressbook/importers/Makefile.am b/addressbook/importers/Makefile.am
index 574d17d..19f6892 100644
--- a/addressbook/importers/Makefile.am
+++ b/addressbook/importers/Makefile.am
@@ -24,12 +24,8 @@ libevolution_addressbook_importers_la_LIBADD = \
$(top_builddir)/e-util/libeutil.la \
$(top_builddir)/addressbook/util/libeabutil.la \
$(top_builddir)/widgets/misc/libemiscwidgets.la \
-<<<<<<< HEAD
$(EVOLUTION_DATA_SERVER_LIBS) \
- $(GTKHTML_LIBS)
-=======
$(GNOME_PLATFORM_LIBS) \
$(IMPORTERS_LIBS)
->>>>>>> Preliminary WebKit conversion.
-include $(top_srcdir)/git.mk
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 b80d56c..89c0d33 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -81,7 +81,6 @@ mailinclude_HEADERS = \
em-format-html-display.h \
em-format-html-print.h \
em-format-html.h \
- em-html-stream.h \
em-search-context.h \
em-subscription-editor.h \
em-sync-stream.h \
@@ -146,7 +145,6 @@ libevolution_mail_la_SOURCES = \
em-format-html-display.c \
em-format-html-print.c \
em-format-html.c \
- em-html-stream.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 7461e59..3e33bac 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -220,23 +220,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_GET_PRIVATE (web_view);
- 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 (e_mail_display_parent_class)->
- load_string (web_view, string);
-}
-
-static void
mail_display_url_requested (GtkHTML *html,
const gchar *uri,
GtkHTMLStream *stream)
@@ -362,7 +345,6 @@ e_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 ef2449e..3b5d2cb 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2683,19 +2683,27 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
GCancellable *cancellable;
EActivity *activity;
EWebView *web_view;
- gchar *string;
+ gchar *string, *html;
web_view = e_preview_pane_get_web_view (preview_pane);
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 a0e5086..b87991f 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>
@@ -113,8 +110,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 {
@@ -126,12 +123,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;
@@ -362,12 +354,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;
@@ -378,23 +368,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
@@ -495,7 +479,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>"
@@ -587,7 +571,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);
@@ -636,7 +620,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);
@@ -1094,10 +1078,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;
@@ -1135,7 +1118,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;
@@ -1171,7 +1154,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
@@ -1187,13 +1169,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 */
- if (efhd->priv->attachment_expanded) {
+ /* 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
@@ -1243,9 +1226,8 @@ efhd_bar_resize (EMFormatHTML *efh,
}
}
-static gboolean
+static GtkWidget*
efhd_add_bar (EMFormatHTML *efh,
- GtkHTMLEmbedded *eb,
EMFormatHTMLPObject *pobject)
{
EMFormatHTMLDisplayPrivate *priv;
@@ -1261,17 +1243,16 @@ efhd_add_bar (EMFormatHTML *efh,
priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efh);
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
@@ -1296,7 +1277,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);
@@ -1332,10 +1313,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;
@@ -1352,7 +1332,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);
@@ -1426,10 +1406,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 6bf4fbe..74194cd 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -52,9 +52,6 @@
#include <shell/e-shell.h>
-#include <gtkhtml/gtkhtml.h>
-#include <gtkhtml/gtkhtml-stream.h>
-
#include <glib/gi18n.h>
#include <libemail-utils/mail-mt.h>
@@ -64,7 +61,6 @@
#include <libemail-engine/mail-config.h>
#include "em-format-html.h"
-#include "em-html-stream.h"
#include "em-utils.h"
#define EM_FORMAT_HTML_GET_PRIVATE(obj) \
@@ -73,7 +69,7 @@
#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 {
@@ -126,7 +122,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,
@@ -159,7 +174,6 @@ struct _format_msg {
EMFormatHTML *format;
EMFormat *format_source;
- EMHTMLStream *estream;
CamelFolder *folder;
gchar *uid;
CamelMimeMessage *message;
@@ -178,11 +192,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;
@@ -190,62 +202,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);
@@ -253,41 +222,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
@@ -306,12 +261,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);
@@ -333,12 +282,12 @@ static gboolean
efh_format_helper (struct _format_msg *m,
gboolean async)
{
- 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);
@@ -355,55 +304,50 @@ efh_format_helper (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;
if (async) {
mail_msg_unordered_push (m);
@@ -412,8 +356,8 @@ efh_format_helper (struct _format_msg *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;
}
@@ -426,27 +370,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)
@@ -663,13 +586,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;
+ }
+
+ /* 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 (efh->priv->lock);
+ g_mutex_free (priv->lock);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -713,8 +652,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;
@@ -781,8 +719,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;
@@ -800,10 +738,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);
}
@@ -1063,18 +1001,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);
@@ -1435,15 +1370,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;
@@ -1458,15 +1393,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;
@@ -1481,13 +1416,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);
@@ -1497,48 +1432,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)
{
@@ -1629,7 +1622,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;
@@ -1657,95 +1650,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;
}
+}
- return res;
+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);
+
+ /* 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"
@@ -1970,7 +2053,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]),
@@ -1989,7 +2072,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);
@@ -2071,9 +2154,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 (
@@ -2137,8 +2220,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);
@@ -2293,12 +2376,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);
}
@@ -2345,10 +2428,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 */
}
@@ -2424,7 +2506,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)));
}
}
@@ -3239,6 +3321,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) {
@@ -3299,6 +3383,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");
@@ -3324,6 +3427,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 bc6a171..d6dd4f9 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -30,7 +30,6 @@
#include <em-format/em-format.h>
#include <misc/e-web-view.h>
-#include <gtkhtml/gtkhtml-embedded.h>
#include <libemail-engine/e-mail-enums.h>
/* Standard GObject macros */
@@ -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 1944570..077cffe 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]