[evolution/wip/webkit2: 117/128] Apply patches from wip-webkit2 on top of the master



commit 978883feb7a2329830b27d76462fb0866933e5bc
Author: Tomas Popela <tpopela redhat com>
Date:   Mon Sep 8 11:12:18 2014 +0200

    Apply patches from wip-webkit2 on top of the master
    
    The main development will be done in this branch wip/webkit2 (based on 3.13.x) the
    wip-webkit2 branch will be left on 3.11.x as playground for various
    things as it doesn't have to WebKit based composer.

 Makefile.am                                        |    1 +
 addressbook/gui/widgets/eab-contact-display.c      |   45 +-
 addressbook/gui/widgets/eab-contact-formatter.c    |   62 -
 addressbook/gui/widgets/eab-contact-formatter.h    |    1 -
 configure.ac                                       |   19 +-
 e-util/Makefile.am                                 |    3 +
 e-util/e-dom-utils.c                               | 1280 ++++++++++++++++
 e-util/e-dom-utils.h                               |  107 ++
 e-util/e-mail-signature-preview.c                  |   69 +-
 e-util/e-search-bar.c                              |  180 ++-
 e-util/e-util.h                                    |    1 +
 e-util/e-web-view-preview.c                        |   12 +-
 e-util/e-web-view.c                                | 1480 ++++++++++++++-----
 e-util/e-web-view.h                                |   53 +-
 em-format/Makefile.am                              |    2 +
 em-format/e-mail-formatter-headers.c               |    4 +-
 em-format/e-mail-formatter.c                       |    3 +
 em-format/e-mail-meta-remove-filter.c              |  267 ++++
 em-format/e-mail-meta-remove-filter.h              |   66 +
 em-format/e-mail-part-headers.c                    |   36 +-
 em-format/e-mail-part.c                            |   10 +-
 em-format/e-mail-part.h                            |    9 +-
 mail/e-http-request.c                              |    2 +-
 mail/e-mail-display-popup-extension.c              |    5 +-
 mail/e-mail-display-popup-extension.h              |    7 +-
 mail/e-mail-display.c                              | 1450 +++++++++++++-----
 mail/e-mail-display.h                              |    6 +-
 mail/e-mail-printer.c                              |   24 +-
 mail/e-mail-reader-utils.c                         |    6 +-
 mail/e-mail-reader.c                               |   38 +-
 mail/e-mail-request.c                              |    2 +-
 modules/itip-formatter/Makefile.am                 |    5 +-
 modules/itip-formatter/e-mail-formatter-itip.c     |    2 +-
 modules/itip-formatter/e-mail-part-itip.c          |   39 +-
 .../itip-formatter/itip-view-elements-defines.h    |   65 +
 modules/itip-formatter/itip-view.c                 | 1578 +++++++++-----------
 modules/itip-formatter/itip-view.h                 |   11 +-
 .../module-itip-formatter-dom-utils.c              |  723 +++++++++
 .../module-itip-formatter-dom-utils.h              |  112 ++
 modules/itip-formatter/web-extension/Makefile.am   |   25 +
 .../module-itip-formatter-web-extension.c          |  619 ++++++++
 .../module-itip-formatter-web-extension.h          |   26 +
 modules/mail/Makefile.am                           |    2 +
 modules/mail/e-mail-shell-backend.c                |    3 +-
 modules/mail/e-mail-shell-view-private.c           |  143 ++-
 modules/mail/e-mail-shell-view-private.h           |    5 +
 modules/mail/web-extension/Makefile.am             |   23 +
 .../mail/web-extension/module-mail-web-extension.c |  141 ++
 .../mail/web-extension/module-mail-web-extension.h |   26 +
 modules/prefer-plain/Makefile.am                   |    2 +-
 .../e-mail-display-popup-prefer-plain.c            |  230 +++-
 modules/prefer-plain/web-extension/Makefile.am     |   23 +
 .../module-prefer-plain-web-extension.c            |  176 +++
 .../module-prefer-plain-web-extension.h            |   26 +
 modules/text-highlight/Makefile.am                 |    2 +
 .../e-mail-display-popup-text-highlight.c          |  209 ++-
 modules/text-highlight/web-extension/Makefile.am   |   23 +
 .../module-text-highlight-web-extension.c          |  176 +++
 .../module-text-highlight-web-extension.h          |   26 +
 modules/vcard-inline/e-mail-formatter-vcard.c      |    9 +-
 modules/vcard-inline/e-mail-part-vcard.c           |  216 ++--
 modules/vcard-inline/e-mail-part-vcard.h           |    4 -
 modules/web-inspector/evolution-web-inspector.c    |   33 +-
 plugins/mail-to-task/mail-to-task.c                |   15 +-
 shell/main.c                                       |    3 +-
 web-extensions/Makefile.am                         |   23 +
 web-extensions/evolution-web-extension.c           |  636 ++++++++
 web-extensions/evolution-web-extension.h           |   26 +
 68 files changed, 8420 insertions(+), 2236 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index cd8e3e9..82c2ae8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -71,6 +71,7 @@ SUBDIRS =                     \
        art                     \
        plugins                 \
        modules                 \
+       web-extensions          \
        $(MAINT_SUBDIR)         \
        doc                     \
        ui                      \
diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c
index cd7fafd..f2111be 100644
--- a/addressbook/gui/widgets/eab-contact-display.c
+++ b/addressbook/gui/widgets/eab-contact-display.c
@@ -28,7 +28,7 @@
 #include <string.h>
 #include <glib/gi18n.h>
 
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
 
 #include "e-contact-map.h"
 #include "eab-contact-formatter.h"
@@ -386,19 +386,31 @@ contact_display_object_requested (WebKitWebView *web_view,
 #endif
 
 static void
-contact_display_load_status_changed (WebKitWebView *web_view,
-                                     GParamSpec *pspec,
-                                     gpointer user_data)
+contact_display_load_changed (WebKitWebView *web_view,
+                              WebKitLoadEvent load_event,
+                              gpointer user_data)
 {
-       WebKitLoadStatus load_status;
-       WebKitDOMDocument *document;
-
-       load_status = webkit_web_view_get_load_status (web_view);
-       if (load_status != WEBKIT_LOAD_FINISHED)
-               return;
-
-       document = webkit_web_view_get_dom_document (web_view);
-       eab_contact_formatter_bind_dom (document);
+       GDBusProxy *web_extension;
+       GVariant* result;
+
+       if (load_event != WEBKIT_LOAD_FINISHED)
+               return;
+
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
+       if (web_extension) {
+               result = g_dbus_proxy_call_sync (
+                               web_extension,
+                               "EABContactFormatterBindDOM",
+                               g_variant_new (
+                                       "(t)",
+                                       webkit_web_view_get_page_id (web_view)),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               NULL, //cancellable
+                               NULL);
+               if (result)
+                       g_variant_unref (result);
+       }
 }
 
 static void
@@ -514,15 +526,12 @@ eab_contact_display_init (EABContactDisplay *display)
                G_CALLBACK (contact_display_object_requested), display);
 #endif
        e_signal_connect_notify (
-               web_view, "notify::load-status",
-               G_CALLBACK (contact_display_load_status_changed), NULL);
+               web_view, "notify::load-changed",
+               G_CALLBACK (contact_display_load_changed), NULL);
        g_signal_connect (
                web_view, "style-updated",
                G_CALLBACK (load_contact), NULL);
 
-       e_web_view_install_request_handler (E_WEB_VIEW (display), E_TYPE_FILE_REQUEST);
-       e_web_view_install_request_handler (E_WEB_VIEW (display), E_TYPE_STOCK_REQUEST);
-
        action_group = gtk_action_group_new ("internal-mailto");
        gtk_action_group_set_translation_domain (action_group, domain);
        gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
diff --git a/addressbook/gui/widgets/eab-contact-formatter.c b/addressbook/gui/widgets/eab-contact-formatter.c
index 14e0d0b..983ae66 100644
--- a/addressbook/gui/widgets/eab-contact-formatter.c
+++ b/addressbook/gui/widgets/eab-contact-formatter.c
@@ -1383,65 +1383,3 @@ eab_contact_formatter_format_contact (EABContactFormatter *formatter,
        else
                render_compact (formatter, contact, output_buffer);
 }
-
-static void
-collapse_contacts_list (WebKitDOMEventTarget *event_target,
-                        WebKitDOMEvent *event,
-                        gpointer user_data)
-{
-       WebKitDOMDocument *document;
-       WebKitDOMElement *list;
-       gchar *id, *list_id;
-       gchar *imagesdir, *src;
-       gboolean hidden;
-
-       document = user_data;
-       id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (event_target));
-
-       list_id = g_strconcat ("list-", id, NULL);
-       list = webkit_dom_document_get_element_by_id (document, list_id);
-       g_free (id);
-       g_free (list_id);
-
-       if (list == NULL)
-               return;
-
-       imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
-       hidden = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (list));
-
-       if (hidden)
-               src = g_strdup_printf ("evo-file://%s/minus.png", imagesdir);
-       else
-               src = g_strdup_printf ("evo-file://%s/plus.png", imagesdir);
-
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (list), !hidden);
-       webkit_dom_html_image_element_set_src (
-               WEBKIT_DOM_HTML_IMAGE_ELEMENT (event_target), src);
-
-       g_free (src);
-       g_free (imagesdir);
-}
-
-void
-eab_contact_formatter_bind_dom (WebKitDOMDocument *document)
-{
-       WebKitDOMNodeList *nodes;
-       gulong ii, length;
-
-       nodes = webkit_dom_document_get_elements_by_class_name (
-               document, "_evo_collapse_button");
-
-       length = webkit_dom_node_list_get_length (nodes);
-       for (ii = 0; ii < length; ii++) {
-
-               WebKitDOMNode *node;
-
-               node = webkit_dom_node_list_item (nodes, ii);
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (node), "click",
-                       G_CALLBACK (collapse_contacts_list), FALSE, document);
-       }
-
-       g_object_unref (nodes);
-}
diff --git a/addressbook/gui/widgets/eab-contact-formatter.h b/addressbook/gui/widgets/eab-contact-formatter.h
index b4acc62..b691f31 100644
--- a/addressbook/gui/widgets/eab-contact-formatter.h
+++ b/addressbook/gui/widgets/eab-contact-formatter.h
@@ -75,7 +75,6 @@ void          eab_contact_formatter_format_contact
                                                (EABContactFormatter *formatter,
                                                 EContact *contact,
                                                 GString *output_buffer);
-void           eab_contact_formatter_bind_dom  (WebKitDOMDocument *document);
 
 G_END_DECLS
 
diff --git a/configure.ac b/configure.ac
index 2babc56..eecaa11 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,7 +50,7 @@ m4_define([gcr_minimum_version], [3.4])
 m4_define([enchant_minimum_version], [1.1.7])
 m4_define([gnome_desktop_minimum_version], [2.91.3])
 m4_define([gsettings_desktop_schemas_minimum_version], [2.91.92])
-m4_define([webkitgtk_minimum_version], [2.2.0])
+m4_define([webkit2gtk_minimum_version], [2.5.3])
 m4_define([libgdata_minimum_version], [0.10])
 m4_define([libxml_minimum_version], [2.7.3])
 m4_define([shared_mime_info_minimum_version], [0.22])
@@ -279,7 +279,7 @@ PKG_CHECK_MODULES([GNOME_PLATFORM],
         libxml-2.0 >= libxml_minimum_version
         shared-mime-info >= shared_mime_info_minimum_version
         gsettings-desktop-schemas >= gsettings_desktop_schemas_minimum_version
-        webkitgtk-3.0 >= webkitgtk_minimum_version])
+        webkit2gtk-4.0 >= webkitgtk_minimum_version])
 
 GNOME_DESKTOP_DEPENDENCY=""
 AC_ARG_ENABLE([gnome-desktop],
@@ -1266,6 +1266,16 @@ AC_SUBST(viewsdir)
 dnl For evolution-alarm-notify.desktop
 AS_AC_EXPAND(PRIVLIBEXECDIR, "$privlibexecdir")
 
+dnl **********************************
+dnl WebKit2 Web Extensions
+dnl **********************************
+webextensionsdir="$privlibdir/web-extensions"
+AC_SUBST(webextensionsdir)
+
+PKG_CHECK_MODULES(WEB_EXTENSION, [webkit2gtk-4.0 >= webkit2gtk_minimum_version])
+AC_SUBST(WEB_EXTENSIONS_CFLAGS)
+AC_SUBST(WEB_EXTENSIONS_LIBS)
+
 dnl ************************
 dnl Plugins
 dnl ************************
@@ -1593,8 +1603,10 @@ modules/contact-photos/Makefile
 modules/gravatar/Makefile
 modules/itip-formatter/Makefile
 modules/itip-formatter/plugin/Makefile
+modules/itip-formatter/web-extension/Makefile
 modules/mail-config/Makefile
 modules/mail/Makefile
+modules/mail/web-extension/Makefile
 modules/mailto-handler/Makefile
 modules/mdn/Makefile
 modules/offline-alert/Makefile
@@ -1602,10 +1614,12 @@ modules/plugin-lib/Makefile
 modules/plugin-manager/Makefile
 modules/prefer-plain/Makefile
 modules/prefer-plain/plugin/Makefile
+modules/prefer-plain/web-extension/Makefile
 modules/settings/Makefile
 modules/spamassassin/Makefile
 modules/startup-wizard/Makefile
 modules/text-highlight/Makefile
+modules/text-highlight/web-extension/Makefile
 modules/tnef-attachment/Makefile
 modules/vcard-inline/Makefile
 modules/web-inspector/Makefile
@@ -1623,6 +1637,7 @@ plugins/pst-import/Makefile
 plugins/publish-calendar/Makefile
 plugins/save-calendar/Makefile
 plugins/templates/Makefile
+web-extensions/Makefile
 smime/Makefile
 smime/lib/Makefile
 smime/gui/Makefile
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 61ee3f8..030efe6 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -97,6 +97,7 @@ libevolution_util_la_CPPFLAGS = \
        -DEVOLUTION_TOOLSDIR=\""$(privlibexecdir)"\" \
        -DEVOLUTION_UIDIR=\""$(uidir)"\" \
        -DEVOLUTION_RULEDIR=\"$(ruledir)\" \
+       -DEVOLUTION_WEB_EXTENSIONS_DIR=\""$(webextensionsdir)"\" \
        -DG_LOG_DOMAIN=\"evolution-util\" \
        $(EVOLUTION_DATA_SERVER_CFLAGS) \
        $(GNOME_PLATFORM_CFLAGS) \
@@ -178,6 +179,7 @@ evolution_util_include_HEADERS =  \
        e-destination-store.h \
        e-dialog-utils.h \
        e-dialog-widgets.h \
+       e-dom-utils.h \
        e-emoticon-action.h \
        e-emoticon-chooser-menu.h \
        e-emoticon-chooser.h \
@@ -450,6 +452,7 @@ libevolution_util_la_SOURCES = \
        e-destination-store.c \
        e-dialog-utils.c \
        e-dialog-widgets.c \
+       e-dom-utils.c \
        e-emoticon-action.c \
        e-emoticon-chooser-menu.c \
        e-emoticon-chooser.c \
diff --git a/e-util/e-dom-utils.c b/e-util/e-dom-utils.c
new file mode 100644
index 0000000..377d174
--- /dev/null
+++ b/e-util/e-dom-utils.c
@@ -0,0 +1,1280 @@
+/*
+ * e-dom-utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-dom-utils.h"
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+
+#include "../web-extensions/evolution-web-extension.h"
+
+#include <config.h>
+
+static void
+replace_local_image_links (WebKitDOMElement *element)
+{
+       WebKitDOMElement *child;
+
+       if (element == NULL)
+               return;
+
+       if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (element)) {
+               WebKitDOMHTMLImageElement *img;
+               gchar *src;
+
+               img = WEBKIT_DOM_HTML_IMAGE_ELEMENT (element);
+               src = webkit_dom_html_image_element_get_src (img);
+               if (src && g_ascii_strncasecmp (src, "file://", 7) == 0) {
+                       gchar *new_src;
+
+                       /* this forms "evo-file://", which can be loaded,
+                        * while "file://" cannot be, due to webkit policy */
+                       new_src = g_strconcat ("evo-", src, NULL);
+                       webkit_dom_html_image_element_set_src (img, new_src);
+                       g_free (new_src);
+               }
+
+               g_free (src);
+       }
+
+       if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+               WebKitDOMDocument *content_document;
+
+               content_document =
+                       webkit_dom_html_iframe_element_get_content_document (
+                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+
+               if (!content_document)
+                       return;
+
+               replace_local_image_links (WEBKIT_DOM_ELEMENT (content_document));
+       }
+
+       child = webkit_dom_element_get_first_element_child (element);
+       replace_local_image_links (child);
+
+       do {
+               element = webkit_dom_element_get_next_element_sibling (element);
+               replace_local_image_links (element);
+       } while (element != NULL);
+}
+
+void
+e_dom_utils_replace_local_image_links (WebKitDOMDocument *document)
+{
+       WebKitDOMNode *node;
+
+       for (node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (document));
+            node;
+            node = webkit_dom_node_get_next_sibling (node)) {
+               if (WEBKIT_DOM_IS_ELEMENT (node))
+                       replace_local_image_links (WEBKIT_DOM_ELEMENT (node));
+       }
+}
+
+static gboolean
+document_has_selection (WebKitDOMDocument *document)
+{
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       if (!dom_window)
+               return FALSE;
+
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       if (!WEBKIT_DOM_IS_DOM_SELECTION (dom_selection))
+               return FALSE;
+
+       if (webkit_dom_dom_selection_get_range_count (dom_selection) == 0)
+               return FALSE;
+
+       if (webkit_dom_dom_selection_get_is_collapsed (dom_selection))
+               return FALSE;
+
+       return TRUE;
+}
+
+gchar *
+e_dom_utils_get_document_content_html (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_document_element (document);
+
+       return webkit_dom_html_element_get_outer_html (WEBKIT_DOM_HTML_ELEMENT (element));
+}
+
+static gchar *
+get_frame_selection_html (WebKitDOMElement *iframe)
+{
+       WebKitDOMDocument *content_document;
+       WebKitDOMDOMWindow *window;
+       WebKitDOMDOMSelection *selection;
+       WebKitDOMNodeList *frames;
+       gulong ii, length;
+
+       content_document = webkit_dom_html_iframe_element_get_content_document (
+               WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+
+       if (!content_document)
+               return NULL;
+
+       window = webkit_dom_document_get_default_view (content_document);
+       selection = webkit_dom_dom_window_get_selection (window);
+       if (selection && (webkit_dom_dom_selection_get_range_count (selection) > 0)) {
+               WebKitDOMRange *range;
+               WebKitDOMElement *element;
+               WebKitDOMDocumentFragment *fragment;
+
+               range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
+               if (range != NULL) {
+                       fragment = webkit_dom_range_clone_contents (
+                               range, NULL);
+
+                       element = webkit_dom_document_create_element (
+                               content_document, "DIV", NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (element),
+                               WEBKIT_DOM_NODE (fragment), NULL);
+
+                       return webkit_dom_html_element_get_inner_html (
+                               WEBKIT_DOM_HTML_ELEMENT (element));
+               }
+       }
+
+       frames = webkit_dom_document_get_elements_by_tag_name (
+               content_document, "IFRAME");
+       length = webkit_dom_node_list_get_length (frames);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+               gchar *text;
+
+               node = webkit_dom_node_list_item (frames, ii);
+
+               text = get_frame_selection_html (
+                       WEBKIT_DOM_ELEMENT (node));
+
+               if (text != NULL) {
+                       g_object_unref (frames);
+                       return text;
+               }
+       }
+
+       g_object_unref (frames);
+       return NULL;
+}
+
+gchar *
+e_dom_utils_get_selection_content_html (WebKitDOMDocument *document)
+{
+       WebKitDOMNodeList *frames;
+       gulong ii, length;
+
+       if (!document_has_selection (document))
+               return NULL;
+
+       frames = webkit_dom_document_get_elements_by_tag_name (document, "IFRAME");
+       length = webkit_dom_node_list_get_length (frames);
+
+       for (ii = 0; ii < length; ii++) {
+               gchar *text;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (frames, ii);
+
+               text = get_frame_selection_html (
+                       WEBKIT_DOM_ELEMENT (node));
+
+               if (text != NULL)
+                       return text;
+       }
+
+       return NULL;
+}
+
+static gchar *
+get_frame_selection_content_text (WebKitDOMElement *iframe)
+{
+       WebKitDOMDocument *content_document;
+       WebKitDOMDOMWindow *window;
+       WebKitDOMDOMSelection *selection;
+       WebKitDOMNodeList *frames;
+       gulong ii, length;
+
+       content_document = webkit_dom_html_iframe_element_get_content_document (
+               WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+
+       if (!content_document)
+               return NULL;
+
+       window = webkit_dom_document_get_default_view (content_document);
+       selection = webkit_dom_dom_window_get_selection (window);
+       if (selection && (webkit_dom_dom_selection_get_range_count (selection) > 0)) {
+               WebKitDOMRange *range;
+
+               range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
+               if (range != NULL)
+                       return webkit_dom_range_to_string (range, NULL);
+       }
+
+       frames = webkit_dom_document_get_elements_by_tag_name (
+               content_document, "IFRAME");
+       length = webkit_dom_node_list_get_length (frames);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+               gchar *text;
+
+               node = webkit_dom_node_list_item (frames, ii);
+
+               text = get_frame_selection_content_text (
+                       WEBKIT_DOM_ELEMENT (node));
+
+               if (text != NULL) {
+                       g_object_unref (frames);
+                       return text;
+               }
+       }
+
+       g_object_unref (frames);
+       return NULL;
+}
+
+gchar *
+e_dom_utils_get_selection_content_text (WebKitDOMDocument *document)
+{
+       WebKitDOMNodeList *frames;
+       gulong ii, length;
+
+       frames = webkit_dom_document_get_elements_by_tag_name (document, "IFRAME");
+       length = webkit_dom_node_list_get_length (frames);
+
+       for (ii = 0; ii < length; ii++) {
+               gchar *text;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (frames, ii);
+
+               text = get_frame_selection_content_text (
+                       WEBKIT_DOM_ELEMENT (node));
+
+               if (text != NULL) {
+                       g_object_unref (frames);
+                       return text;
+               }
+       }
+
+       g_object_unref (frames);
+       return NULL;
+}
+
+void
+e_dom_utils_create_and_add_css_style_sheet (WebKitDOMDocument *document,
+                                            const gchar *style_sheet_id)
+{
+       WebKitDOMElement *style_element;
+
+       style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+
+       if (!style_element) {
+               /* Create new <style> element */
+               style_element = webkit_dom_document_create_element (document, "style", NULL);
+               webkit_dom_element_set_id (
+                       style_element,
+                       style_sheet_id);
+               webkit_dom_html_style_element_set_media (
+                       WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element),
+                       "screen");
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (style_element),
+                       /* WebKit hack - we have to insert empty TextNode into style element */
+                       WEBKIT_DOM_NODE (webkit_dom_document_create_text_node (document, "")),
+                       NULL);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (webkit_dom_document_get_head (document)),
+                       WEBKIT_DOM_NODE (style_element),
+                       NULL);
+       }
+}
+
+static void
+add_css_rule_into_style_sheet (WebKitDOMDocument *document,
+                               const gchar *style_sheet_id,
+                               const gchar *selector,
+                               const gchar *style)
+{
+       WebKitDOMElement *style_element;
+       WebKitDOMStyleSheet *sheet;
+       WebKitDOMCSSRuleList *rules_list;
+       gint length, ii;
+
+       style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+
+       if (!style_element) {
+               e_dom_utils_create_and_add_css_style_sheet (document, style_sheet_id);
+               style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+       }
+
+       /* Get sheet that is associated with style element */
+       sheet = webkit_dom_html_style_element_get_sheet (WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element));
+
+       rules_list = webkit_dom_css_style_sheet_get_css_rules (WEBKIT_DOM_CSS_STYLE_SHEET (sheet));
+       length = webkit_dom_css_rule_list_get_length (rules_list);
+
+       /* Check if rule exists */
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMCSSRule *rule;
+               gchar *rule_text;
+               gchar *rule_selector, *selector_end;
+
+               rule = webkit_dom_css_rule_list_item (rules_list, ii);
+
+               if (!WEBKIT_DOM_IS_CSS_RULE (rule))
+                       continue;
+
+               rule_text = webkit_dom_css_rule_get_css_text (rule);
+
+               /* Find the start of the style => end of the selector */
+               selector_end = g_strstr_len (rule_text, -1, " {");
+               if (!selector_end) {
+                       g_free (rule_text);
+                       continue;
+               }
+
+               rule_selector =
+                       g_utf8_substring (
+                               rule_text,
+                               0,
+                               g_utf8_pointer_to_offset (rule_text, selector_end));
+
+               if (g_strcmp0 (rule_selector, selector) == 0) {
+                       /* If exists remove it */
+                       webkit_dom_css_style_sheet_remove_rule (
+                               WEBKIT_DOM_CSS_STYLE_SHEET (sheet),
+                               ii, NULL);
+               }
+
+               g_free (rule_selector);
+               g_free (rule_text);
+       }
+
+       /* Insert the rule at the end, so it will override previously inserted */
+       webkit_dom_css_style_sheet_add_rule (
+               WEBKIT_DOM_CSS_STYLE_SHEET (sheet),
+               selector,
+               style,
+               webkit_dom_css_rule_list_get_length (
+                       webkit_dom_css_style_sheet_get_css_rules (
+                               WEBKIT_DOM_CSS_STYLE_SHEET (sheet))), /* Index */
+               NULL);
+}
+
+static void
+add_css_rule_into_style_sheet_recursive (WebKitDOMDocument *document,
+                                         const gchar *style_sheet_id,
+                                         const gchar *selector,
+                                         const gchar *style)
+{
+       WebKitDOMNodeList *frames;
+       gint ii, length;
+
+       /* Add rule to document */
+       add_css_rule_into_style_sheet (
+               document,
+               style_sheet_id,
+               selector,
+               style);
+
+       frames = webkit_dom_document_query_selector_all (document, "iframe", NULL);
+       length = webkit_dom_node_list_get_length (frames);
+
+       /* Add rules to every sub document */
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMDocument *content_document = NULL;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (frames, ii);
+               content_document =
+                       webkit_dom_html_iframe_element_get_content_document (
+                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+               if (!content_document)
+                       continue;
+
+               add_css_rule_into_style_sheet_recursive (
+                       content_document,
+                       style_sheet_id,
+                       selector,
+                       style);
+       }
+       g_object_unref (frames);
+}
+
+void
+e_dom_utils_add_css_rule_into_style_sheet (WebKitDOMDocument *document,
+                                           const gchar *style_sheet_id,
+                                           const gchar *selector,
+                                           const gchar *style)
+{
+       g_return_if_fail (style_sheet_id && *style_sheet_id);
+       g_return_if_fail (selector && *selector);
+       g_return_if_fail (style && *style);
+
+       add_css_rule_into_style_sheet_recursive (
+               document,
+               style_sheet_id,
+               selector,
+               style);
+}
+
+static void
+collapse_contacts_list (WebKitDOMEventTarget *event_target,
+                        WebKitDOMEvent *event,
+                        gpointer user_data)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *list;
+       gchar *id, *list_id;
+       gchar *imagesdir, *src;
+       gboolean hidden;
+
+       document = user_data;
+       id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (event_target));
+
+       list_id = g_strconcat ("list-", id, NULL);
+       list = webkit_dom_document_get_element_by_id (document, list_id);
+       g_free (id);
+       g_free (list_id);
+
+       if (list == NULL)
+               return;
+
+       imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+       hidden = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (list));
+
+       if (hidden)
+               src = g_strdup_printf ("evo-file://%s/minus.png", imagesdir);
+       else
+               src = g_strdup_printf ("evo-file://%s/plus.png", imagesdir);
+
+       webkit_dom_html_element_set_hidden (
+               WEBKIT_DOM_HTML_ELEMENT (list), !hidden);
+       webkit_dom_html_image_element_set_src (
+               WEBKIT_DOM_HTML_IMAGE_ELEMENT (event_target), src);
+
+       g_free (src);
+       g_free (imagesdir);
+}
+
+static void
+toggle_headers_visibility (WebKitDOMElement *button,
+                           WebKitDOMEvent *event,
+                           WebKitDOMDocument *document)
+{
+       WebKitDOMElement *short_headers, *full_headers;
+       WebKitDOMCSSStyleDeclaration *css_short, *css_full;
+       gboolean expanded;
+       const gchar *path;
+       gchar *css_value;
+
+       short_headers = webkit_dom_document_get_element_by_id (
+               document, "__evo-short-headers");
+       if (short_headers == NULL)
+               return;
+
+       css_short = webkit_dom_element_get_style (short_headers);
+
+       full_headers = webkit_dom_document_get_element_by_id (
+               document, "__evo-full-headers");
+       if (full_headers == NULL)
+               return;
+
+       css_full = webkit_dom_element_get_style (full_headers);
+       css_value = webkit_dom_css_style_declaration_get_property_value (
+               css_full, "display");
+       expanded = (g_strcmp0 (css_value, "table") == 0);
+       g_free (css_value);
+
+       webkit_dom_css_style_declaration_set_property (
+               css_full, "display",
+               expanded ? "none" : "table", "", NULL);
+       webkit_dom_css_style_declaration_set_property (
+               css_short, "display",
+               expanded ? "table" : "none", "", NULL);
+
+       if (expanded)
+               path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
+       else
+               path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+
+       webkit_dom_html_image_element_set_src (
+               WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+}
+
+static void
+toggle_address_visibility (WebKitDOMElement *button,
+                           WebKitDOMEvent *event,
+                           GDBusConnection *connection)
+{
+       WebKitDOMElement *full_addr, *ellipsis;
+       WebKitDOMElement *parent;
+       WebKitDOMCSSStyleDeclaration *css_full, *css_ellipsis;
+       const gchar *path;
+       gboolean expanded;
+       GError *error = NULL;
+
+       /* <b> element */
+       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (button));
+       /* <td> element */
+       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (parent));
+
+       full_addr = webkit_dom_element_query_selector (parent, "#__evo-moreaddr", NULL);
+
+       if (!full_addr)
+               return;
+
+       css_full = webkit_dom_element_get_style (full_addr);
+
+       ellipsis = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-ellipsis", NULL);
+
+       if (!ellipsis)
+               return;
+
+       css_ellipsis = webkit_dom_element_get_style (ellipsis);
+
+       expanded = (g_strcmp0 (
+               webkit_dom_css_style_declaration_get_property_value (
+               css_full, "display"), "inline") == 0);
+
+       webkit_dom_css_style_declaration_set_property (
+               css_full, "display", (expanded ? "none" : "inline"), "", NULL);
+       webkit_dom_css_style_declaration_set_property (
+               css_ellipsis, "display", (expanded ? "inline" : "none"), "", NULL);
+
+       if (expanded)
+               path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
+       else
+               path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+
+       if (!WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (button)) {
+               button = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-img", NULL);
+
+               if (!button)
+                       return;
+       }
+
+       webkit_dom_html_image_element_set_src (
+               WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+               EVOLUTION_WEB_EXTENSION_INTERFACE,
+               "HeadersCollapsed",
+               g_variant_new ("(b)", expanded),
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal HeadersCollapsed: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+e_dom_utils_bind_dom (WebKitDOMDocument *document,
+                      const gchar *selector,
+                      const gchar *event,
+                      gpointer callback,
+                      gpointer user_data)
+{
+       WebKitDOMNodeList *nodes;
+       gulong ii, length;
+
+       nodes = webkit_dom_document_query_selector_all (
+                       document, selector, NULL);
+
+       length = webkit_dom_node_list_get_length (nodes);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (nodes, ii);
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (node), event,
+                       G_CALLBACK (callback), FALSE, user_data);
+       }
+       g_object_unref (nodes);
+}
+
+static void
+e_dom_utils_bind_elements_recursively (WebKitDOMDocument *document,
+                                       const gchar *selector,
+                                       const gchar *event,
+                                       gpointer callback,
+                                       gpointer user_data)
+{
+       WebKitDOMNodeList *nodes;
+       gulong ii, length;
+
+       nodes = webkit_dom_document_query_selector_all (
+                       document, selector, NULL);
+
+       length = webkit_dom_node_list_get_length (nodes);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (nodes, ii);
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (node), event,
+                       G_CALLBACK (callback), FALSE, user_data);
+       }
+       g_object_unref (nodes);
+
+       nodes = webkit_dom_document_query_selector_all (document, "iframe", NULL);
+       length = webkit_dom_node_list_get_length (nodes);
+
+       /* Add rules to every sub document */
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMDocument *content_document = NULL;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (nodes, ii);
+               content_document =
+                       webkit_dom_html_iframe_element_get_content_document (
+                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+               if (!content_document)
+                       continue;
+
+               e_dom_utils_bind_elements_recursively (
+                       content_document,
+                       selector,
+                       event,
+                       callback,
+                       user_data);
+       }
+       g_object_unref (nodes);
+}
+
+static void
+element_focus_cb (WebKitDOMElement *element,
+                  WebKitDOMEvent *event,
+                 GDBusConnection *connection)
+{
+       g_dbus_connection_call (
+               connection,
+               "org.gnome.Evolution.WebExtension",
+               "/org/gnome/Evolution/WebExtension",
+               "org.freedesktop.DBus.Properties",
+               "Set",
+               g_variant_new (
+                       "(ssv)",
+                       "org.gnome.Evolution.WebExtension",
+                       "NeedInput",
+                       g_variant_new_boolean (TRUE)),
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+
+}
+
+static void
+element_blur_cb (WebKitDOMElement *element,
+                 WebKitDOMEvent *event,
+                GDBusConnection *connection)
+{
+       g_dbus_connection_call (
+               connection,
+               "org.gnome.Evolution.WebExtension",
+               "/org/gnome/Evolution/WebExtension",
+               "org.freedesktop.DBus.Properties",
+               "Set",
+               g_variant_new (
+                       "(ssv)",
+                       "org.gnome.Evolution.WebExtension",
+                       "NeedInput",
+                       g_variant_new_boolean (FALSE)),
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+
+void
+e_dom_utils_bind_focus_on_elements (WebKitDOMDocument *document,
+                                    GDBusConnection *connection)
+{
+       const gchar *elements = "input, textarea, select, button, label";
+
+       e_dom_utils_bind_elements_recursively (
+               document,
+               elements,
+               "focus",
+               element_focus_cb,
+               connection);
+
+       e_dom_utils_bind_elements_recursively (
+               document,
+               elements,
+               "blur",
+               element_blur_cb,
+               connection);
+}
+
+void
+e_dom_utils_e_mail_display_bind_dom (WebKitDOMDocument *document,
+                                     GDBusConnection *connection)
+{
+       e_dom_utils_bind_dom (
+               document,
+               "#__evo-collapse-headers-img",
+               "click",
+               toggle_headers_visibility,
+               document);
+
+       e_dom_utils_bind_dom (
+               document,
+               "*[id^=__evo-moreaddr-]",
+               "click",
+               toggle_address_visibility,
+               connection);
+}
+
+void
+e_dom_utils_eab_contact_formatter_bind_dom (WebKitDOMDocument *document)
+{
+       e_dom_utils_bind_dom (
+               document,
+               "._evo_collapse_button",
+               "click",
+               collapse_contacts_list,
+               document);
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMElement *
+e_dom_utils_find_element_by_selector (WebKitDOMDocument *document,
+                                      const gchar *selector)
+{
+       WebKitDOMNodeList *frames;
+       WebKitDOMElement *element;
+       gulong ii, length;
+
+       /* Try to look up the element in this DOM document */
+       element = webkit_dom_document_query_selector (document, selector, NULL);
+       if (element != NULL)
+               return element;
+
+       /* If the element is not here then recursively scan all frames */
+       frames = webkit_dom_document_get_elements_by_tag_name (document, "iframe");
+       length = webkit_dom_node_list_get_length (frames);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMHTMLIFrameElement *iframe;
+               WebKitDOMDocument *content_document;
+               WebKitDOMElement *element;
+
+               iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+                       webkit_dom_node_list_item (frames, ii));
+
+               content_document = webkit_dom_html_iframe_element_get_content_document (iframe);
+               if (!content_document)
+                       continue;
+
+               element = e_dom_utils_find_element_by_id (content_document, selector);
+
+               if (element != NULL) {
+                       g_object_unref (frames);
+                       return element;
+               }
+       }
+
+       g_object_unref (frames);
+       return NULL;
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMElement *
+e_dom_utils_find_element_by_id (WebKitDOMDocument *document,
+                                const gchar *id)
+{
+       WebKitDOMNodeList *frames;
+       WebKitDOMElement *element;
+       gulong ii, length;
+
+       /* Try to look up the element in this DOM document */
+       element = webkit_dom_document_get_element_by_id (document, id);
+       if (element != NULL)
+               return element;
+
+       /* If the element is not here then recursively scan all frames */
+       frames = webkit_dom_document_get_elements_by_tag_name (
+               document, "iframe");
+       length = webkit_dom_node_list_get_length (frames);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMHTMLIFrameElement *iframe;
+               WebKitDOMDocument *content_document;
+               WebKitDOMElement *element;
+
+               iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+                       webkit_dom_node_list_item (frames, ii));
+
+               content_document = webkit_dom_html_iframe_element_get_content_document (iframe);
+               if (!content_document)
+                       continue;
+
+               element = e_dom_utils_find_element_by_id (content_document, id);
+
+               if (element != NULL) {
+                       g_object_unref (frames);
+                       return element;
+               }
+       }
+
+       g_object_unref (frames);
+       return NULL;
+}
+
+gboolean
+e_dom_utils_element_exists (WebKitDOMDocument *document,
+                            const gchar *element_id)
+{
+       WebKitDOMNodeList *frames;
+       gboolean element_exists = FALSE;
+       gulong ii, length;
+
+       /* Try to look up the element in this DOM document */
+       if (webkit_dom_document_get_element_by_id (document, element_id))
+               return TRUE;
+
+       /* If the element is not here then recursively scan all frames */
+       frames = webkit_dom_document_get_elements_by_tag_name (
+               document, "iframe");
+       length = webkit_dom_node_list_get_length (frames);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMHTMLIFrameElement *iframe;
+               WebKitDOMDocument *content_document;
+
+               iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+                       webkit_dom_node_list_item (frames, ii));
+
+               content_document = webkit_dom_html_iframe_element_get_content_document (iframe);
+               if (!content_document)
+                       continue;
+
+               element_exists = e_dom_utils_element_exists (content_document, element_id);
+
+               if (element_exists) {
+                       g_object_unref (frames);
+                       return TRUE;
+               }
+       }
+
+       g_object_unref (frames);
+       return FALSE;
+}
+
+gchar *
+e_dom_utils_get_active_element_name (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_active_element (document);
+
+       if (!element)
+               return NULL;
+
+       while (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+               WebKitDOMDocument *content_document;
+
+               content_document =
+                       webkit_dom_html_iframe_element_get_content_document (
+                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+
+               if (!content_document)
+                       break;
+
+               element = webkit_dom_document_get_active_element (content_document);
+       }
+
+       return webkit_dom_node_get_local_name (WEBKIT_DOM_NODE (element));
+}
+
+void
+e_dom_utils_e_mail_part_headers_bind_dom_element (WebKitDOMDocument *document,
+                                                  const gchar *element_id)
+{
+       WebKitDOMDocument *element_document;
+       WebKitDOMElement *element;
+       WebKitDOMElement *photo;
+       gchar *addr, *uri;
+
+       element = e_dom_utils_find_element_by_id (document, element_id);
+       if (!element)
+               return;
+
+       element_document = webkit_dom_node_get_owner_document (
+               WEBKIT_DOM_NODE (element));
+       photo = webkit_dom_document_get_element_by_id (
+               element_document, "__evo-contact-photo");
+
+       /* Contact photos disabled, the <img> tag is not there. */
+       if (!photo)
+               return;
+
+       addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
+       uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
+
+       webkit_dom_html_image_element_set_src (
+               WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
+
+       g_free (addr);
+       g_free (uri);
+}
+
+void
+e_dom_utils_element_set_inner_html (WebKitDOMDocument *document,
+                                    const gchar *element_id,
+                                    const gchar *inner_html)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_element_set_inner_html (
+               WEBKIT_DOM_HTML_ELEMENT (element), inner_html, NULL);
+}
+
+void
+e_dom_utils_remove_element (WebKitDOMDocument *document,
+                            const gchar *element_id)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_node_remove_child (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+               WEBKIT_DOM_NODE (element),
+               NULL);
+}
+
+void
+e_dom_utils_element_remove_child_nodes (WebKitDOMDocument *document,
+                                        const gchar *element_id)
+{
+       WebKitDOMNode *node;
+
+       node = WEBKIT_DOM_NODE (webkit_dom_document_get_element_by_id (document, element_id));
+
+       if (!node)
+               return;
+
+       while (webkit_dom_node_has_child_nodes (node)) {
+               webkit_dom_node_remove_child (
+                       node,
+                       webkit_dom_node_get_last_child (node),
+                       NULL);
+       }
+}
+
+void
+e_dom_utils_hide_element (WebKitDOMDocument *document,
+                          const gchar *element_id,
+                          gboolean hide)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_element_set_hidden (
+               WEBKIT_DOM_HTML_ELEMENT (element), hide);
+}
+
+gboolean
+e_dom_utils_element_is_hidden (WebKitDOMDocument *document,
+                               const gchar *element_id)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return FALSE;
+
+       return webkit_dom_html_element_get_hidden (
+               WEBKIT_DOM_HTML_ELEMENT (element));
+}
+
+static void
+get_total_offsets (WebKitDOMElement *element,
+                   glong *left,
+                   glong *top)
+{
+       WebKitDOMElement *offset_parent;
+
+       if (left)
+               *left = 0;
+
+       if (top)
+               *top = 0;
+
+       offset_parent = element;
+       do {
+               if (left) {
+                       *left += webkit_dom_element_get_offset_left (offset_parent);
+                       *left -= webkit_dom_element_get_scroll_left (offset_parent);
+               }
+               if (top) {
+                       *top += webkit_dom_element_get_offset_top (offset_parent);
+                       *top -= webkit_dom_element_get_scroll_top (offset_parent);
+               }
+               offset_parent = webkit_dom_element_get_offset_parent (offset_parent);
+       } while (offset_parent);
+}
+
+static WebKitDOMElement *
+find_element_from_point (WebKitDOMDocument *document,
+                         gint32 x,
+                         gint32 y,
+                         WebKitDOMElement *element_on_point)
+{
+       WebKitDOMDocument *content_document;
+       WebKitDOMElement *element;
+
+       if (!element_on_point)
+               element = webkit_dom_document_element_from_point (document, x, y);
+       else {
+               glong left, top;
+               get_total_offsets (element_on_point, &left, &top);
+
+               element = webkit_dom_document_element_from_point (
+                       document, x - left, y - top);
+       }
+
+       if (!element)
+               return element_on_point;
+
+       if (element_on_point && webkit_dom_node_is_equal_node (
+               WEBKIT_DOM_NODE (element),
+               WEBKIT_DOM_NODE (element_on_point))) {
+               return element_on_point;
+       }
+
+       if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+               return element_on_point;
+
+       content_document =
+               webkit_dom_html_iframe_element_get_content_document (
+                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+
+       if (!content_document)
+               return element_on_point;
+
+       return find_element_from_point (content_document, x, y, element);
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMElement *
+e_dom_utils_get_element_from_point (WebKitDOMDocument *document,
+                                    gint32 x,
+                                    gint32 y)
+{
+       return find_element_from_point (document, x, y, NULL);
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMDocument *
+e_dom_utils_get_document_from_point (WebKitDOMDocument *document,
+                                     gint32 x,
+                                     gint32 y)
+{
+       WebKitDOMElement *element;
+
+       if (x == 0 && y == 0)
+               element = webkit_dom_document_get_active_element (document);
+       else
+               element = find_element_from_point (document, x, y, NULL);
+
+       if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+               return webkit_dom_html_iframe_element_get_content_document (
+                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+       else
+               return webkit_dom_node_get_owner_document (
+                       WEBKIT_DOM_NODE (element));
+}
+
+/* VCard Inline Module DOM functions */
+
+static void
+display_mode_toggle_button_cb (WebKitDOMElement *button,
+                               WebKitDOMEvent *event,
+                               GDBusConnection *connection)
+{
+       GError *error = NULL;
+       gchar *element_id;
+
+       element_id = webkit_dom_element_get_id (button);
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+               EVOLUTION_WEB_EXTENSION_INTERFACE,
+               "VCardInlineDisplayModeToggled",
+               g_variant_new ("(s)", element_id),
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal DisplayModeToggled: %s\n", error->message);
+               g_error_free (error);
+       }
+
+       g_free (element_id);
+}
+
+static void
+save_vcard_button_cb (WebKitDOMElement *button,
+                      WebKitDOMEvent *event,
+                      GDBusConnection *connection)
+{
+       GError *error = NULL;
+       gchar *button_value;
+
+       button_value = webkit_dom_html_button_element_get_value (
+               WEBKIT_DOM_HTML_BUTTON_ELEMENT (button));
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+               EVOLUTION_WEB_EXTENSION_INTERFACE,
+               "VCardInlineSaveButtonPressed",
+               g_variant_new ("(s)", button_value),
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal SaveVCardButtonPressed: %s\n", error->message);
+               g_error_free (error);
+       }
+
+       g_free (button_value);
+}
+
+void
+e_dom_utils_module_vcard_inline_bind_dom (WebKitDOMDocument *document,
+                                          const gchar *element_id,
+                                          GDBusConnection *connection)
+{
+       WebKitDOMElement *element;
+       WebKitDOMDocument *element_document;
+       gchar *selector;
+
+       element = e_dom_utils_find_element_by_id (document, element_id);
+       if (!element)
+               return;
+
+       element_document = webkit_dom_node_get_owner_document (
+               WEBKIT_DOM_NODE (element));
+
+       selector = g_strconcat ("button[id='", element_id, "']", NULL);
+       e_dom_utils_bind_dom (
+               element_document,
+               selector,
+               "click",
+               display_mode_toggle_button_cb,
+               connection);
+       g_free (selector);
+
+       selector = g_strconcat ("button[value='", element_id, "']", NULL);
+       e_dom_utils_bind_dom (
+               element_document,
+               selector,
+               "click",
+               save_vcard_button_cb,
+               connection);
+       g_free (selector);
+
+       e_dom_utils_eab_contact_formatter_bind_dom (element_document);
+}
+
+void
+e_dom_utils_module_vcard_inline_update_button (WebKitDOMDocument *document,
+                                               const gchar *button_id,
+                                               const gchar *html_label,
+                                               const gchar *access_key)
+{
+       WebKitDOMElement *element;
+       gchar *selector;
+
+       selector = g_strconcat ("button[id='", button_id, "']", NULL);
+       element = e_dom_utils_find_element_by_selector (document, selector);
+       g_free (selector);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_element_set_inner_html (
+               WEBKIT_DOM_HTML_ELEMENT (element), html_label, NULL);
+
+       if (access_key) {
+               webkit_dom_html_element_set_access_key (
+                       WEBKIT_DOM_HTML_ELEMENT (element), access_key);
+       }
+}
+
+void
+e_dom_utils_module_vcard_inline_set_iframe_src (WebKitDOMDocument *document,
+                                                const gchar *button_id,
+                                                const gchar *src)
+{
+       WebKitDOMElement *element, *parent, *iframe;
+       gchar *selector;
+
+       selector = g_strconcat ("button[id='", button_id, "']", NULL);
+       element = e_dom_utils_find_element_by_selector (document, selector);
+       g_free (selector);
+
+       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (element));
+       if (!parent)
+               return;
+
+       iframe = webkit_dom_element_query_selector (parent, "iframe", NULL);
+       if (!iframe)
+               return;
+
+       webkit_dom_html_iframe_element_set_src (
+               WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe), src);
+}
diff --git a/e-util/e-dom-utils.h b/e-util/e-dom-utils.h
new file mode 100644
index 0000000..2da7d94
--- /dev/null
+++ b/e-util/e-dom-utils.h
@@ -0,0 +1,107 @@
+/*
+ * e-dom-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_DOM_UTILS_H
+#define E_DOM_UTILS_H
+
+#include <webkitdom/webkitdom.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void           e_dom_utils_replace_local_image_links
+                                               (WebKitDOMDocument *document);
+gchar *                e_dom_utils_get_document_content_html
+                                               (WebKitDOMDocument *document);
+gchar *                e_dom_utils_get_selection_content_html
+                                               (WebKitDOMDocument *document);
+gchar *                e_dom_utils_get_selection_content_text
+                                               (WebKitDOMDocument *document);
+void           e_dom_utils_create_and_add_css_style_sheet
+                                               (WebKitDOMDocument *document,
+                                                const gchar *style_sheet_id);
+void           e_dom_utils_add_css_rule_into_style_sheet
+                                               (WebKitDOMDocument *document,
+                                                const gchar *style_sheet_id,
+                                                const gchar *selector,
+                                                const gchar *style);
+void           e_dom_utils_eab_contact_formatter_bind_dom
+                                               (WebKitDOMDocument *document);
+void           e_dom_utils_bind_focus_on_elements
+                                               (WebKitDOMDocument *document,
+                                                GDBusConnection *connection);
+void           e_dom_utils_e_mail_display_bind_dom
+                                               (WebKitDOMDocument *document,
+                                                GDBusConnection *connection);
+WebKitDOMElement *
+               e_dom_utils_find_element_by_selector
+                                               (WebKitDOMDocument *document,
+                                                const gchar *selector);
+WebKitDOMElement *
+               e_dom_utils_find_element_by_id  (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+gboolean       e_dom_utils_element_exists
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+gchar *                e_dom_utils_get_active_element_name
+                                               (WebKitDOMDocument *document);
+void           e_dom_utils_e_mail_part_headers_bind_dom_element
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+void           e_dom_utils_element_set_inner_html
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id,
+                                                const gchar *inner_html);
+void           e_dom_utils_remove_element      (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+void           e_dom_utils_element_remove_child_nodes
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+void           e_dom_utils_hide_element        (WebKitDOMDocument *document,
+                                                const gchar *element_id,
+                                                 gboolean hide);
+gboolean       e_dom_utils_element_is_hidden   (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+WebKitDOMElement *
+               e_dom_utils_get_element_from_point
+                                               (WebKitDOMDocument *document,
+                                                gint32 x,
+                                                gint32 y);
+WebKitDOMDocument *
+               e_dom_utils_get_document_from_point
+                                               (WebKitDOMDocument *document,
+                                                gint32 x,
+                                                gint32 y);
+/* VCard Inline Module DOM functions */
+void           e_dom_utils_module_vcard_inline_bind_dom
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id,
+                                                GDBusConnection *connection);
+void           e_dom_utils_module_vcard_inline_update_button
+                                               (WebKitDOMDocument *document,
+                                                const gchar *button_id,
+                                                const gchar *html_label,
+                                                const gchar *access_key);
+void           e_dom_utils_module_vcard_inline_set_iframe_src
+                                               (WebKitDOMDocument *document,
+                                                const gchar *button_id,
+                                                const gchar *src);
+G_END_DECLS
+
+#endif /* E_DOM_UTILS_H */
diff --git a/e-util/e-mail-signature-preview.c b/e-util/e-mail-signature-preview.c
index f125c8b..9312ff7 100644
--- a/e-util/e-mail-signature-preview.c
+++ b/e-util/e-mail-signature-preview.c
@@ -56,56 +56,31 @@ G_DEFINE_TYPE (
        E_TYPE_WEB_VIEW)
 
 static void
-replace_local_image_links (WebKitDOMDocument *document)
-{
-       gint ii, length;
-       WebKitDOMNodeList *list;
-
-       list = webkit_dom_document_query_selector_all (
-               document, "img[src^=\"file://\"]", NULL);
-       length = webkit_dom_node_list_get_length (list);
-
-       for (ii = 0; ii < length; ii++) {
-               gchar *src, *new_src;
-               WebKitDOMHTMLImageElement *img;
-
-               img = WEBKIT_DOM_HTML_IMAGE_ELEMENT (
-                       webkit_dom_node_list_item (list, ii));
-               src = webkit_dom_html_image_element_get_src (img);
-
-               /* this forms "evo-file://", which can be loaded,
-                * while "file://" cannot be, due to WebKit policy */
-               new_src = g_strconcat ("evo-", src, NULL);
-               webkit_dom_html_image_element_set_src (img, new_src);
-               g_free (new_src);
-               g_free (src);
-       }
-       g_object_unref (list);
-
-       list = webkit_dom_document_get_elements_by_tag_name ( document, "iframe");
-       length = webkit_dom_node_list_get_length (list);
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMDocument *content_document;
-               WebKitDOMHTMLIFrameElement *iframe;
-
-               iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
-                       webkit_dom_node_list_item (list, ii));
-
-               content_document =
-                       webkit_dom_html_iframe_element_get_content_document (iframe);
-
-               if (content_document && WEBKIT_DOM_IS_DOCUMENT (content_document))
-                       replace_local_image_links (content_document);
-       }
-       g_object_unref (list);
-}
-
-static void
 signature_preview_document_loaded_cb (WebKitWebView *web_view,
                                       WebKitWebFrame *web_frame,
                                       gpointer user_data)
 {
-       replace_local_image_links (webkit_web_view_get_dom_document (web_view));
+       GDBusProxy *web_extension;
+       GVariant* result;
+
+       if (load_event != WEBKIT_LOAD_FINISHED)
+               return;
+
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
+       if (web_extension) {
+               result = g_dbus_proxy_call_sync (
+                               web_extension,
+                               "ReplaceLocalImageLinks",
+                               g_variant_new (
+                                       "(t)",
+                                       webkit_web_view_get_page_id (web_view)),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               NULL, //cancellable
+                               NULL);
+               if (result)
+                       g_variant_unref (result);
+       }
 }
 
 static void
@@ -361,7 +336,7 @@ e_mail_signature_preview_init (EMailSignaturePreview *preview)
        preview->priv = E_MAIL_SIGNATURE_PREVIEW_GET_PRIVATE (preview);
 
        g_signal_connect (
-               preview, "document-load-finished",
+               preview, "load-changed",
                G_CALLBACK (signature_preview_document_loaded_cb), NULL);
 }
 
diff --git a/e-util/e-search-bar.c b/e-util/e-search-bar.c
index d3ade35..3410509 100644
--- a/e-util/e-search-bar.c
+++ b/e-util/e-search-bar.c
@@ -44,9 +44,11 @@ struct _ESearchBarPrivate {
        GtkWidget *prev_button;
        GtkWidget *next_button;
 
+       WebKitFindController *find_controller;
+
        gchar *active_search;
 
-       guint rerun_search : 1;
+       gboolean search_forward;
 };
 
 enum {
@@ -77,7 +79,6 @@ search_bar_update_matches (ESearchBar *search_bar,
        GtkWidget *matches_label;
        gchar *text;
 
-       search_bar->priv->rerun_search = FALSE;
        matches_label = search_bar->priv->matches_label;
 
        text = g_strdup_printf (_("Matches: %u"), matches);
@@ -86,14 +87,88 @@ search_bar_update_matches (ESearchBar *search_bar,
        g_free (text);
 }
 
+ static void
+webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
+                                      guint match_count,
+                                      ESearchBar *search_bar)
+{
+       GtkWidget *widget;
+       WebKitFindOptions options;
+       gboolean wrapped = FALSE;
+
+       search_bar_update_matches (search_bar, match_count);
+
+       g_free (search_bar->priv->active_search);
+       search_bar->priv->active_search =
+               g_strdup (webkit_find_controller_get_search_text (find_controller));
+
+       gtk_widget_set_sensitive (search_bar->priv->next_button, TRUE);
+       gtk_widget_set_sensitive (search_bar->priv->prev_button, TRUE);
+
+       g_object_notify (G_OBJECT (search_bar), "active-search");
+
+       options = webkit_find_controller_get_options (find_controller);
+
+       if (options & WEBKIT_FIND_OPTIONS_WRAP_AROUND)
+               wrapped = TRUE;
+
+       /* Update wrapped label visibility. */
+       widget = search_bar->priv->wrapped_next_box;
+
+       if (wrapped && search_bar->priv->search_forward)
+               gtk_widget_show (widget);
+       else
+               gtk_widget_hide (widget);
+
+       widget = search_bar->priv->wrapped_prev_box;
+
+       if (wrapped && !search_bar->priv->search_forward)
+               gtk_widget_show (widget);
+       else
+               gtk_widget_hide (widget);
+}
+
 static void
-search_bar_update_highlights (ESearchBar *search_bar)
+webkit_find_controller_failed_to_found_text_cb (WebKitFindController *find_controller,
+                                                ESearchBar *search_bar)
 {
-       EWebView *web_view;
+       WebKitFindOptions options;
+       GtkWidget *widget;
+
+       options = webkit_find_controller_get_options (find_controller);
+
+       /* If we didn't find anything, try from the beggining with WRAP_AROUND option */
+       if (!(options & WEBKIT_FIND_OPTIONS_WRAP_AROUND)) {
+               webkit_find_controller_search (
+                       find_controller,
+                       webkit_find_controller_get_search_text (find_controller),
+                       options | WEBKIT_FIND_OPTIONS_WRAP_AROUND,
+                       G_MAXUINT);
+       }
+
+       search_bar_update_matches (search_bar, 0);
+
+       g_free (search_bar->priv->active_search);
+       search_bar->priv->active_search =
+               g_strdup (webkit_find_controller_get_search_text (find_controller));
+
+       gtk_widget_set_sensitive (search_bar->priv->next_button, FALSE);
+       gtk_widget_set_sensitive (search_bar->priv->prev_button, FALSE);
+
+       g_object_notify (G_OBJECT (search_bar), "active-search");
+
+       /* Update wrapped label visibility. */
+       widget = search_bar->priv->wrapped_next_box;
+       gtk_widget_hide (widget);
 
-       web_view = e_search_bar_get_web_view (search_bar);
+       widget = search_bar->priv->wrapped_prev_box;
+       gtk_widget_hide (widget);
+}
 
-       webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+static void
+search_bar_update_highlights (ESearchBar *search_bar)
+{
+       webkit_find_controller_search_finish (search_bar->priv->find_controller);
 
        e_search_bar_changed (search_bar);
 }
@@ -102,15 +177,13 @@ static void
 search_bar_find (ESearchBar *search_bar,
                  gboolean search_forward)
 {
-       EWebView *web_view;
-       GtkWidget *widget;
+       WebKitFindController *find_controller;
        gboolean case_sensitive;
-       gboolean wrapped = FALSE;
-       gboolean success;
        gchar *text;
-       guint matches;
 
-       web_view = e_search_bar_get_web_view (search_bar);
+       find_controller = search_bar->priv->find_controller;
+       search_bar->priv->search_forward = search_forward;
+
        case_sensitive = e_search_bar_get_case_sensitive (search_bar);
        text = e_search_bar_get_text (search_bar);
 
@@ -120,46 +193,14 @@ search_bar_find (ESearchBar *search_bar,
                return;
        }
 
-       webkit_web_view_unmark_text_matches (
-               WEBKIT_WEB_VIEW (web_view));
-       matches = webkit_web_view_mark_text_matches (
-               WEBKIT_WEB_VIEW (web_view),
-               text, case_sensitive, 0);
-       webkit_web_view_set_highlight_text_matches (
-               WEBKIT_WEB_VIEW (web_view), TRUE);
-       search_bar_update_matches (search_bar, matches);
-
-       success = webkit_web_view_search_text (
-               WEBKIT_WEB_VIEW (web_view),
-               text, case_sensitive, search_forward, FALSE);
-
-       if (!success)
-               wrapped = webkit_web_view_search_text (
-                       WEBKIT_WEB_VIEW (web_view),
-                       text, case_sensitive, search_forward, TRUE);
-
-       g_free (search_bar->priv->active_search);
-       search_bar->priv->active_search = text;
-
-       gtk_widget_set_sensitive (search_bar->priv->next_button, matches != 0);
-       gtk_widget_set_sensitive (search_bar->priv->prev_button, matches != 0);
-
-       g_object_notify (G_OBJECT (search_bar), "active-search");
-
-       /* Update wrapped label visibility. */
-       widget = search_bar->priv->wrapped_next_box;
+       webkit_find_controller_search_finish (find_controller);
+       webkit_find_controller_search (
+               find_controller,
+               text,
+               case_sensitive ? WEBKIT_FIND_OPTIONS_NONE : WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE,
+               G_MAXUINT);
 
-       if (wrapped && search_forward)
-               gtk_widget_show (widget);
-       else
-               gtk_widget_hide (widget);
-
-       widget = search_bar->priv->wrapped_prev_box;
-
-       if (wrapped && !search_forward)
-               gtk_widget_show (widget);
-       else
-               gtk_widget_hide (widget);
+       g_free (text);
 }
 
 static void
@@ -202,15 +243,14 @@ search_bar_toggled_cb (ESearchBar *search_bar)
 }
 
 static void
-web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
-                                 GParamSpec *pspec,
-                                 gpointer user_data)
+web_view_load_changed_cb (WebKitWebView *webkit_web_view,
+                          WebKitLoadEvent load_event,
+                          gpointer user_data)
 {
-       WebKitLoadStatus status;
        ESearchBar *search_bar;
 
        status = webkit_web_view_get_load_status (webkit_web_view);
-       if (status != WEBKIT_LOAD_FINISHED)
+       if (load_event != WEBKIT_LOAD_FINISHED)
                return;
 
        if (!user_data)
@@ -231,14 +271,29 @@ static void
 search_bar_set_web_view (ESearchBar *search_bar,
                          EWebView *web_view)
 {
+       WebKitFindController *find_controller;
+
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (search_bar->priv->web_view == NULL);
 
        search_bar->priv->web_view = g_object_ref (web_view);
 
+       find_controller =
+               webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (web_view));
+
+       search_bar->priv->find_controller = find_controller;
+
        e_signal_connect_notify (
-               web_view, "notify::load-status",
-               G_CALLBACK (web_view_load_status_changed_cb), search_bar);
+               web_view, "notify::changed",
+               G_CALLBACK (web_view_load_changed_cb), search_bar);
+
+       g_signal_connect (
+               find_controller, "found-text",
+               G_CALLBACK (webkit_find_controller_found_text_cb), search_bar);
+
+       g_signal_connect (
+               find_controller, "failed-to-find-text",
+               G_CALLBACK (webkit_find_controller_failed_to_found_text_cb), search_bar);
 }
 
 static void
@@ -390,7 +445,6 @@ static void
 search_bar_show (GtkWidget *widget)
 {
        ESearchBar *search_bar;
-       EWebView *web_view;
 
        search_bar = E_SEARCH_BAR (widget);
 
@@ -399,8 +453,7 @@ search_bar_show (GtkWidget *widget)
 
        gtk_widget_grab_focus (search_bar->priv->entry);
 
-       web_view = e_search_bar_get_web_view (search_bar);
-       webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+       webkit_find_controller_search_finish (search_bar->priv->find_controller);
 
        search_bar_find (search_bar, TRUE);
 }
@@ -439,8 +492,6 @@ search_bar_key_press_event (GtkWidget *widget,
 static void
 search_bar_clear (ESearchBar *search_bar)
 {
-       WebKitWebView *web_view;
-
        g_free (search_bar->priv->active_search);
        search_bar->priv->active_search = NULL;
 
@@ -452,9 +503,6 @@ search_bar_clear (ESearchBar *search_bar)
 
        search_bar_update_highlights (search_bar);
 
-       web_view = WEBKIT_WEB_VIEW (search_bar->priv->web_view);
-       webkit_web_view_unmark_text_matches (web_view);
-
        g_object_notify (G_OBJECT (search_bar), "active-search");
 }
 
diff --git a/e-util/e-util.h b/e-util/e-util.h
index e2481eb..e03f6b6 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -91,6 +91,7 @@
 #include <e-util/e-destination-store.h>
 #include <e-util/e-dialog-utils.h>
 #include <e-util/e-dialog-widgets.h>
+#include <e-util/e-dom-utils.h>
 #include <e-util/e-emoticon-action.h>
 #include <e-util/e-emoticon-chooser-menu.h>
 #include <e-util/e-emoticon-chooser.h>
diff --git a/e-util/e-web-view-preview.c b/e-util/e-web-view-preview.c
index 0e6b51e..5c0dabe 100644
--- a/e-util/e-web-view-preview.c
+++ b/e-util/e-web-view-preview.c
@@ -173,19 +173,19 @@ in_scrolled_window (GtkWidget *widget)
 static void
 e_web_view_preview_init (EWebViewPreview *preview)
 {
-       GtkWidget *tree_view_sw, *web_view_sw;
+       GtkWidget *tree_view_sw, *web_view;
 
        preview->priv = E_WEB_VIEW_PREVIEW_GET_PRIVATE (preview);
        preview->priv->escape_values = TRUE;
 
        tree_view_sw = in_scrolled_window (gtk_tree_view_new ());
-       web_view_sw = in_scrolled_window (e_web_view_new ());
+       web_view = e_web_view_new ();
 
        gtk_widget_hide (tree_view_sw);
-       gtk_widget_show (web_view_sw);
+       gtk_widget_show (web_view);
 
        gtk_paned_pack1 (GTK_PANED (preview), tree_view_sw, FALSE, TRUE);
-       gtk_paned_pack2 (GTK_PANED (preview), web_view_sw, TRUE, TRUE);
+       gtk_paned_pack2 (GTK_PANED (preview), web_view, TRUE, TRUE);
 
        /* rawly 3 lines of a text plus a little bit more */
        if (gtk_paned_get_position (GTK_PANED (preview)) < 85)
@@ -211,7 +211,7 @@ e_web_view_preview_get_preview (EWebViewPreview *preview)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), NULL);
 
-       return gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview))));
+       return gtk_paned_get_child2 (GTK_PANED (preview));
 }
 
 void
@@ -223,7 +223,7 @@ e_web_view_preview_set_preview (EWebViewPreview *preview,
        g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
        g_return_if_fail (GTK_IS_WIDGET (preview_widget));
 
-       old_child = gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview))));
+       old_child = gtk_paned_get_child2 (GTK_PANED (preview));
        if (old_child) {
                g_return_if_fail (old_child != preview_widget);
                gtk_widget_destroy (old_child);
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index ad94c83..838f212 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -40,6 +40,8 @@
 #include "e-selectable.h"
 #include "e-stock-request.h"
 
+#include "../web-extensions/evolution-web-extension.h"
+
 #define E_WEB_VIEW_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
@@ -71,6 +73,11 @@ struct _EWebViewPrivate {
        gulong antialiasing_changed_handler_id;
 
        GHashTable *old_settings;
+
+       GDBusProxy *web_extension;
+       guint web_extension_watch_name_id;
+
+       WebKitFindController *find_controller;
 };
 
 struct _AsyncContext {
@@ -103,7 +110,6 @@ enum {
 };
 
 static guint signals[LAST_SIGNAL];
-static GOnce disable_webkit_3rd_party_plugins_once = G_ONCE_INIT;
 
 static const gchar *ui =
 "<ui>"
@@ -353,36 +359,6 @@ static GtkActionEntry standard_entries[] = {
 };
 
 static void
-web_view_init_web_settings (WebKitWebView *web_view)
-{
-       WebKitWebSettings *web_settings;
-
-       web_settings = webkit_web_settings_new ();
-
-       g_object_set (
-               G_OBJECT (web_settings),
-               "enable-frame-flattening", TRUE,
-               "enable-java-applet", FALSE,
-               "enable-html5-database", FALSE,
-               "enable-html5-local-storage", FALSE,
-               "enable-offline-web-application-cache", FALSE,
-               "enable-site-specific-quirks", TRUE,
-               "enable-scripts", FALSE,
-               "respect-image-orientation", TRUE,
-               NULL);
-
-       g_object_bind_property (
-               web_settings, "enable-caret-browsing",
-               web_view, "caret-mode",
-               G_BINDING_BIDIRECTIONAL |
-               G_BINDING_SYNC_CREATE);
-
-       webkit_web_view_set_settings (web_view, web_settings);
-
-       g_object_unref (web_settings);
-}
-
-static void
 web_view_menu_item_select_cb (EWebView *web_view,
                               GtkWidget *widget)
 {
@@ -401,20 +377,57 @@ web_view_menu_item_select_cb (EWebView *web_view,
 }
 
 static void
+webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
+                                      guint match_count,
+                                      EWebView *web_view)
+{
+}
+
+static void
+webkit_find_controller_failed_to_found_text_cb (WebKitFindController *find_controller,
+                                                EWebView *web_view)
+{
+}
+
+static void
+web_view_set_find_controller (EWebView *web_view)
+{
+       WebKitFindController *find_controller;
+
+       find_controller =
+               webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (web_view));
+
+       g_signal_connect (
+               find_controller, "found-text",
+               G_CALLBACK (webkit_find_controller_found_text_cb), web_view);
+
+       g_signal_connect (
+               find_controller, "failed-to-find-text",
+               G_CALLBACK (webkit_find_controller_failed_to_found_text_cb), web_view);
+
+       web_view->priv->find_controller = find_controller;
+}
+
+static void
 web_view_update_document_highlights (EWebView *web_view)
 {
-       WebKitWebView *webkit_web_view;
+       WebKitFindController *find_controller;
        GList *head, *link;
 
-       webkit_web_view = WEBKIT_WEB_VIEW (web_view);
+       if (!web_view->priv->find_controller)
+               web_view_set_find_controller (web_view);
 
-       head = g_queue_peek_head_link (&web_view->priv->highlights);
+       find_controller = web_view->priv->find_controller;
 
-       for (link = head; link != NULL; link = g_list_next (link))
-               webkit_web_view_mark_text_matches (
-                       webkit_web_view, link->data, FALSE, 0);
+       head = g_queue_peek_head_link (&web_view->priv->highlights);
 
-       webkit_web_view_set_highlight_text_matches (webkit_web_view, TRUE);
+       for (link = head; link != NULL; link = g_list_next (link)) {
+               webkit_find_controller_search (
+                       find_controller,
+                       link->data,
+                       WEBKIT_FIND_OPTIONS_NONE,
+                       G_MAXUINT);
+       }
 }
 
 static void
@@ -442,9 +455,10 @@ web_view_connect_proxy_cb (EWebView *web_view,
 
 static gboolean
 web_view_context_menu_cb (WebKitWebView *webkit_web_view,
-                          GtkWidget *default_menu,
+                          WebKitContextMenu *context_menu,
+                          GdkEvent *event,
                           WebKitHitTestResult *hit_test_result,
-                          gboolean triggered_with_keyboard)
+                          gpointer user_data)
 {
        WebKitHitTestResultContext context;
        EWebView *web_view;
@@ -459,7 +473,7 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
        if (hit_test_result == NULL)
                return FALSE;
 
-       g_object_get (hit_test_result, "context", &context, NULL);
+       context = webkit_hit_test_result_get_context (hit_test_result);
 
        if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
                gchar *image_uri = NULL;
@@ -484,7 +498,7 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
 
        return event_handled;
 }
-
+#if 0
 static GtkWidget *
 web_view_create_plugin_widget_cb (EWebView *web_view,
                                   const gchar *mime_type,
@@ -502,13 +516,15 @@ web_view_create_plugin_widget_cb (EWebView *web_view,
 
        return class->create_plugin_widget (web_view, mime_type, uri, param);
 }
-
+#endif
 static void
-web_view_hovering_over_link_cb (EWebView *web_view,
-                                const gchar *title,
-                                const gchar *uri)
+web_view_mouse_target_changed_cb (EWebView *web_view,
+                                  WebKitHitTestResult *hit_test_result,
+                                  guint modifiers,
+                                  gpointer user_data)
 {
        EWebViewClass *class;
+       const gchar *title, *uri;
 
        /* XXX WebKitWebView does not provide a class method for
         *     this signal, so we do so we can override the default
@@ -517,26 +533,40 @@ web_view_hovering_over_link_cb (EWebView *web_view,
        class = E_WEB_VIEW_GET_CLASS (web_view);
        g_return_if_fail (class->hovering_over_link != NULL);
 
+       title = webkit_hit_test_result_get_link_title (hit_test_result);
+       uri = webkit_hit_test_result_get_link_uri (hit_test_result);
+
        class->hovering_over_link (web_view, title, uri);
 }
 
 static gboolean
-web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
-                                                  WebKitWebFrame *frame,
-                                                  WebKitNetworkRequest *request,
-                                                  WebKitWebNavigationAction *navigation_action,
-                                                  WebKitWebPolicyDecision *policy_decision)
+web_view_decide_policy_cb (EWebView *web_view,
+                           WebKitPolicyDecision *decision,
+                           WebKitPolicyDecisionType type)
 {
        EWebViewClass *class;
-       WebKitWebNavigationReason reason;
+       WebKitNavigationPolicyDecision *navigation_decision;
+       WebKitNavigationAction *navigation_action;
+       WebKitNavigationType navigation_type;
+       WebKitURIRequest *request;
        const gchar *uri, *frame_uri;
 
-       reason = webkit_web_navigation_action_get_reason (navigation_action);
-       if (reason != WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
+       if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
+               return FALSE;
+
+       navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+       navigation_action = webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
+       navigation_type = webkit_navigation_action_get_navigation_type (navigation_action);
+
+       if (navigation_type != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) {
                return FALSE;
+       }
 
-       uri = webkit_network_request_get_uri (request);
-       frame_uri = webkit_web_frame_get_uri (frame);
+       request = webkit_navigation_action_get_request (navigation_action);
+       uri = webkit_uri_request_get_uri (request);
+       /* FIXME XXX WK2 */
+//     frame_uri = webkit_web_frame_get_uri (frame);
+       frame_uri = "";
 
        /* Allow navigation through fragments in page */
        if (uri && *uri && frame_uri && *frame_uri) {
@@ -588,7 +618,7 @@ web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
        class = E_WEB_VIEW_GET_CLASS (web_view);
        g_return_val_if_fail (class->link_clicked != NULL, FALSE);
 
-       webkit_web_policy_decision_ignore (policy_decision);
+       webkit_policy_decision_ignore (decision);
 
        class->link_clicked (web_view, uri);
 
@@ -621,7 +651,7 @@ style_updated_cb (EWebView *web_view)
 
        e_web_view_add_css_rule_into_style_sheet (
                web_view,
-               "-e-web-view-css-sheet",
+               "-e-web-view-style-sheet",
                ".-e-web-view-background-color",
                style);
 
@@ -640,7 +670,7 @@ style_updated_cb (EWebView *web_view)
 
        e_web_view_add_css_rule_into_style_sheet (
                web_view,
-               "-e-web-view-css-sheet",
+               "-e-web-view-style-sheet",
                ".-e-web-view-text-color",
                style);
 
@@ -649,18 +679,15 @@ style_updated_cb (EWebView *web_view)
 }
 
 static void
-web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
-                                 GParamSpec *pspec,
-                                 gpointer user_data)
+web_view_load_changed_cb (WebKitWebView *webkit_web_view,
+                          WebKitLoadEvent load_event,
+                          gpointer user_data)
 {
-       WebKitLoadStatus status;
        EWebView *web_view;
 
        web_view = E_WEB_VIEW (webkit_web_view);
 
-       status = webkit_web_view_get_load_status (webkit_web_view);
-
-       if (status != WEBKIT_LOAD_FINISHED)
+       if (load_event != WEBKIT_LOAD_FINISHED)
                return;
 
        style_updated_cb (web_view);
@@ -678,6 +705,46 @@ web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
        }
 }
 
+static GObjectConstructParam*
+find_property(guint n_properties,
+              GObjectConstructParam* properties,
+              GParamSpec* param_spec)
+{
+       while (n_properties--) {
+               if (properties->pspec == param_spec)
+                       return properties;
+               properties++;
+       }
+
+       return NULL;
+}
+
+static GObject*
+web_view_constructor (GType type,
+                      guint n_construct_properties,
+                      GObjectConstructParam *construct_properties)
+{
+       GObjectClass* object_class;
+       GParamSpec* param_spec;
+       GObjectConstructParam *param = NULL;
+
+       object_class = G_OBJECT_CLASS(g_type_class_ref(type));
+       g_return_val_if_fail(object_class != NULL, NULL);
+
+       if (construct_properties && n_construct_properties != 0) {
+               param_spec = g_object_class_find_property(object_class, "settings");
+               if ((param = find_property(n_construct_properties, construct_properties, param_spec)))
+                       g_value_take_object (param->value, e_web_view_get_default_webkit_settings ());
+               param_spec = g_object_class_find_property(object_class, "user-content-manager");
+               if ((param = find_property(n_construct_properties, construct_properties, param_spec)))
+                       g_value_take_object (param->value, webkit_user_content_manager_new ());
+       }
+
+       g_type_class_unref (object_class);
+
+       return G_OBJECT_CLASS (e_web_view_parent_class)->constructor(type, n_construct_properties, 
construct_properties);
+}
+
 static void
 web_view_set_property (GObject *object,
                        guint property_id,
@@ -824,12 +891,18 @@ web_view_dispose (GObject *object)
                priv->antialiasing_changed_handler_id = 0;
        }
 
+       if (priv->web_extension_watch_name_id > 0) {
+               g_bus_unwatch_name (priv->web_extension_watch_name_id);
+               priv->web_extension_watch_name_id = 0;
+       }
+
        g_clear_object (&priv->ui_manager);
        g_clear_object (&priv->open_proxy);
        g_clear_object (&priv->print_proxy);
        g_clear_object (&priv->save_as_proxy);
        g_clear_object (&priv->aliasing_settings);
        g_clear_object (&priv->font_settings);
+       g_clear_object (&priv->web_extension);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_web_view_parent_class)->dispose (object);
@@ -858,8 +931,32 @@ web_view_finalize (GObject *object)
 }
 
 static void
+web_view_initialize (WebKitWebView *web_view)
+{
+       const gchar *id = "org.gnome.settings-daemon.plugins.xsettings";
+       GSettings *settings;
+       GSettingsSchema *settings_schema;
+
+       /* Optional schema */
+       settings_schema = g_settings_schema_source_lookup (
+               g_settings_schema_source_get_default (), id, FALSE);
+
+       if (settings_schema)
+               settings = g_settings_new (id);
+       else
+               settings = NULL;
+
+       e_web_view_update_fonts_settings (
+               g_settings_new ("org.gnome.desktop.interface"),
+               settings,
+               NULL, NULL, GTK_WIDGET (web_view));
+}
+
+
+static void
 web_view_constructed (GObject *object)
 {
+       WebKitSettings *web_settings;
 #ifndef G_OS_WIN32
        GSettings *settings;
 
@@ -882,6 +979,16 @@ web_view_constructed (GObject *object)
 
        /* Chain up to parent's constructed() method. */
        G_OBJECT_CLASS (e_web_view_parent_class)->constructed (object);
+
+       web_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (object));
+
+       g_object_bind_property (
+               web_settings, "enable-caret-browsing",
+               E_WEB_VIEW (object), "caret-mode",
+               G_BINDING_BIDIRECTIONAL |
+               G_BINDING_SYNC_CREATE);
+
+       web_view_initialize (WEBKIT_WEB_VIEW (object));
 }
 
 static gboolean
@@ -919,7 +1026,8 @@ web_view_scroll_event (GtkWidget *widget,
                }
        }
 
-       return FALSE;
+       return GTK_WIDGET_CLASS (e_web_view_parent_class)->
+               scroll_event (widget, event);
 }
 
 static gboolean
@@ -1073,9 +1181,8 @@ web_view_load_string (EWebView *web_view,
        if (string == NULL)
                string = "";
 
-       webkit_web_view_load_string (
-               WEBKIT_WEB_VIEW (web_view),
-               string, "text/html", "UTF-8", "evo-file:///");
+       webkit_web_view_load_html (
+               WEBKIT_WEB_VIEW (web_view), string, "evo-file:///");
 }
 
 static void
@@ -1131,8 +1238,73 @@ web_view_stop_loading (EWebView *web_view)
 }
 
 static void
-web_view_update_actions (EWebView *web_view)
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+                                GAsyncResult *result,
+                                EWebView *web_view)
+{
+       GError *error = NULL;
+
+       web_view->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
+       if (!web_view->priv->web_extension) {
+               g_warning ("Error creating web extension proxy: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           const gchar *name_owner,
+                           EWebView *web_view)
+{
+       g_dbus_proxy_new (
+               connection,
+               G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+               G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+               NULL,
+               name,
+               EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+               EVOLUTION_WEB_EXTENSION_INTERFACE,
+               NULL,
+               (GAsyncReadyCallback)web_extension_proxy_created_cb,
+               web_view);
+}
+
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           EWebView *web_view)
+{
+       g_clear_object (&web_view->priv->web_extension);
+}
+
+static void
+web_view_watch_web_extension (EWebView *web_view)
+{
+       web_view->priv->web_extension_watch_name_id =
+               g_bus_watch_name (
+                       G_BUS_TYPE_SESSION,
+                       EVOLUTION_WEB_EXTENSION_SERVICE_NAME,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       (GBusNameAppearedCallback) web_extension_appeared_cb,
+                       (GBusNameVanishedCallback) web_extension_vanished_cb,
+                       web_view, NULL);
+}
+
+GDBusProxy *
+e_web_view_get_web_extension_proxy (EWebView *web_view)
+{
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+       return web_view->priv->web_extension;
+}
+
+static void
+web_view_update_actions_cb (WebKitWebView *webkit_web_view,
+                            GAsyncResult *result,
+                            gpointer user_data)
 {
+       EWebView *web_view;
        GtkActionGroup *action_group;
        gboolean can_copy;
        gboolean scheme_is_http = FALSE;
@@ -1143,8 +1315,11 @@ web_view_update_actions (EWebView *web_view)
        const gchar *group_name;
        const gchar *uri;
 
+       web_view = E_WEB_VIEW (webkit_web_view);
+
        uri = e_web_view_get_selected_uri (web_view);
-       can_copy = webkit_web_view_can_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
+       can_copy = webkit_web_view_can_execute_editing_command_finish (
+               webkit_web_view, result, NULL);
        cursor_image_src = e_web_view_get_cursor_image_src (web_view);
 
        /* Parse the URI early so we know if the actions will work. */
@@ -1206,6 +1381,17 @@ web_view_update_actions (EWebView *web_view)
 }
 
 static void
+eb_view_update_actions (EWebView *web_view)
+{
+       webkit_web_view_can_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view),
+               WEBKIT_EDITING_COMMAND_COPY,
+               NULL, /* cancellable */
+               (GAsyncReadyCallback) web_view_update_actions_cb,
+               NULL);
+}
+
+static void
 web_view_submit_alert (EAlertSink *alert_sink,
                        EAlert *alert)
 {
@@ -1302,6 +1488,19 @@ web_view_submit_alert (EAlertSink *alert_sink,
 }
 
 static void
+web_view_can_execute_editing_command_cb (WebKitWebView *webkit_web_view,
+                                         GAsyncResult *result,
+                                         GtkAction *action)
+{
+       gboolean can_do_command;
+
+       can_do_command = webkit_web_view_can_execute_editing_command_finish (
+               webkit_web_view, result, NULL);
+
+       gtk_action_set_sensitive (action, can_do_command);
+}
+
+static void
 web_view_selectable_update_actions (ESelectable *selectable,
                                     EFocusTracker *focus_tracker,
                                     GdkAtom *clipboard_targets,
@@ -1315,21 +1514,33 @@ web_view_selectable_update_actions (ESelectable *selectable,
        web_view = WEBKIT_WEB_VIEW (selectable);
 
        action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
-       sensitive = webkit_web_view_can_cut_clipboard (web_view);
+       webkit_web_view_can_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view),
+               WEBKIT_EDITING_COMMAND_CUT,
+               NULL, /* cancellable */
+               (GAsyncReadyCallback) web_view_can_execute_editing_command_cb,
+               action);
        tooltip = _("Cut the selection");
-       gtk_action_set_sensitive (action, sensitive);
        gtk_action_set_tooltip (action, tooltip);
 
        action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
-       sensitive = webkit_web_view_can_copy_clipboard (web_view);
+       webkit_web_view_can_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view),
+               WEBKIT_EDITING_COMMAND_COPY,
+               NULL, /* cancellable */
+               (GAsyncReadyCallback) web_view_can_execute_editing_command_cb,
+               action);
        tooltip = _("Copy the selection");
-       gtk_action_set_sensitive (action, sensitive);
        gtk_action_set_tooltip (action, tooltip);
 
        action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
-       sensitive = webkit_web_view_can_paste_clipboard (web_view);
+       webkit_web_view_can_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view),
+               WEBKIT_EDITING_COMMAND_PASTE,
+               NULL, /* cancellable */
+               (GAsyncReadyCallback) web_view_can_execute_editing_command_cb,
+               action);
        tooltip = _("Paste the clipboard");
-       gtk_action_set_sensitive (action, sensitive);
        gtk_action_set_tooltip (action, tooltip);
 
        action = e_focus_tracker_get_select_all_action (focus_tracker);
@@ -1385,30 +1596,6 @@ e_web_view_test_change_and_update_fonts_cb (EWebView *web_view,
        }
 }
 
-static gpointer
-web_view_disable_webkit_3rd_party_plugins (gpointer unused)
-{
-       WebKitWebPluginDatabase *database;
-       GSList *installed_plugins, *iterator;
-
-       database = webkit_get_web_plugin_database ();
-
-       if (!database)
-               return NULL;
-
-       installed_plugins = webkit_web_plugin_database_get_plugins (database);
-
-       if (!installed_plugins)
-               return NULL;
-
-       for (iterator = installed_plugins; iterator; iterator = iterator->next)
-               webkit_web_plugin_set_enabled (iterator->data, FALSE);
-
-       webkit_web_plugin_database_plugins_list_free (installed_plugins);
-
-       return NULL;
-}
-
 static void
 e_web_view_class_init (EWebViewClass *class)
 {
@@ -1418,6 +1605,7 @@ e_web_view_class_init (EWebViewClass *class)
        g_type_class_add_private (class, sizeof (EWebViewPrivate));
 
        object_class = G_OBJECT_CLASS (class);
+       object_class->constructor = web_view_constructor;
        object_class->set_property = web_view_set_property;
        object_class->get_property = web_view_get_property;
        object_class->dispose = web_view_dispose;
@@ -1577,10 +1765,6 @@ e_web_view_class_init (EWebViewClass *class)
                NULL, NULL,
                e_marshal_BOOLEAN__STRING,
                G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
-
-       webkit_set_cache_model (WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
-       webkit_set_default_web_database_quota (0);
-       webkit_application_cache_set_maximum_size (0);
 }
 
 static void
@@ -1600,6 +1784,300 @@ e_web_view_selectable_init (ESelectableInterface *iface)
 }
 
 static void
+web_view_process_uri_scheme_finished_cb (EWebView *web_view,
+                                         GAsyncResult *result,
+                                         WebKitURISchemeRequest *request)
+{
+       GError *error = NULL;
+
+       if (!g_task_propagate_boolean (G_TASK (result), &error)) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_warning ("URI %s cannot be processed: %s",
+                               webkit_uri_scheme_request_get_uri (request),
+                               error ? error->message : "Unknown error");
+               }
+               g_object_unref (request);
+               if (error)
+                       g_error_free (error);
+       }
+}
+
+static void
+web_view_cid_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                     EWebView *web_view)
+{
+}
+
+static void
+web_view_process_file_uri_scheme_request (GTask *task,
+                                          gpointer source_object,
+                                          gpointer task_data,
+                                          GCancellable *cancellable)
+{
+       gboolean ret_val = FALSE;
+       const gchar *uri;
+       gchar *content = NULL;
+       gchar *content_type = NULL;
+       gchar *filename = NULL;
+       GInputStream *stream;
+       gsize length = 0;
+       GError *error = NULL;
+       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
+
+       uri = webkit_uri_scheme_request_get_uri (request);
+
+       filename = g_filename_from_uri (strstr (uri, "file"), NULL, &error);
+       if (!filename)
+               goto out;
+
+       if (!g_file_get_contents (filename, &content, &length, &error))
+               goto out;
+
+       content_type = g_content_type_guess (filename, NULL, 0, NULL);
+
+       stream = g_memory_input_stream_new_from_data (content, length, g_free);
+
+       webkit_uri_scheme_request_finish (request, stream, length, content_type);
+
+       ret_val = TRUE;
+ out:
+       g_free (content_type);
+       g_free (content);
+       g_free (filename);
+
+       if (ret_val)
+               g_object_unref (request);
+
+       if (error)
+               g_task_return_error (task, error);
+       else
+               g_task_return_boolean (task, ret_val);
+}
+
+static void
+web_view_file_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                      EWebView *web_view)
+{
+       GTask *task;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       task = g_task_new (
+               web_view, NULL,
+               (GAsyncReadyCallback) web_view_process_uri_scheme_finished_cb,
+               request);
+
+       g_task_set_task_data (task, g_object_ref (request), NULL);
+       g_task_run_in_thread (task, web_view_process_file_uri_scheme_request);
+
+       g_object_unref (task);
+}
+
+static void
+web_view_mail_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                      EWebView *web_view)
+{
+}
+
+static void
+web_view_gtk_stock_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                           EWebView *web_view)
+{
+       SoupURI *uri;
+       GHashTable *query = NULL;
+       GtkStyleContext *context;
+       GtkWidgetPath *path;
+       GtkIconSet *icon_set;
+       gssize size = GTK_ICON_SIZE_BUTTON;
+       gchar *a_size;
+       gchar *buffer = NULL;
+       gchar *content_type = NULL;
+       gsize buff_len = 0;
+       GError *local_error = NULL;
+
+       uri = soup_uri_new (webkit_uri_scheme_request_get_uri (request));
+
+       if (uri && uri->query)
+               query = soup_form_decode (uri->query);
+
+       if (query) {
+               a_size = g_hash_table_lookup (query, "size");
+               if (a_size != NULL)
+                       size = atoi (a_size);
+               g_hash_table_destroy (query);
+       }
+
+       /* Try style context first */
+       context = gtk_style_context_new ();
+       path = gtk_widget_path_new ();
+       gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
+       gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
+       gtk_style_context_set_path (context, path);
+       gtk_widget_path_free (path);
+
+       if (icon_set != NULL) {
+               GdkPixbuf *pixbuf;
+
+               pixbuf = gtk_icon_set_render_icon_pixbuf (
+                       icon_set, context, size);
+               gdk_pixbuf_save_to_buffer (
+                       pixbuf, &buffer, &buff_len,
+                       "png", &local_error, NULL);
+               g_object_unref (pixbuf);
+       /* Fallback to icon theme */
+       } else {
+               GtkIconTheme *icon_theme;
+               GtkIconInfo *icon_info;
+               const gchar *filename;
+
+               icon_theme = gtk_icon_theme_get_default ();
+
+               icon_info = gtk_icon_theme_lookup_icon (
+                       icon_theme, uri->host, size,
+                       GTK_ICON_LOOKUP_USE_BUILTIN);
+
+               filename = gtk_icon_info_get_filename (icon_info);
+               if (filename != NULL) {
+                       g_file_get_contents (
+                               filename, &buffer, &buff_len, &local_error);
+                       content_type =
+                               g_content_type_guess (filename, NULL, 0, NULL);
+
+               } else {
+                       GdkPixbuf *pixbuf;
+
+                       pixbuf = gtk_icon_info_get_builtin_pixbuf (icon_info);
+                       if (pixbuf != NULL) {
+                               gdk_pixbuf_save_to_buffer (
+                                       pixbuf, &buffer, &buff_len,
+                                       "png", &local_error, NULL);
+                               g_object_unref (pixbuf);
+                       }
+               }
+
+               gtk_icon_info_free (icon_info);
+       }
+
+       /* Sanity check */
+       g_return_if_fail (
+               ((buffer != NULL) && (local_error == NULL)) ||
+               ((buffer == NULL) && (local_error != NULL)));
+
+       if (!content_type)
+               content_type = g_strdup ("image/png");
+
+       if (buffer != NULL) {
+               GInputStream *stream;
+
+               stream = g_memory_input_stream_new_from_data (
+                       buffer, buff_len, (GDestroyNotify) g_free);
+
+               webkit_uri_scheme_request_finish (
+                       request, stream, buff_len, content_type);
+
+               g_object_unref (stream);
+       }
+
+       g_object_unref (context);
+       g_free (content_type);
+}
+
+void
+e_web_view_register_uri_scheme (EWebView *web_view,
+                                EURIScheme scheme,
+                                gpointer user_callback,
+                               gpointer user_data)
+{
+       WebKitWebContext *context;
+       gpointer callback = NULL;
+       const gchar *uri_scheme;
+
+       static GHashTable *hash_table = NULL;
+
+       if (!hash_table)
+               hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
+
+       context = webkit_web_context_get_default ();
+
+       callback = user_callback;
+
+       switch (scheme) {
+               case CID_URI_SCHEME:
+                       uri_scheme = "cid";
+                       if (!callback)
+                               callback = web_view_cid_uri_scheme_appeared_cb;
+                       break;
+               case FILE_URI_SCHEME:
+                       uri_scheme = "evo-file";
+                       if (!callback)
+                               callback = web_view_file_uri_scheme_appeared_cb;
+                       break;
+               case MAIL_URI_SCHEME:
+                       uri_scheme = "mail";
+                       if (!callback)
+                               callback = web_view_mail_uri_scheme_appeared_cb;
+                       break;
+               case EVO_HTTP_URI_SCHEME:
+                       uri_scheme = "evo-http";
+                       if (!callback)
+                               callback = web_view_http_uri_scheme_appeared_cb;
+                       break;
+               case EVO_HTTPS_URI_SCHEME:
+                       uri_scheme = "evo-https";
+                       if (!callback)
+                               callback = web_view_http_uri_scheme_appeared_cb;
+                       break;
+               case GTK_STOCK_URI_SCHEME:
+                       uri_scheme = "gtk-stock";
+                       if (!callback)
+                               callback = web_view_gtk_stock_uri_scheme_appeared_cb;
+                       break;
+               default:
+                       return;
+       }
+
+       if (g_hash_table_lookup (hash_table, uri_scheme))
+               return;
+
+       g_hash_table_insert (hash_table, (gpointer) uri_scheme, callback);
+
+       webkit_web_context_register_uri_scheme (
+               context,
+               uri_scheme,
+               (WebKitURISchemeRequestCallback) callback,
+               user_data ? user_data : web_view,
+               NULL);
+
+}
+
+static void
+web_view_update_fonts (EWebView *web_view)
+{
+       e_web_view_update_fonts (web_view);
+}
+
+void
+e_web_view_update_fonts (EWebView *web_view)
+{
+       EWebViewClass *class;
+       PangoFontDescription *ms = NULL, *vw = NULL;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       class = E_WEB_VIEW_GET_CLASS (web_view);
+       if (class->set_fonts != NULL)
+               class->set_fonts (web_view, &ms, &vw);
+
+       e_web_view_update_fonts_settings (
+               web_view->priv->font_settings,
+               web_view->priv->aliasing_settings,
+               ms, vw, GTK_WIDGET (web_view));
+
+       pango_font_description_free (ms);
+       pango_font_description_free (vw);
+}
+
+static void
 e_web_view_init (EWebView *web_view)
 {
        GtkUIManager *ui_manager;
@@ -1612,52 +2090,47 @@ e_web_view_init (EWebView *web_view)
        gulong handler_id;
        GError *error = NULL;
 
-       g_once (
-               &disable_webkit_3rd_party_plugins_once,
-               web_view_disable_webkit_3rd_party_plugins, NULL);
-
        web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
 
        web_view->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
(GDestroyNotify) g_variant_unref);
 
        /* XXX No WebKitWebView class method pointers to
         *     override so we have to use signal handlers. */
-
-       g_signal_connect (
+#if 0
+       e_signal_connect (
                web_view, "create-plugin-widget",
                G_CALLBACK (web_view_create_plugin_widget_cb), NULL);
-
-       g_signal_connect (
+#endif
+       e_signal_connect (
                web_view, "context-menu",
                G_CALLBACK (web_view_context_menu_cb), NULL);
 
-       g_signal_connect (
-               web_view, "hovering-over-link",
-               G_CALLBACK (web_view_hovering_over_link_cb), NULL);
+       u_signal_connect (
+               web_view, "mouse-target-changed",
+               G_CALLBACK (web_view_mouse_target_changed_cb), NULL);
 
-       g_signal_connect (
-               web_view, "navigation-policy-decision-requested",
-               G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
+       e_signal_connect (
+               web_view, "decide-policy",
+               G_CALLBACK (web_view_decide_policy_cb),
                NULL);
 
-       g_signal_connect (
-               web_view, "new-window-policy-decision-requested",
-               G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
-               NULL);
+       e_signal_connect (
+               webkit_web_context_get_default (), "initialize-web-extensions",
+               G_CALLBACK (initialize_web_extensions_cb), NULL);
 
-       g_signal_connect (
+       e_signal_connect (
+               web_view, "load-changed",
+               G_CALLBACK (web_view_load_changed_cb), NULL);
+
+       e_signal_connect (
                web_view, "document-load-finished",
                G_CALLBACK (style_updated_cb), NULL);
 
-       e_signal_connect_notify (
-               web_view, "notify::load-status",
-               G_CALLBACK (web_view_load_status_changed_cb), NULL);
-
-       g_signal_connect (
+       e_signal_connect (
                web_view, "style-updated",
                G_CALLBACK (style_updated_cb), NULL);
 
-       g_signal_connect (
+       e_signal_connect (
                web_view, "state-flags-changed",
                G_CALLBACK (style_updated_cb), NULL);
 
@@ -1668,10 +2141,10 @@ e_web_view_init (EWebView *web_view)
                ui_manager, "connect-proxy",
                G_CALLBACK (web_view_connect_proxy_cb), web_view);
 
-       web_view_init_web_settings (WEBKIT_WEB_VIEW (web_view));
+       web_view_watch_web_extension (web_view);
 
-       e_web_view_install_request_handler (web_view, E_TYPE_FILE_REQUEST);
-       e_web_view_install_request_handler (web_view, E_TYPE_STOCK_REQUEST);
+       e_web_view_register_uri_scheme (web_view, FILE_URI_SCHEME, NULL, NULL);
+       e_web_view_register_uri_scheme (web_view, GTK_STOCK_URI_SCHEME, NULL, NULL);
 
        settings = e_util_ref_settings ("org.gnome.desktop.interface");
        web_view->priv->font_settings = g_object_ref (settings);
@@ -1700,8 +2173,6 @@ e_web_view_init (EWebView *web_view)
                g_settings_schema_unref (settings_schema);
        }
 
-       e_web_view_update_fonts (web_view);
-
        action_group = gtk_action_group_new ("uri");
        gtk_action_group_set_translation_domain (action_group, domain);
        gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
@@ -1808,14 +2279,14 @@ e_web_view_init (EWebView *web_view)
        id = "org.gnome.evolution.webview";
        e_plugin_ui_register_manager (ui_manager, id, web_view);
        e_plugin_ui_enable_manager (ui_manager, id);
-
-       e_web_view_clear (E_WEB_VIEW (web_view));
 }
 
 GtkWidget *
 e_web_view_new (void)
 {
-       return g_object_new (E_TYPE_WEB_VIEW, NULL);
+       return g_object_new (
+               E_TYPE_WEB_VIEW,
+               NULL);
 }
 
 void
@@ -1823,7 +2294,7 @@ e_web_view_clear (EWebView *web_view)
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       webkit_web_view_load_html_string (
+       webkit_web_view_load_html (
                WEBKIT_WEB_VIEW (web_view),
                "<html>"
                "<head></head>"
@@ -1940,19 +2411,100 @@ e_web_view_reload (EWebView *web_view)
        webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
 }
 
-gchar *
-e_web_view_get_html (EWebView *web_view)
+static void
+get_document_content_html_cb (GDBusProxy *web_extension,
+                              GAsyncResult *result,
+                              GTask *task)
 {
-       WebKitDOMDocument *document;
-       WebKitDOMElement *element;
+       GVariant *result_variant;
+       const gchar *html_content;
 
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               html_content = g_variant_get_string (result_variant, NULL);
+               g_variant_unref (result_variant);
+       }
+
+       g_task_return_pointer (task, g_strdup (html_content), g_free);
+       g_object_unref (task);
+}
+
+void
+e_web_view_get_content_html (EWebView *web_view,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       GDBusProxy *web_extension;
+       GTask *task;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       task = g_task_new (web_view, cancellable, callback, user_data);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               g_dbus_proxy_call (
+                       web_extension,
+                       "GetDocumentContentHtml",
+                       g_variant_new (
+                               "(t)",
+                               webkit_web_view_get_page_id (
+                                       WEBKIT_WEB_VIEW (web_view))),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       cancellable,
+                       (GAsyncReadyCallback) get_document_content_html_cb,
+                       g_object_ref (task));
+       } else
+               g_task_return_pointer (task, NULL, NULL);
+}
+
+const gchar *
+e_web_view_get_content_html_finish (EWebView *web_view,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+       g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
 
-       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
-       element = webkit_dom_document_get_document_element (document);
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+const gchar *
+e_web_view_get_content_html_sync (EWebView *web_view,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       GDBusProxy *web_extension;
+
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               GVariant *result;
+               const gchar *html_content = NULL;
+
+               result = g_dbus_proxy_call_sync (
+                               web_extension,
+                               "GetDocumentContentHTML",
+                               g_variant_new (
+                                       "(t)",
+                                       webkit_web_view_get_page_id (
+                                               WEBKIT_WEB_VIEW (web_view))),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               cancellable,
+                               error);
+
+               if (result) {
+                       html_content = g_variant_get_string (result, NULL);
+                       g_variant_unref (result);
+                       return html_content;
+               }
+       }
 
-       return webkit_dom_html_element_get_outer_html (
-               WEBKIT_DOM_HTML_ELEMENT (element));
+       return NULL;
 }
 
 gboolean
@@ -1982,8 +2534,10 @@ e_web_view_get_copy_target_list (EWebView *web_view)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
 
-       return webkit_web_view_get_copy_target_list (
-               WEBKIT_WEB_VIEW (web_view));
+       return NULL;
+       /* FIXME XXX WK2 */
+//     return webkit_web_view_get_copy_target_list (
+//             WEBKIT_WEB_VIEW (web_view));
 }
 
 gboolean
@@ -2035,7 +2589,9 @@ e_web_view_get_editable (EWebView *web_view)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
 
-       return webkit_web_view_get_editable (WEBKIT_WEB_VIEW (web_view));
+       /* FIXME XXX WK2 */
+//     return webkit_web_view_get_editable (WEBKIT_WEB_VIEW (web_view));
+       return TRUE;
 }
 
 void
@@ -2044,6 +2600,7 @@ e_web_view_set_editable (EWebView *web_view,
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
+       /* FIXME XXX WK2 */
        webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view), editable);
 }
 
@@ -2128,8 +2685,10 @@ e_web_view_get_paste_target_list (EWebView *web_view)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
 
+       /* FIXME XXX WK2
        return webkit_web_view_get_paste_target_list (
-               WEBKIT_WEB_VIEW (web_view));
+               WEBKIT_WEB_VIEW (web_view)); */
+       return NULL;
 }
 
 GtkAction *
@@ -2203,11 +2762,11 @@ e_web_view_add_highlight (EWebView *web_view,
                &web_view->priv->highlights,
                g_strdup (highlight));
 
-       webkit_web_view_mark_text_matches (
-               WEBKIT_WEB_VIEW (web_view), highlight, FALSE, 0);
-
-       webkit_web_view_set_highlight_text_matches (
-               WEBKIT_WEB_VIEW (web_view), TRUE);
+       webkit_find_controller_search (
+               web_view->priv->find_controller,
+               highlight,
+               WEBKIT_FIND_OPTIONS_NONE,
+               G_MAXUINT);
 }
 
 void
@@ -2215,7 +2774,10 @@ e_web_view_clear_highlights (EWebView *web_view)
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+       if (!web_view->priv->find_controller)
+               web_view_set_find_controller (web_view);
+
+       webkit_find_controller_search_finish (web_view->priv->find_controller);
 
        while (!g_queue_is_empty (&web_view->priv->highlights))
                g_free (g_queue_pop_head (&web_view->priv->highlights));
@@ -2262,7 +2824,8 @@ e_web_view_copy_clipboard (EWebView *web_view)
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
+       webkit_web_view_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_COPY);
 }
 
 void
@@ -2270,7 +2833,8 @@ e_web_view_cut_clipboard (EWebView *web_view)
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       webkit_web_view_cut_clipboard (WEBKIT_WEB_VIEW (web_view));
+       webkit_web_view_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_CUT);
 }
 
 gboolean
@@ -2278,7 +2842,9 @@ e_web_view_is_selection_active (EWebView *web_view)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
 
-       return webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view));
+       /* FIXME XXX WK2
+       return webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view));*/
+       return FALSE;
 }
 
 void
@@ -2286,17 +2852,18 @@ e_web_view_paste_clipboard (EWebView *web_view)
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       webkit_web_view_paste_clipboard (WEBKIT_WEB_VIEW (web_view));
+       webkit_web_view_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_PASTE);
 }
 
 gboolean
 e_web_view_scroll_forward (EWebView *web_view)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
-
+/* FIXME XXX WK2
        webkit_web_view_move_cursor (
                WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, 1);
-
+*/
        return TRUE;  /* XXX This means nothing. */
 }
 
@@ -2304,10 +2871,10 @@ gboolean
 e_web_view_scroll_backward (EWebView *web_view)
 {
        g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
-
+/* FIXME XXX WK2
        webkit_web_view_move_cursor (
                WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, -1);
-
+*/
        return TRUE;  /* XXX This means nothing. */
 }
 
@@ -2316,7 +2883,8 @@ e_web_view_select_all (EWebView *web_view)
 {
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       webkit_web_view_select_all (WEBKIT_WEB_VIEW (web_view));
+       webkit_web_view_execute_editing_command (
+               WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_SELECT_ALL);
 }
 
 void
@@ -2340,19 +2908,31 @@ e_web_view_zoom_100 (EWebView *web_view)
 void
 e_web_view_zoom_in (EWebView *web_view)
 {
+       gdouble zoom_level;
+
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       if (webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) < 4.9999)
-               webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
+       /* There is no webkit_web_view_zoom_in function in WK2, so emulate it */
+       zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view));
+       /* zoom-step in WK1 was 0.1 */
+       zoom_level += 0.1;
+       if (zoom_level < 4.9999) {
+               webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), zoom_level);
 }
 
 void
 e_web_view_zoom_out (EWebView *web_view)
 {
+       gdouble zoom_level;
+
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-       if (webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) > 0.1999)
-               webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
+       /* There is no webkit_web_view_zoom_out function in WK2, so emulate it */
+       zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view));
+       /* zoom-step in WK1 was 0.1 */
+       zoom_level -= 0.1;
+       if (zoom_level > 0.1999)
+               webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), zoom_level);
 }
 
 GtkUIManager *
@@ -2476,6 +3056,102 @@ element_is_in_pre_tag (WebKitDOMNode *node)
        return FALSE;
 }
 
+static void
+get_selection_content_html_cb (GDBusProxy *web_extension,
+                               GAsyncResult *result,
+                               GTask *task)
+{
+       GVariant *result_variant;
+       const gchar *html_content;
+
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               html_content = g_variant_get_string (result_variant, NULL);
+               g_variant_unref (result_variant);
+       }
+
+       g_task_return_pointer (task, g_strdup (html_content), g_free);
+       g_object_unref (task);
+}
+
+void
+e_web_view_get_selection_content_html (EWebView *web_view,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
+{
+       GDBusProxy *web_extension;
+       GTask *task;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       task = g_task_new (web_view, cancellable, callback, user_data);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               g_dbus_proxy_call (
+                       web_extension,
+                       "GetSelectionContentHTML",
+                       g_variant_new (
+                               "(t)",
+                               webkit_web_view_get_page_id (
+                                       WEBKIT_WEB_VIEW (web_view))),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       cancellable,
+                       (GAsyncReadyCallback) get_selection_content_html_cb,
+                       g_object_ref (task));
+       } else
+               g_task_return_pointer (task, NULL, NULL);
+}
+
+const gchar *
+e_web_view_get_selection_content_html_finish (EWebView *web_view,
+                                              GAsyncResult *result,
+                                              GError **error)
+{
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+       g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
+
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+const gchar *
+e_web_view_get_selection_content_html_sync (EWebView *web_view,
+                                            GCancellable *cancellable,
+                                            GError **error)
+{
+       GDBusProxy *web_extension;
+
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               GVariant *result;
+               const gchar *html_content = NULL;
+
+               result = g_dbus_proxy_call_sync (
+                               web_extension,
+                               "GetSelectionContentHtml",
+                               g_variant_new (
+                                       "(t)",
+                                       webkit_web_view_get_page_id (
+                                               WEBKIT_WEB_VIEW (web_view))),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               cancellable,
+                               error);
+
+               if (result) {
+                       html_content = g_variant_get_string (result, NULL);
+                       g_variant_unref (result);
+                       return html_content;
+               }
+       }
+
+       return NULL;
+}
+
 static gchar *
 web_view_get_frame_selection_html (WebKitDOMElement *iframe)
 {
@@ -2574,61 +3250,98 @@ e_web_view_get_selection_html (EWebView *web_view)
        return NULL;
 }
 
+static gdouble
+get_screen_dpi (GdkScreen *screen)
+{
+       gdouble dpi;
+       gdouble dp, di;
+
+       dpi = gdk_screen_get_resolution (screen);
+       if (dpi != -1)
+               return dpi;
+
+       dp = hypot (gdk_screen_get_width (screen), gdk_screen_get_height (screen));
+       di = hypot (gdk_screen_get_width_mm (screen), gdk_screen_get_height_mm (screen)) / 25.4;
+
+       return dp / di;
+}
+
+static guint
+normalize_font_size (GtkWidget *widget,
+                     gdouble font_size)
+{
+       /* WebKit2 uses font sizes in pixels. */
+       GdkScreen *screen;
+       gdouble dpi;
+
+       if (widget) {
+               screen = gtk_widget_has_screen (widget) ?
+                       gtk_widget_get_screen (widget) : gdk_screen_get_default ();
+       } else {
+               screen = gdk_screen_get_default ();
+       }
+
+       dpi = screen ? get_screen_dpi (screen) : 96;
+
+       return font_size / 72.0 * dpi;
+}
+
 void
-e_web_view_update_fonts (EWebView *web_view)
+e_web_view_update_fonts_settings (GSettings *font_settings,
+                                  GSettings *aliasing_settings,
+                                  PangoFontDescription *ms_font,
+                                  PangoFontDescription *vw_font,
+                                  GtkWidget *view_widget)
 {
-       EWebViewClass *class;
-       GString *stylesheet;
-       gchar *base64;
+       gboolean clean_ms = FALSE, clean_vw = FALSE;
        gchar *aa = NULL;
-       WebKitWebSettings *settings;
-       PangoFontDescription *min_size, *ms, *vw;
        const gchar *styles[] = { "normal", "oblique", "italic" };
        const gchar *smoothing = NULL;
-       GtkStyleContext *context;
        GdkColor *link = NULL;
        GdkColor *visited = NULL;
+       GString *stylesheet;
+       GtkStyleContext *context;
+       PangoFontDescription *min_size, *ms, *vw;
+       WebKitSettings *wk_settings;
+       WebKitUserContentManager *manager;
+       WebKitUserStyleSheet *style_sheet;
 
-       g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
-       ms = NULL;
-       vw = NULL;
-
-       class = E_WEB_VIEW_GET_CLASS (web_view);
-       if (class->set_fonts != NULL)
-               class->set_fonts (web_view, &ms, &vw);
-
-       if (ms == NULL) {
+       if (!ms_font) {
                gchar *font;
 
                font = g_settings_get_string (
-                       web_view->priv->font_settings,
+                       font_settings,
                        "monospace-font-name");
 
                ms = pango_font_description_from_string (
                        (font != NULL) ? font : "monospace 10");
 
+               clean_ms = TRUE;
+
                g_free (font);
-       }
+       } else
+               ms = ms_font;
 
-       if (vw == NULL) {
+       if (!vw_font) {
                gchar *font;
 
                font = g_settings_get_string (
-                       web_view->priv->font_settings,
+                       font_settings,
                        "font-name");
 
                vw = pango_font_description_from_string (
                        (font != NULL) ? font : "serif 10");
 
+               clean_vw = TRUE;
+
                g_free (font);
-       }
+       } else
+               vw = vw_font;
 
-       if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw)) {
+       if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw))
                min_size = ms;
-       } else {
+       else
                min_size = vw;
-       }
 
        stylesheet = g_string_new ("");
        g_string_append_printf (
@@ -2643,9 +3356,9 @@ e_web_view_update_fonts (EWebView *web_view)
                pango_font_description_get_weight (vw),
                styles[pango_font_description_get_style (vw)]);
 
-       if (web_view->priv->aliasing_settings != NULL)
+       if (aliasing_settings != NULL)
                aa = g_settings_get_string (
-                       web_view->priv->aliasing_settings, "antialiasing");
+                       aliasing_settings, "antialiasing");
 
        if (g_strcmp0 (aa, "none") == 0)
                smoothing = "none";
@@ -2671,73 +3384,165 @@ e_web_view_update_fonts (EWebView *web_view)
                "  font-size: %dpt;\n"
                "  font-weight: %d;\n"
                "  font-style: %s;\n"
-               "}",
+               "} \n",
                pango_font_description_get_family (ms),
                pango_font_description_get_size (ms) / PANGO_SCALE,
                pango_font_description_get_weight (ms),
                styles[pango_font_description_get_style (ms)]);
 
-       context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
-       gtk_style_context_get_style (
-               context,
-               "link-color", &link,
-               "visited-link-color", &visited,
-               NULL);
+       if (view_widget) {
+               context = gtk_widget_get_style_context (view_widget);
+               gtk_style_context_get_style (
+                       context,
+                       "link-color", &link,
+                       "visited-link-color", &visited,
+                       NULL);
 
-       if (link == NULL) {
-               link = g_slice_new0 (GdkColor);
-               link->blue = G_MAXINT16;
-       }
+               if (link == NULL) {
+                       link = g_slice_new0 (GdkColor);
+                       link->blue = G_MAXINT16;
+               }
 
-       if (visited == NULL) {
-               visited = g_slice_new0 (GdkColor);
-               visited->red = G_MAXINT16;
-       }
+               if (visited == NULL) {
+                       visited = g_slice_new0 (GdkColor);
+                       visited->red = G_MAXINT16;
+               }
 
-       g_string_append_printf (
-               stylesheet,
-               "a {\n"
-               "  color: #%06x;\n"
-               "}\n"
-               "a:visited {\n"
-               "  color: #%06x;\n"
-               "}\n",
-               e_color_to_value (link),
-               e_color_to_value (visited));
-
-       gdk_color_free (link);
-       gdk_color_free (visited);
-
-       base64 = g_base64_encode ((guchar *) stylesheet->str, stylesheet->len);
-       g_string_free (stylesheet, TRUE);
+               g_string_append_printf (
+                       stylesheet,
+                       "a {\n"
+                       "  color: #%06x;\n"
+                       "}\n"
+                       "a:visited {\n"
+                       "  color: #%06x;\n"
+                       "}\n",
+                       e_color_to_value (link),
+                       e_color_to_value (visited));
+
+               gdk_color_free (link);
+               gdk_color_free (visited);
+       }
 
-       stylesheet = g_string_new ("data:text/css;charset=utf-8;base64,");
-       g_string_append (stylesheet, base64);
-       g_free (base64);
+       wk_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view_widget));
 
-       settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
        g_object_set (
-               G_OBJECT (settings),
+               wk_settings,
                "default-font-size",
-               pango_font_description_get_size (vw) / PANGO_SCALE,
+               normalize_font_size (
+                       view_widget, pango_font_description_get_size (vw) / PANGO_SCALE),
                "default-font-family",
                pango_font_description_get_family (vw),
                "monospace-font-family",
                pango_font_description_get_family (ms),
                "default-monospace-font-size",
-               pango_font_description_get_size (ms) / PANGO_SCALE,
+               normalize_font_size (
+                       view_widget, pango_font_description_get_size (ms) / PANGO_SCALE),
                "minimum-font-size",
-               pango_font_description_get_size (min_size) / PANGO_SCALE,
-               "user-stylesheet-uri",
+               normalize_font_size (
+                       view_widget, pango_font_description_get_size (min_size) / PANGO_SCALE),
+               NULL);
+
+       manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (view_widget));
+       webkit_user_content_manager_remove_all_style_sheets (manager);
+
+       webkit_user_style_sheet_new (
                stylesheet->str,
+               WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+               WEBKIT_USER_STYLE_LEVEL_USER,
+               NULL,
                NULL);
 
+       webkit_user_content_manager_add_style_sheet (manager, style_sheet);
+
+       webkit_user_style_sheet_unref (style_sheet);
+
        g_string_free (stylesheet, TRUE);
 
+       if (clean_ms)
+               pango_font_description_free (ms);
+       if (clean_vw)
+               pango_font_description_free (vw);
+}
+
+WebKitSettings *
+e_web_view_get_default_webkit_settings (void)
+{
+       return webkit_settings_new_with_settings (
+               "auto-load-images", TRUE,
+               "default-charset", "utf-8",
+               "enable-html5-database", FALSE,
+               "enable-html5-local-storage", FALSE,
+               "enable-java", FALSE,
+               "enable-javascript", FALSE,
+               "enable-offline-web-application-cache", FALSE,
+               "enable-page-cache", FALSE,
+               "enable-plugins", FALSE,
+               "enable-private-browsing", TRUE,
+               "enable-smooth-scrolling", TRUE,
+               "media-playback-allows-inline", FALSE,
+               NULL);
+}
+
+static void
+initialize_web_extensions_cb (WebKitWebContext *web_context,
+                              gpointer user_data)
+{
+       /* Set the web extensions dir before the process is launched */
+       webkit_web_context_set_web_extensions_directory (
+               web_context, EVOLUTION_WEB_EXTENSIONS_DIR);
+
+       webkit_web_context_set_cache_model (
+               web_context, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+}
+
+void
+e_web_view_update_fonts (EWebView *web_view)
+{
+       EWebViewClass *class;
+       PangoFontDescription *ms = NULL, *vw = NULL;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       class = E_WEB_VIEW_GET_CLASS (web_view);
+       if (class->set_fonts != NULL)
+               class->set_fonts (web_view, &ms, &vw);
+
+       e_web_view_update_fonts_settings (
+               web_view->priv->font_settings,
+               web_view->priv->aliasing_settings,
+               ms, vw, GTK_WIDGET (web_view));
+
        pango_font_description_free (ms);
        pango_font_description_free (vw);
 }
 
+WebKitWebViewGroup *
+e_web_view_get_web_view_group (void)
+{
+       static WebKitWebViewGroup *web_view_group = NULL;
+
+       if (!web_view_group) {
+               web_view_group = webkit_web_view_group_new ("Evolution WebView Group");
+               web_view_initialize_group (web_view_group);
+       }
+
+       return web_view_group;
+}
+
+void
+e_web_view_initialize_webkit (void)
+{
+       WebKitWebContext *web_context;
+
+       web_context = webkit_web_context_get_default ();
+
+       /* Set the web extensions dir before the process is launched */
+       webkit_web_context_set_web_extensions_directory (
+               web_context, EVOLUTION_WEB_EXTENSIONS_DIR);
+
+       webkit_web_context_set_cache_model (web_context, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+}
+
 /* Helper for e_web_view_cursor_image_copy() */
 static void
 web_view_cursor_image_copy_pixbuf_cb (GObject *source_object,
@@ -3149,7 +3954,8 @@ e_web_view_request (EWebView *web_view,
        g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (uri != NULL);
 
-       session = webkit_get_default_session ();
+//     session = webkit_get_default_session ();
+       session = NULL;
 
        async_context = g_slice_new0 (AsyncContext);
 
@@ -3223,154 +4029,51 @@ e_web_view_request_finish (EWebView *web_view,
 
        return g_object_ref (async_context->input_stream);
 }
-
+/*
 void
 e_web_view_install_request_handler (EWebView *web_view,
                                     GType handler_type)
 {
        SoupSession *session;
 
-       session = webkit_get_default_session ();
+//     session = webkit_get_default_session ();
+       session = NULL;
        soup_session_add_feature_by_type (session, handler_type);
 }
-
+*/
+/**
+ * e_web_view_create_and_add_css_style_sheet:
+ * @web_view: an #EWebView
+ * @style_sheet_id: CSS style sheet's id
+ *
+ * Creates new CSS style sheet with given @style_sheel_id and inserts
+ * it into given @web_view document.
+ **/
 void
-e_web_view_create_and_add_css_style_sheet (WebKitDOMDocument *document,
+e_web_view_create_and_add_css_style_sheet (EWebView *web_view,
                                            const gchar *style_sheet_id)
 {
-       WebKitDOMElement *style_element;
-
-       style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
-
-       if (!style_element) {
-               /* Create new <style> element */
-               style_element = webkit_dom_document_create_element (document, "style", NULL);
-               webkit_dom_element_set_id (
-                       WEBKIT_DOM_ELEMENT (style_element),
-                       style_sheet_id);
-               webkit_dom_html_style_element_set_media (
-                       WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element),
-                       "screen");
-               webkit_dom_node_append_child (
-                       WEBKIT_DOM_NODE (style_element),
-                       /* WebKit hack - we have to insert empty TextNode into style element */
-                       WEBKIT_DOM_NODE (webkit_dom_document_create_text_node (document, "")),
-                       NULL);
-
-               webkit_dom_node_append_child (
-                       WEBKIT_DOM_NODE (webkit_dom_document_get_head (document)),
-                       WEBKIT_DOM_NODE (style_element),
-                       NULL);
-       }
-}
-
-static void
-add_css_rule_into_style_sheet (WebKitDOMDocument *document,
-                               const gchar *style_sheet_id,
-                               const gchar *selector,
-                               const gchar *style)
-{
-       WebKitDOMElement *style_element;
-       WebKitDOMStyleSheet *sheet;
-       WebKitDOMCSSRuleList *rules_list;
-       gint length, ii;
-
-       style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
-
-       if (!style_element) {
-               e_web_view_create_and_add_css_style_sheet (document, style_sheet_id);
-               style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
-       }
-
-       /* Get sheet that is associated with style element */
-       sheet = webkit_dom_html_style_element_get_sheet (WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element));
-
-       rules_list = webkit_dom_css_style_sheet_get_css_rules (WEBKIT_DOM_CSS_STYLE_SHEET (sheet));
-       length = webkit_dom_css_rule_list_get_length (rules_list);
-
-       /* Check if rule exists */
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMCSSRule *rule;
-               gchar *rule_text;
-               gchar *rule_selector, *selector_end;
-
-               rule = webkit_dom_css_rule_list_item (rules_list, ii);
-
-               if (!WEBKIT_DOM_IS_CSS_RULE (rule))
-                       continue;
-
-               rule_text = webkit_dom_css_rule_get_css_text (rule);
-
-               /* Find the start of the style => end of the selector */
-               selector_end = g_strstr_len (rule_text, -1, " {");
-               if (!selector_end) {
-                       g_free (rule_text);
-                       continue;
-               }
-
-               rule_selector =
-                       g_utf8_substring (
-                               rule_text,
-                               0,
-                               g_utf8_pointer_to_offset (rule_text, selector_end));
-
-               if (g_strcmp0 (rule_selector, selector) == 0) {
-                       /* If exists remove it */
-                       webkit_dom_css_style_sheet_remove_rule (
-                               WEBKIT_DOM_CSS_STYLE_SHEET (sheet),
-                               ii, NULL);
-               }
-
-               g_free (rule_selector);
-               g_free (rule_text);
-       }
-
-       /* Insert the rule at the end, so it will override previously inserted */
-       webkit_dom_css_style_sheet_add_rule (
-               WEBKIT_DOM_CSS_STYLE_SHEET (sheet),
-               selector,
-               style,
-               webkit_dom_css_rule_list_get_length (
-                       webkit_dom_css_style_sheet_get_css_rules (
-                               WEBKIT_DOM_CSS_STYLE_SHEET (sheet))), /* Index */
-               NULL);
-}
-
-static void
-add_css_rule_into_style_sheet_recursive (WebKitDOMDocument *document,
-                                         const gchar *style_sheet_id,
-                                         const gchar *selector,
-                                         const gchar *style)
-{
-       WebKitDOMNodeList *frames;
-       gint ii, length;
-
-       /* Add rule to document */
-       add_css_rule_into_style_sheet (
-               document,
-               style_sheet_id,
-               selector,
-               style);
-
-       frames = webkit_dom_document_query_selector_all (document, "iframe", NULL);
-       length = webkit_dom_node_list_get_length (frames);
+       GDBusProxy *web_extension;
 
-       /* Add rules to every sub document */
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMDocument *iframe_document;
-               WebKitDOMNode *node;
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+       g_return_if_fail (style_sheet_id && *style_sheet_id);
 
-               node = webkit_dom_node_list_item (frames, ii);
-               iframe_document = webkit_dom_html_iframe_element_get_content_document (
-                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
-
-               add_css_rule_into_style_sheet_recursive (
-                       iframe_document,
-                       style_sheet_id,
-                       selector,
-                       style);
-       }
-       g_object_unref (frames);
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               g_dbus_proxy_call (
+                       web_extension,
+                       "CreateAndAddCSSStyleSheet",
+                       g_variant_new (
+                               "(ts)",
+                               webkit_web_view_get_page_id (
+                                       WEBKIT_WEB_VIEW (web_view)),
+                               style_sheet_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       }
 }
 
 /**
@@ -3387,21 +4090,36 @@ add_css_rule_into_style_sheet_recursive (WebKitDOMDocument *document,
  * into DOM documents inside iframe elements.
  **/
 void
-e_web_view_add_css_rule_into_style_sheet (EWebView *view,
+e_web_view_add_css_rule_into_style_sheet (EWebView *web_view,
                                           const gchar *style_sheet_id,
                                           const gchar *selector,
                                           const gchar *style)
 {
-       g_return_if_fail (E_IS_WEB_VIEW (view));
+       GDBusProxy *web_extension;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
        g_return_if_fail (style_sheet_id && *style_sheet_id);
        g_return_if_fail (selector && *selector);
        g_return_if_fail (style && *style);
 
-       add_css_rule_into_style_sheet_recursive (
-               webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view)),
-               style_sheet_id,
-               selector,
-               style);
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               g_dbus_proxy_call (
+                       web_extension,
+                       "AddCSSRuleIntoStyleSheet",
+                       g_variant_new (
+                               "(tsss)",
+                               webkit_web_view_get_page_id (
+                                       WEBKIT_WEB_VIEW (web_view)),
+                               style_sheet_id,
+                               selector,
+                               style),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       }
 }
 
 gboolean
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index 1836f70..a1ddde6 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -28,7 +28,7 @@
 #ifndef E_WEB_VIEW_H
 #define E_WEB_VIEW_H
 
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
 #include <e-util/e-activity.h>
 
 /* Standard GObject macros */
@@ -56,6 +56,15 @@ typedef struct _EWebView EWebView;
 typedef struct _EWebViewClass EWebViewClass;
 typedef struct _EWebViewPrivate EWebViewPrivate;
 
+typedef enum {
+       CID_URI_SCHEME,
+       FILE_URI_SCHEME,
+       MAIL_URI_SCHEME,
+       EVO_HTTP_URI_SCHEME,
+       EVO_HTTPS_URI_SCHEME,
+       GTK_STOCK_URI_SCHEME
+} EURIScheme;
+
 struct _EWebView {
        WebKitWebView parent;
        EWebViewPrivate *priv;
@@ -101,6 +110,15 @@ struct _EWebViewClass {
 
 GType          e_web_view_get_type             (void) G_GNUC_CONST;
 GtkWidget *    e_web_view_new                  (void);
+WebKitSettings *
+               e_web_view_get_default_webkit_settings
+                                               (void);
+void           e_web_view_update_fonts_settings
+                                               (GSettings *font_settings,
+                                                GSettings *aliasing_settings,
+                                                PangoFontDescription *ms_font,
+                                                PangoFontDescription *vw_font,
+                                                GtkWidget *view_widget);
 void           e_web_view_clear                (EWebView *web_view);
 void           e_web_view_load_string          (EWebView *web_view,
                                                 const gchar *string);
@@ -111,7 +129,20 @@ gchar *            e_web_view_redirect_uri         (EWebView *web_view,
 gchar *                e_web_view_suggest_filename     (EWebView *web_view,
                                                 const gchar *uri);
 void           e_web_view_reload               (EWebView *web_view);
-gchar *                e_web_view_get_html             (EWebView *web_view);
+void           e_web_view_get_content_html     (EWebView *web_view,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+const gchar *  e_web_view_get_content_html_finish
+                                               (EWebView *web_view,
+                                                GAsyncResult *result,
+                                                GError **error);
+const gchar *  e_web_view_get_content_html_sync
+                                               (EWebView *web_view,
+                                                GCancellable *cancellable,
+                                                GError **error);
+GDBusProxy *   e_web_view_get_web_extension_proxy
+                                               (EWebView *web_view);
 gboolean       e_web_view_get_caret_mode       (EWebView *web_view);
 void           e_web_view_set_caret_mode       (EWebView *web_view,
                                                 gboolean caret_mode);
@@ -180,7 +211,19 @@ void               e_web_view_status_message       (EWebView *web_view,
                                                 const gchar *status_message);
 void           e_web_view_stop_loading         (EWebView *web_view);
 void           e_web_view_update_actions       (EWebView *web_view);
-gchar *                e_web_view_get_selection_html   (EWebView *web_view);
+void           e_web_view_get_selection_content_html
+                                               (EWebView *web_view,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+const gchar *  e_web_view_get_selection_content_html_finish
+                                               (EWebView *web_view,
+                                                GAsyncResult *result,
+                                                GError **error);
+const gchar *  e_web_view_get_selection_content_html_sync
+                                               (EWebView *web_view,
+                                                GCancellable *cancellable,
+                                                GError **error);
 void           e_web_view_update_fonts         (EWebView *web_view);
 void           e_web_view_cursor_image_copy    (EWebView *web_view);
 void           e_web_view_cursor_image_save    (EWebView *web_view);
@@ -192,6 +235,10 @@ void               e_web_view_request              (EWebView *web_view,
 GInputStream * e_web_view_request_finish       (EWebView *web_view,
                                                 GAsyncResult *result,
                                                 GError **error);
+void           e_web_view_register_uri_scheme  (EWebView *web_view,
+                                                EURIScheme scheme,
+                                                gpointer user_callback,
+                                                gpointer user_data);
 void           e_web_view_install_request_handler
                                                (EWebView *web_view,
                                                 GType handler_type);
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index 7827d79..70ae62d 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -30,6 +30,7 @@ evolution_mail_formatter_include_HEADERS =            \
        e-mail-formatter-quote.h                        \
        e-mail-formatter-utils.h                        \
        e-mail-inline-filter.h                          \
+       e-mail-meta-remove-filter.h                     \
        e-mail-parser-extension.h                       \
        e-mail-parser.h                                 \
        e-mail-part.h                                   \
@@ -89,6 +90,7 @@ libevolution_mail_formatter_la_SOURCES =              \
        e-mail-formatter-quote-text-enriched.c          \
        e-mail-formatter-quote-text-html.c              \
        e-mail-formatter-quote-text-plain.c             \
+       e-mail-meta-remove-filter.c                     \
        e-mail-parser-extension.c                       \
        e-mail-parser.c                                 \
        e-mail-parser-application-mbox.c                \
diff --git a/em-format/e-mail-formatter-headers.c b/em-format/e-mail-formatter-headers.c
index a16571d..12445f6 100644
--- a/em-format/e-mail-formatter-headers.c
+++ b/em-format/e-mail-formatter-headers.c
@@ -519,7 +519,7 @@ emfe_headers_format (EMailFormatterExtension *extension,
        g_string_append_printf (
                buffer,
                "%s id=\"%s\"><table class=\"-e-mail-formatter-header-color\" border=\"0\" width=\"100%%\" "
-               "style=\"direction: %s\">"
+               "style=\"direction: %s; border-spacing: 0px\">"
                "<tr>",
                (context->mode != E_MAIL_FORMATTER_MODE_PRINTING) ?
                        "<div class=\"headers -e-mail-formatter-body-color\"" :
@@ -530,7 +530,7 @@ emfe_headers_format (EMailFormatterExtension *extension,
        if (is_collapsable)
                g_string_append_printf (
                        buffer,
-                       "<td valign=\"top\" width=\"16\">"
+                       "<td valign=\"top\" width=\"16\" style=\"padding-left: 0px\">"
                        "<img src=\"evo-file://%s/%s\" class=\"navigable\" "
                        "     id=\"__evo-collapse-headers-img\" />"
                        "</td>",
diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c
index 2e44fe7..54c0777 100644
--- a/em-format/e-mail-formatter.c
+++ b/em-format/e-mail-formatter.c
@@ -28,6 +28,7 @@
 #include "e-mail-formatter-extension.h"
 #include "e-mail-formatter-utils.h"
 #include "e-mail-part.h"
+#include "e-mail-meta-remove-filter.h"
 
 #define d(x)
 
@@ -1047,6 +1048,8 @@ e_mail_formatter_format_text (EMailFormatter *formatter,
        CamelMimeFilter *filter;
        const gchar *charset = NULL;
        CamelMimeFilter *windows = NULL;
+       /* FIXME XXX WK2 */
+       CamelMimeFilter *meta_remove = NULL;
        CamelMimePart *mime_part;
        CamelContentType *mime_type;
 
diff --git a/em-format/e-mail-meta-remove-filter.c b/em-format/e-mail-meta-remove-filter.c
new file mode 100644
index 0000000..2d0f467
--- /dev/null
+++ b/em-format/e-mail-meta-remove-filter.c
@@ -0,0 +1,267 @@
+/*
+ * e-mail-meta-remove-filter.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "e-mail-meta-remove-filter.h"
+
+G_DEFINE_TYPE (EMailMetaRemoveFilter, e_mail_meta_remove_filter, CAMEL_TYPE_MIME_FILTER)
+
+static void
+remove_meta_tag (CamelMimeFilter *filter,
+                 const gchar *in,
+                 gsize len,
+                 gsize prespace,
+                 gchar **out,
+                 gsize *outlen)
+{
+       EMailMetaRemoveFilter *meta_remove = (EMailMetaRemoveFilter *) filter;
+       register const gchar *inptr = in;
+       const gchar *inend = in + len;
+       const gchar *start = NULL;
+       const gchar *end_of_prev_meta = NULL;
+       gboolean in_meta = meta_remove->in_meta;
+       gboolean previously_in_meta = meta_remove->in_meta;
+       gboolean charset_meta = FALSE;
+       gboolean backup = FALSE;
+       GString *new_out = NULL;
+       gsize offset = 0;
+
+       new_out = g_string_new ("");
+
+       if (meta_remove->after_head)
+               goto copy_input;
+
+       while (inptr < inend) {
+               /* Start of meta */
+               if (g_ascii_strncasecmp (inptr, "<meta ", 6) == 0) {
+                       /* If there was previous meta tag */
+                       if (end_of_prev_meta) {
+                               /* And there were some tags between these two meta tags */
+                               if (inptr - 1 != end_of_prev_meta) {
+                                       /* Save them */
+                                       gchar *tags;
+
+                                       tags = g_strndup (
+                                               end_of_prev_meta + 1,
+                                               inptr - end_of_prev_meta - 2);
+
+                                       g_string_append (new_out, tags);
+                                       g_free (tags);
+                               }
+                       }
+
+                       in_meta = TRUE;
+                       start = inptr;
+                       inptr += 6;
+               }
+
+               /* Meta tags are valid just in head element */
+               if (!in_meta && g_ascii_strncasecmp (inptr, "</head>", 7) == 0) {
+                       meta_remove->after_head = TRUE;
+                       if (end_of_prev_meta)
+                               break;
+                       else
+                               goto copy_input;
+               }
+
+               if (!in_meta && g_ascii_strncasecmp (inptr, "<body", 5) == 0) {
+                       meta_remove->after_head = TRUE;
+                       if (end_of_prev_meta)
+                               break;
+                       else
+                               goto copy_input;
+               }
+
+               /* Charset meta */
+               if (in_meta && !meta_remove->remove_all_meta) {
+                       if (g_ascii_strncasecmp (inptr, "charset", 7) == 0)
+                               charset_meta = TRUE;
+               }
+
+               /* End of meta tag */
+               if (in_meta && g_ascii_strncasecmp (inptr, ">", 1) == 0) {
+                       end_of_prev_meta = inptr;
+                       in_meta = FALSE;
+                       /* Strip meta tag from input */
+                       if (meta_remove->remove_all_meta || charset_meta) {
+                               if (new_out->len == 0 && !previously_in_meta) {
+                                       if (start) {
+                                               /* Copy tags before meta tag */
+                                               if (start - in > 0) {
+                                                       gchar *beginning;
+
+                                                       beginning = g_strndup (in, start - in);
+                                                       g_string_append (new_out, beginning);
+                                                       g_free (beginning);
+                                               }
+                                       } else {
+                                               /* If meta tag continues from previous buffer
+                                                * just adjust the offset */
+                                               offset = end_of_prev_meta + 1 - in;
+                                       }
+                               }
+
+                               /* If we wanted to remove just charset meta and we
+                                * removed it, quit */
+                               if (!meta_remove->remove_all_meta) {
+                                       meta_remove->after_head = TRUE;
+                                       break;
+                               }
+                       }
+                       start = NULL;
+                       charset_meta = FALSE;
+               }
+
+               inptr++;
+       }
+
+       if (in_meta) {
+               /* Meta tag doesn't end in this buffer */
+               gchar *tags = NULL;
+
+               if (end_of_prev_meta && start) {
+                       /* No tags between two meta tags */
+                       if (end_of_prev_meta + 1 == start)
+                               goto save_output;
+                       tags = g_strndup (
+                               end_of_prev_meta + 1,
+                               start - end_of_prev_meta - 2);
+               } else if (!end_of_prev_meta && start) {
+                       tags = g_strndup (in + offset , start - in - offset);
+               }
+
+               if (tags) {
+                       g_string_append (new_out, tags);
+                       g_free (tags);
+               }
+       } else if (end_of_prev_meta) {
+               gchar *end;
+
+               /* Copy tags after last meta to output */
+               end = g_strndup (end_of_prev_meta + 1, inend - end_of_prev_meta - 1);
+               g_string_append (new_out, end);
+               g_free (end);
+       } else if (!end_of_prev_meta) {
+               /* Meta was not found in this buffer */
+               camel_mime_filter_backup (filter, inend - 6, 6);
+               backup = TRUE;
+               goto copy_input;
+       }
+
+ save_output:
+       *out = (gchar *) new_out->str;
+       *outlen = new_out->len;
+       g_string_free (new_out, FALSE);
+
+       meta_remove->in_meta = in_meta;
+
+       return;
+
+ copy_input:
+       if (backup) {
+               *out = g_strndup (in, inend - in - 6);
+               *outlen = inend - in - 6;
+       } else {
+               *out = (gchar *) in;
+               *outlen = inend - in;
+       }
+
+       meta_remove->in_meta = in_meta;
+
+       g_string_free (new_out, TRUE);
+}
+
+static void
+filter_filter (CamelMimeFilter *filter,
+               const gchar *in,
+               gsize len,
+               gsize prespace,
+               gchar **out,
+               gsize *outlen,
+               gsize *outprespace)
+{
+       remove_meta_tag (filter, in, len, prespace, out, outlen);
+
+       *outprespace = prespace;
+}
+
+static void
+filter_complete (CamelMimeFilter *filter,
+                 const gchar *in,
+                 gsize len,
+                 gsize prespace,
+                 gchar **out,
+                 gsize *outlen,
+                 gsize *outprespace)
+{
+       *out = (gchar *) in;
+       *outlen = len;
+       *outprespace = prespace;
+}
+
+static void
+filter_reset (CamelMimeFilter *filter)
+{
+       EMailMetaRemoveFilter *meta_remove = (EMailMetaRemoveFilter *) filter;
+
+       meta_remove->in_meta = FALSE;
+       meta_remove->after_head = FALSE;
+}
+
+static void
+e_mail_meta_remove_filter_class_init (EMailMetaRemoveFilterClass *class)
+{
+       CamelMimeFilterClass *mime_filter_class;
+
+       mime_filter_class = CAMEL_MIME_FILTER_CLASS (class);
+       mime_filter_class->filter = filter_filter;
+       mime_filter_class->complete = filter_complete;
+       mime_filter_class->reset = filter_reset;
+}
+
+static void
+e_mail_meta_remove_filter_init (EMailMetaRemoveFilter *filter)
+{
+}
+
+/**
+ * e_mail_meta_remove_filter_new:
+ * @remove_all_meta: Whether remove all meta tags from message or just meta
+ * tag with charset attribute
+ *
+ * Creates a new meta_remove filter.
+ *
+ * Returns a new meta_remove filter.
+ **/
+CamelMimeFilter *
+e_mail_meta_remove_filter_new (gboolean remove_all_meta)
+{
+       EMailMetaRemoveFilter *filter = g_object_new (E_TYPE_MAIL_META_REMOVE_FILTER, NULL);
+
+       filter->remove_all_meta = remove_all_meta;
+       filter->in_meta = FALSE;
+       filter->after_head = FALSE;
+
+       return CAMEL_MIME_FILTER (filter);
+}
diff --git a/em-format/e-mail-meta-remove-filter.h b/em-format/e-mail-meta-remove-filter.h
new file mode 100644
index 0000000..e46242a
--- /dev/null
+++ b/em-format/e-mail-meta-remove-filter.h
@@ -0,0 +1,66 @@
+/*
+ * e-mail-meta-remove-filter.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_META_REMOVE_FILTER_H
+#define E_MAIL_META_REMOVE_FILTER_H
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_META_REMOVE_FILTER \
+       (e_mail_meta_remove_filter_get_type ())
+#define E_MAIL_META_REMOVE_FILTER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_META_REMOVE_FILTER, EMailmeta_removeFilter))
+#define E_MAIL_META_REMOVE_FILTER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_MAIL_META_REMOVE_FILTER, EMailmeta_removeFilterClass))
+#define E_IS_MAIL_META_REMOVE_FILTER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_META_REMOVE_FILTER))
+#define E_IS_MAIL_META_REMOVE_FILTER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_MAIL_META_REMOVE_FILTER))
+#define E_MAIL_META_REMOVE_FILTER_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_MAIL_META_REMOVE_FILTER, EMailmeta_removeFilterClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailMetaRemoveFilter EMailMetaRemoveFilter;
+typedef struct _EMailMetaRemoveFilterClass EMailMetaRemoveFilterClass;
+
+struct _EMailMetaRemoveFilter {
+       CamelMimeFilter parent;
+
+       gboolean remove_all_meta;
+       gboolean in_meta;
+       gboolean after_head;
+};
+
+struct _EMailMetaRemoveFilterClass {
+       CamelMimeFilterClass parent_class;
+};
+
+GType          e_mail_meta_remove_filter_get_type      (void);
+CamelMimeFilter *
+               e_mail_meta_remove_filter_new           (gboolean remove_all_meta);
+
+G_END_DECLS
+
+#endif /* E_MAIL_META_REMOVE_FILTER_H */
diff --git a/em-format/e-mail-part-headers.c b/em-format/e-mail-part-headers.c
index 9ffa594..db3e7f6 100644
--- a/em-format/e-mail-part-headers.c
+++ b/em-format/e-mail-part-headers.c
@@ -213,29 +213,21 @@ mail_part_headers_constructed (GObject *object)
 
 static void
 mail_part_headers_bind_dom_element (EMailPart *part,
-                                    WebKitDOMElement *element)
+                                    GDBusProxy *web_extension,
+                                    guint64 page_id,
+                                    const gchar *element_id)
 {
-       WebKitDOMDocument *document;
-       WebKitDOMElement *photo;
-       gchar *addr, *uri;
-
-       document = webkit_dom_node_get_owner_document (
-               WEBKIT_DOM_NODE (element));
-       photo = webkit_dom_document_get_element_by_id (
-               document, "__evo-contact-photo");
-
-       /* Contact photos disabled, the <img> tag is not there. */
-       if (photo == NULL)
-               return;
-
-       addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
-       uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
-
-       webkit_dom_html_image_element_set_src (
-               WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
-
-       g_free (addr);
-       g_free (uri);
+       if (web_extension) {
+               g_dbus_proxy_call (
+                       web_extension,
+                       "EMailPartHeadersBindDOMElement",
+                       g_variant_new ("(ts)", page_id, element_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       }
 }
 
 static void
diff --git a/em-format/e-mail-part.c b/em-format/e-mail-part.c
index 8aa21bb..5b76d58 100644
--- a/em-format/e-mail-part.c
+++ b/em-format/e-mail-part.c
@@ -487,17 +487,21 @@ e_mail_part_set_is_attachment (EMailPart *part,
 
 void
 e_mail_part_bind_dom_element (EMailPart *part,
-                              WebKitDOMElement *element)
+                              GDBusProxy *web_extension,
+                              guint64 page_id,
+                              const gchar *element_id)
 {
        EMailPartClass *class;
 
        g_return_if_fail (E_IS_MAIL_PART (part));
-       g_return_if_fail (WEBKIT_DOM_IS_ELEMENT (element));
+       g_return_if_fail (web_extension);
+       g_return_if_fail (page_id != 0);
+       g_return_if_fail (element_id && *element_id);
 
        class = E_MAIL_PART_GET_CLASS (part);
 
        if (class->bind_dom_element != NULL)
-               class->bind_dom_element (part, element);
+               class->bind_dom_element (part, web_extension, page_id, element_id);
 }
 
 static EMailPartValidityPair *
diff --git a/em-format/e-mail-part.h b/em-format/e-mail-part.h
index 63e8ae1..7d112df 100644
--- a/em-format/e-mail-part.h
+++ b/em-format/e-mail-part.h
@@ -19,7 +19,6 @@
 #define E_MAIL_PART_H
 
 #include <camel/camel.h>
-#include <webkit/webkitdom.h>
 
 #include <e-util/e-util.h>
 
@@ -87,7 +86,9 @@ struct _EMailPartClass {
        GObjectClass parent_class;
 
        void            (*bind_dom_element)     (EMailPart *part,
-                                                WebKitDOMElement *element);
+                                                GDBusProxy *web_extension,
+                                                guint64 page_id,
+                                                const gchar *element_id);
 };
 
 GType          e_mail_part_get_type            (void) G_GNUC_CONST;
@@ -115,7 +116,9 @@ gboolean    e_mail_part_get_is_attachment   (EMailPart *part);
 void           e_mail_part_set_is_attachment   (EMailPart *part,
                                                 gboolean is_attachment);
 void           e_mail_part_bind_dom_element    (EMailPart *part,
-                                                WebKitDOMElement *element);
+                                                GDBusProxy *web_extension,
+                                                guint64 page_id,
+                                                const gchar *element_id);
 void           e_mail_part_update_validity     (EMailPart *part,
                                                 CamelCipherValidity *validity,
                                                 EMailPartValidityFlags validity_type);
diff --git a/mail/e-http-request.c b/mail/e-http-request.c
index 39ceb56..f9ae4a3 100644
--- a/mail/e-http-request.c
+++ b/mail/e-http-request.c
@@ -25,7 +25,7 @@
 #include <libsoup/soup-requester.h>
 #include <libsoup/soup-request-http.h>
 #include <camel/camel.h>
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
 
 #include <e-util/e-util.h>
 #include <libemail-engine/libemail-engine.h>
diff --git a/mail/e-mail-display-popup-extension.c b/mail/e-mail-display-popup-extension.c
index e95dc3e..5c5f891 100644
--- a/mail/e-mail-display-popup-extension.c
+++ b/mail/e-mail-display-popup-extension.c
@@ -39,8 +39,7 @@ e_mail_display_popup_extension_default_init (EMailDisplayPopupExtensionInterface
  * on every extension so that they can add their items to the menu.
  */
 void
-e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *extension,
-                                               WebKitHitTestResult *context)
+e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *extension)
 {
        EMailDisplayPopupExtensionInterface *iface;
 
@@ -49,5 +48,5 @@ e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *exten
        iface = E_MAIL_DISPLAY_POPUP_EXTENSION_GET_INTERFACE (extension);
        g_return_if_fail (iface->update_actions != NULL);
 
-       iface->update_actions (extension, context);
+       iface->update_actions (extension);
 }
diff --git a/mail/e-mail-display-popup-extension.h b/mail/e-mail-display-popup-extension.h
index 67c1374..964b0c5 100644
--- a/mail/e-mail-display-popup-extension.h
+++ b/mail/e-mail-display-popup-extension.h
@@ -19,7 +19,6 @@
 #define E_MAIL_DISPLAY_POPUP_EXTENSION_H
 
 #include <glib-object.h>
-#include <webkit/webkit.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION \
@@ -48,15 +47,13 @@ typedef struct _EMailDisplayPopupExtensionInterface EMailDisplayPopupExtensionIn
 struct _EMailDisplayPopupExtensionInterface {
        GTypeInterface parent_interface;
 
-       void    (*update_actions)               (EMailDisplayPopupExtension *extension,
-                                                WebKitHitTestResult *context);
+       void    (*update_actions)               (EMailDisplayPopupExtension *extension);
 };
 
 GType          e_mail_display_popup_extension_get_type (void);
 
 void           e_mail_display_popup_extension_update_actions
-                                                       (EMailDisplayPopupExtension *extension,
-                                                        WebKitHitTestResult *context);
+                                                       (EMailDisplayPopupExtension *extension);
 
 G_END_DECLS
 
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 3f57261..c69d06c 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -36,9 +36,12 @@
 #include "e-http-request.h"
 #include "e-mail-display-popup-extension.h"
 #include "e-mail-request.h"
+#include "e-mail-ui-session.h"
 #include "em-composer-utils.h"
 #include "em-utils.h"
 
+#include <web-extensions/evolution-web-extension.h>
+
 #define d(x)
 
 #define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
@@ -61,6 +64,8 @@ struct _EMailDisplayPrivate {
        guint scheduled_reload;
 
        GHashTable *old_settings;
+
+       guint web_extension_headers_collapsed_signal_id;
 };
 
 enum {
@@ -72,8 +77,6 @@ enum {
        PROP_PART_LIST
 };
 
-static CamelDataCache *emd_global_http_cache = NULL;
-
 static const gchar *ui =
 "<ui>"
 "  <popup name='context'>"
@@ -152,29 +155,6 @@ formatter_image_loading_policy_changed_cb (GObject *object,
                e_mail_display_reload (display);
 }
 
-static gboolean
-mail_display_image_exists_in_cache (const gchar *image_uri)
-{
-       gchar *filename;
-       gchar *hash;
-       gboolean exists = FALSE;
-
-       g_return_val_if_fail (emd_global_http_cache != NULL, FALSE);
-
-       hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, image_uri, -1);
-       filename = camel_data_cache_get_filename (
-               emd_global_http_cache, "http", hash);
-
-       if (filename != NULL) {
-               exists = g_file_test (filename, G_FILE_TEST_EXISTS);
-               g_free (filename);
-       }
-
-       g_free (hash);
-
-       return exists;
-}
-
 static void
 mail_display_update_formatter_colors (EMailDisplay *display)
 {
@@ -188,6 +168,7 @@ mail_display_update_formatter_colors (EMailDisplay *display)
                e_mail_formatter_update_style (formatter, state_flags);
 }
 
+#if 0
 static void
 mail_display_plugin_widget_disconnect_children (GtkWidget *widget,
                                                 gpointer mail_display)
@@ -210,7 +191,7 @@ mail_display_plugin_widget_disconnect (gpointer widget_uri,
                        mail_display_plugin_widget_disconnect_children,
                        mail_display);
 }
-
+#endif
 static gboolean
 mail_display_process_mailto (EWebView *web_view,
                              const gchar *mailto_uri,
@@ -240,14 +221,29 @@ mail_display_process_mailto (EWebView *web_view,
 }
 
 static gboolean
-mail_display_link_clicked (WebKitWebView *web_view,
-                           WebKitWebFrame *frame,
-                           WebKitNetworkRequest *request,
-                           WebKitWebNavigationAction *navigation_action,
-                           WebKitWebPolicyDecision *policy_decision,
-                           gpointer user_data)
+decide_policy_cb (WebKitWebView *web_view,
+                  WebKitPolicyDecision *decision,
+                  WebKitPolicyDecisionType type)
 {
-       const gchar *uri = webkit_network_request_get_uri (request);
+       WebKitNavigationPolicyDecision *navigation_decision;
+       WebKitNavigationAction *navigation_action;
+       WebKitURIRequest *request;
+       const gchar *uri;
+
+       if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
+               return FALSE;
+
+       navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+       navigation_action = webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
+       request = webkit_navigation_action_get_request (navigation_action);
+
+       uri = webkit_uri_request_get_uri (request);
+
+       if (!uri || !*uri) {
+               g_warning ("asdasdasdasdadasdasd");
+               webkit_policy_decision_ignore (decision);
+               return TRUE;
+       }
 
        if (g_str_has_prefix (uri, "file://")) {
                gchar *filename;
@@ -255,8 +251,9 @@ mail_display_link_clicked (WebKitWebView *web_view,
                filename = g_filename_from_uri (uri, NULL, NULL);
 
                if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
-                       webkit_web_policy_decision_ignore (policy_decision);
-                       webkit_network_request_set_uri (request, "about:blank");
+                       webkit_policy_decision_ignore (decision);
+                       /* FIXME XXX WK2 Not sure if the request will be changed there */
+                       webkit_uri_request_set_uri (request, "about:blank");
                        g_free (filename);
                        return TRUE;
                }
@@ -266,17 +263,17 @@ mail_display_link_clicked (WebKitWebView *web_view,
 
        if (mail_display_process_mailto (E_WEB_VIEW (web_view), uri, NULL)) {
                /* do nothing, function handled the "mailto:"; uri already */
-               webkit_web_policy_decision_ignore (policy_decision);
+               webkit_policy_decision_ignore (decision);
                return TRUE;
 
        } else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0) {
                /* ignore */
-               webkit_web_policy_decision_ignore (policy_decision);
+               webkit_policy_decision_ignore (decision);
                return TRUE;
 
        } else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0) {
                /* ignore */
-               webkit_web_policy_decision_ignore (policy_decision);
+               webkit_policy_decision_ignore (decision);
                return TRUE;
 
        }
@@ -284,7 +281,7 @@ mail_display_link_clicked (WebKitWebView *web_view,
        /* Let WebKit handle it. */
        return FALSE;
 }
-
+#if 0
 static void
 mail_display_resource_requested (WebKitWebView *web_view,
                                  WebKitWebFrame *frame,
@@ -725,114 +722,7 @@ exit:
 
        return widget;
 }
-
-static void
-toggle_headers_visibility (WebKitDOMElement *button,
-                           WebKitDOMEvent *event,
-                           WebKitWebView *web_view)
-{
-       WebKitDOMDocument *document;
-       WebKitDOMElement *short_headers, *full_headers;
-       WebKitDOMCSSStyleDeclaration *css_short, *css_full;
-       gboolean expanded;
-       const gchar *path;
-       gchar *css_value;
-
-       document = webkit_web_view_get_dom_document (web_view);
-
-       short_headers = webkit_dom_document_get_element_by_id (
-               document, "__evo-short-headers");
-       if (short_headers == NULL)
-               return;
-
-       css_short = webkit_dom_element_get_style (short_headers);
-
-       full_headers = webkit_dom_document_get_element_by_id (
-               document, "__evo-full-headers");
-       if (full_headers == NULL)
-               return;
-
-       css_full = webkit_dom_element_get_style (full_headers);
-       css_value = webkit_dom_css_style_declaration_get_property_value (
-               css_full, "display");
-       expanded = (g_strcmp0 (css_value, "table") == 0);
-       g_free (css_value);
-
-       webkit_dom_css_style_declaration_set_property (
-               css_full, "display",
-               expanded ? "none" : "table", "", NULL);
-       webkit_dom_css_style_declaration_set_property (
-               css_short, "display",
-               expanded ? "table" : "none", "", NULL);
-
-       if (expanded)
-               path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
-       else
-               path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
-
-       webkit_dom_html_image_element_set_src (
-               WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
-
-       e_mail_display_set_headers_collapsed (
-               E_MAIL_DISPLAY (web_view), expanded);
-
-       d (printf ("Headers %s!\n", expanded ? "collapsed" : "expanded"));
-}
-
-static void
-toggle_address_visibility (WebKitDOMElement *button,
-                           WebKitDOMEvent *event)
-{
-       WebKitDOMElement *full_addr, *ellipsis;
-       WebKitDOMElement *parent;
-       WebKitDOMCSSStyleDeclaration *css_full, *css_ellipsis;
-       const gchar *path;
-       gboolean expanded;
-
-       /* <b> element */
-       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (button));
-       /* <td> element */
-       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (parent));
-
-       full_addr = webkit_dom_element_query_selector (parent, "#__evo-moreaddr", NULL);
-
-       if (!full_addr)
-               return;
-
-       css_full = webkit_dom_element_get_style (full_addr);
-
-       ellipsis = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-ellipsis", NULL);
-
-       if (!ellipsis)
-               return;
-
-       css_ellipsis = webkit_dom_element_get_style (ellipsis);
-
-       expanded = (g_strcmp0 (
-               webkit_dom_css_style_declaration_get_property_value (
-               css_full, "display"), "inline") == 0);
-
-       webkit_dom_css_style_declaration_set_property (
-               css_full, "display", (expanded ? "none" : "inline"), "", NULL);
-       webkit_dom_css_style_declaration_set_property (
-               css_ellipsis, "display", (expanded ? "inline" : "none"), "", NULL);
-
-       if (expanded)
-               path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
-       else
-               path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
-
-       if (!WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (button)) {
-               button = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-img", NULL);
-
-               if (!button)
-                       return;
-       }
-
-       webkit_dom_html_image_element_set_src (
-               WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
-}
-
+#endif
 static void
 add_color_css_rule_for_web_view (EWebView *view,
                                  const gchar *color_name,
@@ -930,87 +820,148 @@ setup_image_click_event_listeners_on_document (WebKitDOMDocument *document,
 }
 
 static void
+headers_collapsed_signal_cb (GDBusConnection *connection,
+                          const gchar *sender_name,
+                          const gchar *object_path,
+                          const gchar *interface_name,
+                          const gchar *signal_name,
+                          GVariant *parameters,
+                          EMailDisplay *display)
+{
+       gboolean expanded;
+
+       if (g_strcmp0 (signal_name, "HeadersCollapsed") != 0)
+               return;
+
+       if (parameters)
+               g_variant_get (parameters, "(b)", &expanded);
+
+       e_mail_display_set_headers_collapsed (display, expanded);
+}
+
+static void
 setup_dom_bindings (WebKitWebView *web_view,
-                    WebKitWebFrame *frame,
+                    WebKitLoadEvent load_event,
                     gpointer user_data)
 {
-       WebKitDOMDocument *document;
+       GDBusProxy *web_extension;
+       EMailDisplay *display;
 
-       document = webkit_web_frame_get_dom_document (frame);
+       if (load_event != WEBKIT_LOAD_FINISHED)
+               return;
 
-       setup_image_click_event_listeners_on_document (document, web_view);
+       display = E_MAIL_DISPLAY (web_view);
+
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
+
+
+       if (web_extension) {
+               if (display->priv->web_extension_headers_collapsed_signal_id == 0) {
+                       display->priv->web_extension_headers_collapsed_signal_id =
+                               g_dbus_connection_signal_subscribe (
+                                       g_dbus_proxy_get_connection (web_extension),
+                                       g_dbus_proxy_get_name (web_extension),
+                                       EVOLUTION_WEB_EXTENSION_INTERFACE,
+                                       "RecurToggled",
+                                       EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+                                       NULL,
+                                       G_DBUS_SIGNAL_FLAGS_NONE,
+                                       (GDBusSignalCallback) headers_collapsed_signal_cb,
+                                       display,
+                                       NULL);
+               }
+
+               g_dbus_proxy_call (
+                       web_extension,
+                       "EMailDisplayBindDOM",
+                       g_variant_new (
+                               "(t)",
+                               webkit_web_view_get_page_id (web_view)),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       }
+}
+
+static void
+mail_element_exists_cb (GDBusProxy *web_extension,
+                        GAsyncResult *result,
+                        EMailPart *part)
+{
+       gboolean element_exists = FALSE;
+       GVariant *result_variant;
+       guint64 page_id;
+
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               g_variant_get (result_variant, "(bt)", &element_exists, &page_id);
+               g_variant_unref (result_variant);
+       }
+
+       if (element_exists)
+               e_mail_part_bind_dom_element (
+                       part,
+                       web_extension,
+                       page_id,
+                       e_mail_part_get_id (part));
+
+       g_object_unref (part);
 }
 
 static void
-mail_parts_bind_dom (GObject *object,
-                     GParamSpec *pspec,
+mail_parts_bind_dom (WebKitWebView *web_view,
+                     WebKitLoadEvent load_event,
                      gpointer user_data)
 {
-       WebKitWebFrame *frame;
-       WebKitLoadStatus load_status;
-       WebKitWebView *web_view;
-       WebKitDOMDocument *document;
        EMailDisplay *display;
        GQueue queue = G_QUEUE_INIT;
        GList *head, *link;
-       const gchar *frame_name;
+       GDBusProxy *web_extension;
 
-       frame = WEBKIT_WEB_FRAME (object);
-       load_status = webkit_web_frame_get_load_status (frame);
-
-       if (load_status != WEBKIT_LOAD_FINISHED)
+       if (load_event != WEBKIT_LOAD_FINISHED)
                return;
 
-       web_view = webkit_web_frame_get_web_view (frame);
        display = E_MAIL_DISPLAY (web_view);
        if (display->priv->part_list == NULL)
                return;
 
        initialize_web_view_colors (display);
-       frame_name = webkit_web_frame_get_name (frame);
-       if (frame_name == NULL || *frame_name == '\0')
-               frame_name = ".message.headers";
 
-       document = webkit_web_view_get_dom_document (web_view);
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+       if (!web_extension)
+               return;
 
        e_mail_part_list_queue_parts (
-               display->priv->part_list, frame_name, &queue);
+               display->priv->part_list, NULL, &queue);
        head = g_queue_peek_head_link (&queue);
 
        for (link = head; link != NULL; link = g_list_next (link)) {
                EMailPart *part = E_MAIL_PART (link->data);
-               WebKitDOMElement *element;
                const gchar *part_id;
 
-               /* Iterate only the parts rendered in
-                * the frame and all it's subparts. */
-               if (!e_mail_part_id_has_prefix (part, frame_name))
-                       break;
-
                part_id = e_mail_part_get_id (part);
-               element = find_element_by_id (document, part_id);
 
-               if (element != NULL)
-                       e_mail_part_bind_dom_element (part, element);
+               g_dbus_proxy_call (
+                       web_extension,
+                       "ElementExists",
+                       g_variant_new (
+                               "(ts)",
+                               webkit_web_view_get_page_id (
+                                       WEBKIT_WEB_VIEW (display)),
+                               part_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       (GAsyncReadyCallback)mail_element_exists_cb,
+                       g_object_ref (part));
        }
 
        while (!g_queue_is_empty (&queue))
                g_object_unref (g_queue_pop_head (&queue));
 }
-
-static void
-mail_display_frame_created (WebKitWebView *web_view,
-                            WebKitWebFrame *frame,
-                            gpointer user_data)
-{
-       d (printf ("Frame %s created!\n", webkit_web_frame_get_name (frame)));
-
-       /* Call bind_func of all parts written in this frame */
-       g_signal_connect (
-               frame, "notify::load-status",
-               G_CALLBACK (mail_parts_bind_dom), NULL);
-}
-
+#if 0
 static void
 mail_display_uri_changed (EMailDisplay *display,
                           GParamSpec *pspec,
@@ -1031,7 +982,7 @@ mail_display_uri_changed (EMailDisplay *display,
                (GDestroyNotify) g_free,
                (GDestroyNotify) e_weak_ref_free);
 }
-
+#endif
 static void
 mail_display_set_property (GObject *object,
                            guint property_id,
@@ -1124,7 +1075,7 @@ mail_display_dispose (GObject *object)
                g_source_remove (priv->scheduled_reload);
                priv->scheduled_reload = 0;
        }
-
+#if 0
        if (priv->widgets != NULL) {
                g_hash_table_foreach (
                        priv->widgets,
@@ -1132,12 +1083,20 @@ mail_display_dispose (GObject *object)
                g_hash_table_destroy (priv->widgets);
                priv->widgets = NULL;
        }
-
+#endif
        if (priv->settings != NULL)
                g_signal_handlers_disconnect_matched (
                        priv->settings, G_SIGNAL_MATCH_DATA,
                        0, 0, NULL, NULL, object);
 
+       if (priv->web_extension_headers_collapsed_signal_id > 0) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (
+                               e_web_view_get_web_extension_proxy (E_WEB_VIEW (object))),
+                       priv->web_extension_headers_collapsed_signal_id);
+               priv->web_extension_headers_collapsed_signal_id = 0;
+       }
+
        g_clear_object (&priv->part_list);
        g_clear_object (&priv->formatter);
        g_clear_object (&priv->settings);
@@ -1163,12 +1122,89 @@ mail_display_finalize (GObject *object)
 }
 
 static void
+mail_display_get_font_settings (GSettings *settings,
+                                PangoFontDescription **monospace,
+                                PangoFontDescription **variable)
+{
+       gboolean use_custom_font;
+       gchar *monospace_font;
+       gchar *variable_font;
+
+       use_custom_font = g_settings_get_boolean (settings, "use-custom-font");
+
+       if (!use_custom_font) {
+               *monospace = NULL;
+               *variable = NULL;
+               return;
+       }
+
+       monospace_font = g_settings_get_string (settings, "monospace-font");
+       variable_font = g_settings_get_string (settings, "variable-width-font");
+
+       *monospace = (monospace_font != NULL) ?
+               pango_font_description_from_string (monospace_font) : NULL;
+       *variable = (variable_font != NULL) ?
+               pango_font_description_from_string (variable_font) : NULL;
+
+       g_free (monospace_font);
+       g_free (variable_font);
+}
+
+static void
+mail_display_set_fonts (EWebView *web_view,
+                        PangoFontDescription **monospace,
+                        PangoFontDescription **variable)
+{
+       EMailDisplay *display = E_MAIL_DISPLAY (web_view);
+
+       mail_display_get_font_settings (display->priv->settings, monospace, variable);
+}
+
+static void
+mail_display_web_view_initialize (WebKitWebView *web_view)
+{
+       const gchar *id = "org.gnome.settings-daemon.plugins.xsettings";
+       GSettings *settings;
+       GSettingsSchema *settings_schema;
+       WebKitSettings *webkit_settings;
+       PangoFontDescription *ms = NULL, *vw = NULL;
+
+       webkit_settings = webkit_web_view_get_settings (web_view);
+
+       g_object_set (webkit_settings,
+               "enable-frame-flattening", TRUE,
+               NULL);
+
+       settings = g_settings_new ("org.gnome.evolution.mail");
+       mail_display_get_font_settings (settings, &ms, &vw);
+
+       /* Optional schema */
+       settings_schema = g_settings_schema_source_lookup (
+               g_settings_schema_source_get_default (), id, FALSE);
+
+       if (settings_schema)
+               settings = g_settings_new (id);
+       else
+               settings = NULL;
+
+       e_web_view_update_fonts_settings (
+               g_settings_new ("org.gnome.desktop.interface"),
+               settings,
+               ms, vw, GTK_WIDGET (web_view));
+
+       pango_font_description_free (ms);
+       pango_font_description_free (vw);
+}
+
+static void
 mail_display_constructed (GObject *object)
 {
        e_extensible_load_extensions (E_EXTENSIBLE (object));
 
        /* Chain up to parent's constructed() method. */
        G_OBJECT_CLASS (e_mail_display_parent_class)->constructed (object);
+
+       mail_display_web_view_initialize (WEBKIT_WEB_VIEW (object));
 }
 
 static void
@@ -1197,15 +1233,11 @@ mail_display_button_press_event (GtkWidget *widget,
                                  GdkEventButton *event)
 {
        EWebView *web_view = E_WEB_VIEW (widget);
-       WebKitHitTestResult *hit_test;
        GList *list, *link;
 
        if (event->button != 3)
                goto chainup;
 
-       hit_test = webkit_web_view_get_hit_test_result (
-               WEBKIT_WEB_VIEW (web_view), event);
-
        list = e_extensible_list_extensions (
                E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
        for (link = list; link != NULL; link = g_list_next (link)) {
@@ -1215,18 +1247,16 @@ mail_display_button_press_event (GtkWidget *widget,
                        continue;
 
                e_mail_display_popup_extension_update_actions (
-                       E_MAIL_DISPLAY_POPUP_EXTENSION (extension), hit_test);
+                       E_MAIL_DISPLAY_POPUP_EXTENSION (extension));
        }
        g_list_free (list);
 
-       g_object_unref (hit_test);
-
 chainup:
        /* Chain up to parent's button_press_event() method. */
        return GTK_WIDGET_CLASS (e_mail_display_parent_class)->
                button_press_event (widget, event);
 }
-
+#if 0
 static gchar *
 mail_display_redirect_uri (EWebView *web_view,
                            const gchar *uri)
@@ -1241,54 +1271,6 @@ mail_display_redirect_uri (EWebView *web_view,
        if (part_list == NULL)
                goto chainup;
 
-       /* Redirect cid:part_id to mail://mail_id/cid:part_id */
-       if (g_str_has_prefix (uri, "cid:")) {
-               CamelFolder *folder;
-               const gchar *message_uid;
-
-               folder = e_mail_part_list_get_folder (part_list);
-               message_uid = e_mail_part_list_get_message_uid (part_list);
-
-               /* Always write raw content of CID object. */
-               return e_mail_part_build_uri (
-                       folder, message_uid,
-                       "part_id", G_TYPE_STRING, uri,
-                       "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_CID, NULL);
-       }
-
-       /* WebKit won't allow to load a local file when displaying
-        * "remote" mail:// protocol, so we need to handle this manually. */
-       if (g_str_has_prefix (uri, "file:")) {
-               gchar *content = NULL;
-               gchar *content_type;
-               gchar *filename;
-               gchar *encoded;
-               gchar *new_uri;
-               gsize length = 0;
-
-               filename = g_filename_from_uri (uri, NULL, NULL);
-               if (filename == NULL)
-                       goto chainup;
-
-               if (!g_file_get_contents (filename, &content, &length, NULL)) {
-                       g_free (filename);
-                       goto chainup;
-               }
-
-               encoded = g_base64_encode ((guchar *) content, length);
-               content_type = g_content_type_guess (filename, NULL, 0, NULL);
-
-               new_uri = g_strdup_printf (
-                       "data:%s;base64,%s", content_type, encoded);
-
-               g_free (content_type);
-               g_free (content);
-               g_free (filename);
-               g_free (encoded);
-
-               return new_uri;
-       }
-
        uri_is_http =
                g_str_has_prefix (uri, "http:") ||
                g_str_has_prefix (uri, "https:") ||
@@ -1407,29 +1389,26 @@ mail_display_suggest_filename (EWebView *web_view,
        return E_WEB_VIEW_CLASS (e_mail_display_parent_class)->
                suggest_filename (web_view, uri);
 }
-
+#endif
 static void
-mail_display_set_fonts (EWebView *web_view,
-                        PangoFontDescription **monospace,
-                        PangoFontDescription **variable)
+mail_display_get_font_settings (GSettings *settings,
+                                PangoFontDescription **monospace,
+                                PangoFontDescription **variable)
 {
        EMailDisplay *display = E_MAIL_DISPLAY (web_view);
        gboolean use_custom_font;
        gchar *monospace_font;
        gchar *variable_font;
 
-       use_custom_font = g_settings_get_boolean (
-               display->priv->settings, "use-custom-font");
+       use_custom_font = g_settings_get_boolean (settings, "use-custom-font");
        if (!use_custom_font) {
                *monospace = NULL;
                *variable = NULL;
                return;
        }
 
-       monospace_font = g_settings_get_string (
-               display->priv->settings, "monospace-font");
-       variable_font = g_settings_get_string (
-               display->priv->settings, "variable-width-font");
+       monospace_font = g_settings_get_string (settings, "monospace-font");
+       variable_font = g_settings_get_string (settings, "variable-width-font");
 
        *monospace = (monospace_font != NULL) ?
                pango_font_description_from_string (monospace_font) : NULL;
@@ -1441,6 +1420,16 @@ mail_display_set_fonts (EWebView *web_view,
 }
 
 static void
+mail_display_set_fonts (EWebView *web_view,
+                        PangoFontDescription **monospace,
+                        PangoFontDescription **variable)
+{
+       EMailDisplay *display = E_MAIL_DISPLAY (web_view);
+
+       mail_display_get_font_settings (display->priv->settings, monospace, variable);
+}
+
+static void
 e_mail_display_test_change_and_update_fonts_cb (EMailDisplay *mail_display,
                                                const gchar *key,
                                                GSettings *settings)
@@ -1546,8 +1535,10 @@ e_mail_display_class_init (EMailDisplayClass *class)
        widget_class->button_press_event = mail_display_button_press_event;
 
        web_view_class = E_WEB_VIEW_CLASS (class);
+#if 0
        web_view_class->redirect_uri = mail_display_redirect_uri;
        web_view_class->suggest_filename = mail_display_suggest_filename;
+#endif
        web_view_class->set_fonts = mail_display_set_fonts;
 
        g_object_class_install_property (
@@ -1606,12 +1597,754 @@ e_mail_display_class_init (EMailDisplayClass *class)
 }
 
 static void
+mail_display_process_uri_scheme_finished_cb (EMailDisplay *display,
+                                             GAsyncResult *result,
+                                             WebKitURISchemeRequest *request)
+{
+       GError *error = NULL;
+
+       if (!g_task_propagate_boolean (G_TASK (result), &error)) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_warning ("URI %s cannot be processed: %s",
+                               webkit_uri_scheme_request_get_uri (request),
+                               error ? error->message : "Unknown error");
+               }
+               g_object_unref (request);
+               if (error)
+                       g_error_free (error);
+       }
+}
+
+static void
+mail_cid_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                 EMailDisplay *display)
+{
+       EMailPartList *part_list;
+       EMailPart *part;
+       GInputStream *stream;
+       const gchar *uri;
+       const gchar *mime_type;
+       GByteArray *byte_array;
+       CamelStream *output_stream;
+       GCancellable *cancellable = NULL;
+       CamelDataWrapper *dw;
+       CamelMimePart *mime_part;
+
+       part_list = e_mail_display_get_part_list (display);
+       uri = webkit_uri_scheme_request_get_uri (request);
+       part = e_mail_part_list_ref_part (part_list, uri);
+       mime_type = e_mail_part_get_mime_type (part);
+       mime_part = e_mail_part_ref_mime_part (part);
+       dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+
+       g_return_if_fail (dw);
+
+       byte_array = g_byte_array_new ();
+       output_stream = camel_stream_mem_new ();
+
+       /* We retain ownership of the byte array. */
+       camel_stream_mem_set_byte_array (
+               CAMEL_STREAM_MEM (output_stream), byte_array);
+
+       camel_data_wrapper_decode_to_stream_sync (
+               dw, output_stream, cancellable, NULL);
+
+       stream = g_memory_input_stream_new_from_bytes (
+               g_byte_array_free_to_bytes (byte_array));
+
+       webkit_uri_scheme_request_finish (request, stream, -1, mime_type);
+
+       g_object_unref (mime_part);
+       g_object_unref (stream);
+       g_object_unref (part);
+}
+
+static gssize
+copy_stream_to_stream (CamelStream *input,
+                       GMemoryInputStream *output,
+                       GCancellable *cancellable)
+{
+       gchar *buff;
+       gssize read_len = 0;
+       gssize total_len = 0;
+
+       g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_SET, cancellable, NULL);
+
+       buff = g_malloc (4096);
+       while ((read_len = camel_stream_read (input, buff, 4096, cancellable, NULL)) > 0) {
+
+               g_memory_input_stream_add_data (output, buff, read_len, g_free);
+
+               total_len += read_len;
+
+               buff = g_malloc (4096);
+       }
+
+       /* Free the last unused buffer */
+       g_free (buff);
+
+       return total_len;
+}
+
+static void
+redirect_handler (SoupMessage *msg,
+                  gpointer user_data)
+{
+       if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
+               SoupSession *soup_session = user_data;
+               SoupURI *new_uri;
+               const gchar *new_loc;
+
+               new_loc = soup_message_headers_get_list (msg->response_headers, "Location");
+               if (!new_loc)
+                       return;
+
+               new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), new_loc);
+               if (!new_uri) {
+                       soup_message_set_status_full (
+                               msg,
+                               SOUP_STATUS_MALFORMED,
+                               "Invalid Redirect URL");
+                       return;
+               }
+
+               soup_message_set_uri (msg, new_uri);
+               soup_session_requeue_message (soup_session, msg);
+
+               soup_uri_free (new_uri);
+       }
+}
+
+static void
+send_and_handle_redirection (SoupSession *session,
+                             SoupMessage *message,
+                             gchar **new_location)
+{
+       gchar *old_uri = NULL;
+
+       g_return_if_fail (message != NULL);
+
+       if (new_location) {
+               old_uri = soup_uri_to_string (soup_message_get_uri (message), FALSE);
+       }
+
+       soup_message_set_flags (message, SOUP_MESSAGE_NO_REDIRECT);
+       soup_message_add_header_handler (
+               message, "got_body", "Location",
+               G_CALLBACK (redirect_handler), session);
+       soup_message_headers_append (message->request_headers, "Connection", "close");
+       soup_session_send_message (session, message);
+
+       if (new_location) {
+               gchar *new_loc = soup_uri_to_string (soup_message_get_uri (message), FALSE);
+
+               if (new_loc && old_uri && !g_str_equal (new_loc, old_uri)) {
+                       *new_location = new_loc;
+               } else {
+                       g_free (new_loc);
+               }
+       }
+
+       g_free (old_uri);
+}
+
+static void
+web_view_process_http_uri_scheme_request (GTask *task,
+                                          gpointer source_object,
+                                          gpointer task_data,
+                                          GCancellable *cancellable)
+{
+       SoupURI *soup_uri;
+       gchar *evo_uri, *uri;
+       gchar *mail_uri;
+       const gchar *user_cache_dir;
+       const gchar *content_type;
+       GInputStream *stream = NULL;
+       gboolean force_load_images = FALSE;
+       gboolean ret_val = FALSE;
+       EMailImageLoadingPolicy image_policy;
+       gchar *uri_md5;
+       EShell *shell;
+       GSettings *settings;
+       CamelDataCache *cache;
+       CamelStream *cache_stream;
+       GHashTable *query;
+       gint uri_len;
+       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
+
+       /* Remove the __evo-mail query */
+       soup_uri = soup_uri_new (webkit_uri_scheme_request_get_uri (request));
+
+       if (!soup_uri_get_query (soup_uri)) {
+               g_task_return_boolean (task, FALSE);
+               soup_uri_free (soup_uri);
+               return;
+       }
+
+       query = soup_form_decode (soup_uri_get_query (soup_uri));
+       mail_uri = g_hash_table_lookup (query, "__evo-mail");
+       if (mail_uri)
+               mail_uri = g_strdup (mail_uri);
+
+       g_hash_table_remove (query, "__evo-mail");
+
+       /* Remove __evo-load-images if present (and in such case set
+        * force_load_images to TRUE) */
+       force_load_images = g_hash_table_remove (query, "__evo-load-images");
+
+       soup_uri_set_query_from_form (soup_uri, query);
+       g_hash_table_unref (query);
+
+       evo_uri = soup_uri_to_string (soup_uri, FALSE);
+
+       if (camel_debug_start ("emformat:requests")) {
+               printf ("%s: looking for '%s'\n", G_STRFUNC, evo_uri);
+               camel_debug_end ();
+       }
+
+       /* Remove the "evo-" prefix from scheme */
+       uri_len = strlen (evo_uri);
+       uri = NULL;
+       if (evo_uri && (uri_len > 5)) {
+               /* Remove trailing "?" if there is no URI query */
+               if (evo_uri[uri_len - 1] == '?') {
+                       uri = g_strndup (evo_uri + 4, uri_len - 5);
+               } else {
+                       uri = g_strdup (evo_uri + 4);
+               }
+               g_free (evo_uri);
+       }
+
+       if (!uri || !*uri)
+               goto cleanup;
+
+       /* Use MD5 hash of the URI as a filname of the resourec cache file.
+        * We were previously using the URI as a filename but the URI is
+        * sometimes too long for a filename. */
+       uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
+
+       /* Open Evolution's cache */
+       user_cache_dir = e_get_user_cache_dir ();
+       cache = camel_data_cache_new (user_cache_dir, NULL);
+       if (cache) {
+               camel_data_cache_set_expire_age (cache, 24 * 60 * 60);
+               camel_data_cache_set_expire_access (cache, 2 * 60 * 60);
+       }
+
+       /* Found item in cache! */
+       cache_stream = camel_data_cache_get (cache, "http", uri_md5, NULL);
+       if (cache_stream)
+               goto process;
+
+       /* If the item is not in the cache and Evolution is in offline mode then
+        * quit regardless any image loading policy */
+       shell = e_shell_get_default ();
+       if (!e_shell_get_online (shell)) {
+               goto cleanup;
+       }
+
+       settings = g_settings_new ("org.gnome.evolution.mail");
+       image_policy = g_settings_get_enum (settings, "image-loading-policy");
+       g_object_unref (settings);
+
+       /* Item not found in cache, but image loading policy allows us to fetch
+        * it from the interwebs */
+       if (!force_load_images && mail_uri &&
+           (image_policy == E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES)) {
+               CamelObjectBag *registry;
+               gchar *decoded_uri;
+               EMailPartList *part_list;
+
+               registry = e_mail_part_list_get_registry ();
+               decoded_uri = soup_uri_decode (mail_uri);
+
+               part_list = camel_object_bag_get (registry, decoded_uri);
+               if (part_list) {
+                       EShellBackend *shell_backend;
+                       EMailBackend *backend;
+                       EMailSession *session;
+                       CamelInternetAddress *addr;
+                       CamelMimeMessage *message;
+                       gboolean known_address = FALSE;
+                       GError *error = NULL;
+
+                       shell_backend =
+                               e_shell_get_backend_by_name (shell, "mail");
+                       backend = E_MAIL_BACKEND (shell_backend);
+                       session = e_mail_backend_get_session (backend);
+
+                       message = e_mail_part_list_get_message (part_list);
+                       addr = camel_mime_message_get_from (message);
+
+                       e_mail_ui_session_check_known_address_sync (
+                               E_MAIL_UI_SESSION (session),
+                               addr, FALSE, cancellable,
+                               &known_address, &error);
+
+                       if (error != NULL) {
+                               g_warning ("%s: %s", G_STRFUNC, error->message);
+                               g_error_free (error);
+                       }
+
+                       if (known_address)
+                               force_load_images = TRUE;
+
+                       g_object_unref (part_list);
+               }
+
+               g_free (decoded_uri);
+       }
+
+       if ((image_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS) ||
+           force_load_images) {
+
+               SoupSession *session;
+               SoupMessage *message;
+               GError *error;
+               EProxy *proxy;
+
+               session = soup_session_sync_new_with_options (
+                               SOUP_SESSION_TIMEOUT, 90,
+                               NULL);
+
+               proxy = e_proxy_new ();
+               e_proxy_setup_proxy (proxy);
+
+               if (e_proxy_require_proxy_for_uri (proxy, uri)) {
+                       SoupURI *proxy_uri;
+
+                       proxy_uri = e_proxy_peek_uri_for (proxy, uri);
+
+                       g_object_set (session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
+               }
+
+               g_clear_object (&proxy);
+
+               message = soup_message_new (SOUP_METHOD_GET, uri);
+               soup_message_headers_append (
+                       message->request_headers, "User-Agent", "Evolution/" VERSION);
+
+               send_and_handle_redirection (session, message, NULL);
+
+               if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
+                       g_warning ("Failed to request %s (code %d)", uri, message->status_code);
+                       goto cleanup;
+               }
+
+               /* Write the response body to cache */
+               error = NULL;
+               cache_stream = camel_data_cache_add (cache, "http", uri_md5, &error);
+               if (error != NULL) {
+                       g_warning (
+                               "Failed to create cache file for '%s': %s",
+                               uri, error->message);
+                       g_clear_error (&error);
+               } else {
+                       camel_stream_write (
+                               cache_stream, message->response_body->data,
+                               message->response_body->length, cancellable, &error);
+
+                       if (error != NULL) {
+                               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                                       g_warning (
+                                               "Failed to write data to cache stream: %s",
+                                               error->message);
+                               g_clear_error (&error);
+                               g_object_unref (cache_stream);
+                               goto cleanup;
+                       }
+
+                       g_seekable_seek (G_SEEKABLE (cache_stream), 0, G_SEEK_SET, cancellable, NULL);
+
+               }
+
+               g_object_unref (message);
+               g_object_unref (session);
+       }
+
+ process:
+       if (cache_stream) {
+               gssize len;
+
+               stream = g_memory_input_stream_new ();
+
+               len = copy_stream_to_stream (
+                       cache_stream,
+                       G_MEMORY_INPUT_STREAM (stream), cancellable);
+
+               camel_stream_close (cache_stream, cancellable, NULL);
+
+               g_object_unref (cache_stream);
+
+               /* When succesfully read some data from cache then
+                * get mimetype and return the stream to WebKit.
+                * Otherwise try to fetch the resource again from the network. */
+               if (len > 0) {
+                       GFile *file;
+                       GFileInfo *info;
+                       gchar *path;
+
+                       path = camel_data_cache_get_filename (cache, "http", uri_md5);
+                       file = g_file_new_for_path (path);
+
+                       info = g_file_query_info (
+                               file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                               0, cancellable, NULL);
+
+                       content_type = g_file_info_get_content_type (info);
+
+                       webkit_uri_scheme_request_finish (
+                               request, stream, len, content_type);
+
+                       ret_val = TRUE;
+
+                       g_object_unref (request);
+                       g_object_unref (stream);
+
+                       d (
+                               printf ("'%s' found in cache (%d bytes, %s)\n",
+                               uri, len, content_type));
+
+                       g_object_unref (info);
+                       g_object_unref (file);
+                       g_free (path);
+               } else {
+                       d (printf ("Failed to load '%s' from cache.\n", uri));
+               }
+       }
+ cleanup:
+       if (cache)
+               g_object_unref (cache);
+
+       if (soup_uri)
+               soup_uri_free (soup_uri);
+
+       g_free (uri);
+       g_free (uri_md5);
+       g_free (mail_uri);
+
+       g_task_return_boolean (task, ret_val);
+}
+
+static void
+mail_http_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                  EMailDisplay *display)
+{
+       GTask *task;
+       GCancellable *cancellable;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       cancellable = g_cancellable_new ();
+
+       task = g_task_new (
+               display, cancellable,
+               (GAsyncReadyCallback) mail_display_process_uri_scheme_finished_cb,
+               request);
+
+       g_task_set_task_data (task, g_object_ref (request), NULL);
+       g_task_run_in_thread (task, web_view_process_http_uri_scheme_request);
+
+       g_object_unref (task);
+       g_object_unref (cancellable);
+}
+
+static void
+mail_display_process_mail_uri_scheme_request (GTask *task,
+                                              gpointer source_object,
+                                              gpointer task_data,
+                                              GCancellable *cancellable)
+{
+       GInputStream *stream = NULL;
+       EMailFormatter *formatter;
+       EMailPartList *part_list;
+       CamelStream *output_stream;
+       GByteArray *byte_array;
+       GHashTable *query;
+       const gchar *val, *uri;
+       const gchar *default_charset, *charset;
+       SoupURI *soup_uri;
+       EMailFormatterContext context = { 0 };
+       EMailDisplay *display = E_MAIL_DISPLAY (source_object);
+       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
+
+       uri = webkit_uri_scheme_request_get_uri (request);
+
+       part_list = display->priv->part_list;
+
+       if (camel_debug_start ("emformat:requests")) {
+               printf ("%s: found part-list %p for full_uri '%s'\n", G_STRFUNC, part_list, uri);
+               camel_debug_end ();
+       }
+
+       if (!part_list) {
+               g_task_return_boolean (task, FALSE);
+               return;
+       }
+
+       soup_uri = soup_uri_new (uri);
+       if (!soup_uri || !soup_uri->query) {
+               if (soup_uri)
+                       soup_uri_free (soup_uri);
+               g_task_return_boolean (task, FALSE);
+               return;
+       }
+       query = soup_form_decode (soup_uri->query);
+
+       val = g_hash_table_lookup (query, "headers_collapsed");
+       if (val && atoi (val) == 1)
+               context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED;
+
+       val = g_hash_table_lookup (query, "headers_collapsable");
+       if (val && atoi (val) == 1)
+               context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE;
+
+       val = g_hash_table_lookup (query, "mode");
+       if (val)
+               context.mode = atoi (val);
+
+       default_charset = g_hash_table_lookup (query, "formatter_default_charset");
+       charset = g_hash_table_lookup (query, "formatter_charset");
+
+       context.part_list = g_object_ref (part_list);
+       context.uri = g_strdup (uri);
+
+       formatter = display->priv->formatter;
+
+       if (default_charset && *default_charset != '\0')
+               e_mail_formatter_set_default_charset (formatter, default_charset);
+       if (charset && *charset != '\0')
+               e_mail_formatter_set_charset (formatter, charset);
+
+       byte_array = g_byte_array_new ();
+       output_stream = camel_stream_mem_new ();
+
+       /* We retain ownership of the byte array. */
+       camel_stream_mem_set_byte_array (
+               CAMEL_STREAM_MEM (output_stream), byte_array);
+
+       val = g_hash_table_lookup (query, "part_id");
+       if (val) {
+               EMailPart *part;
+               const gchar *mime_type;
+               gchar *part_id;
+
+               part_id = soup_uri_decode (val);
+               part = e_mail_part_list_ref_part (part_list, part_id);
+               if (!part) {
+                       if (camel_debug_start ("emformat:requests")) {
+                               printf ("%s: part with id '%s' not found\n", G_STRFUNC, val);
+                               camel_debug_end ();
+                       }
+
+                       g_free (part_id);
+                       goto no_part;
+               }
+               g_free (part_id);
+
+               mime_type = g_hash_table_lookup (query, "mime_type");
+
+               if (context.mode == E_MAIL_FORMATTER_MODE_SOURCE)
+                       mime_type = "application/vnd.evolution.source";
+
+               if (context.mode == E_MAIL_FORMATTER_MODE_CID) {
+                       CamelDataWrapper *dw;
+                       CamelMimePart *mime_part;
+
+                       mime_part = e_mail_part_ref_mime_part (part);
+                       dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+                       if (!dw)
+                               goto no_part;
+
+                       camel_data_wrapper_decode_to_stream_sync (
+                               dw, output_stream, cancellable, NULL);
+
+                       g_object_unref (mime_part);
+               } else {
+                       if (!mime_type)
+                               mime_type = e_mail_part_get_mime_type (part);
+
+                       e_mail_formatter_format_as (
+                               formatter, &context, part,
+                               output_stream, mime_type,
+                               cancellable);
+               }
+
+               g_object_unref (part);
+       } else {
+               e_mail_formatter_format_sync (
+                       formatter, part_list, output_stream,
+                       context.flags, context.mode, cancellable);
+       }
+
+ no_part:
+       g_clear_object (&output_stream);
+       g_clear_object (&context.part_list);
+
+       if (byte_array->data == NULL) {
+               gchar *data;
+
+               data = g_strdup_printf (
+                       "<p align='center'>%s</p>",
+                       _("The message has no text content."));
+               g_byte_array_append (
+                       byte_array, (guint8 *) data, strlen (data));
+               g_free (data);
+       }
+
+       stream = g_memory_input_stream_new_from_bytes (
+               g_byte_array_free_to_bytes (byte_array));
+
+       webkit_uri_scheme_request_finish (request, stream, -1, "text/html");
+
+       g_object_unref (stream);
+
+       if (query)
+               g_hash_table_destroy (query);
+
+       if (soup_uri)
+               soup_uri_free (soup_uri);
+
+       g_task_return_boolean (task, TRUE);
+}
+
+static GInputStream *
+get_empty_image_stream (void)
+{
+       GdkPixbuf *pixbuf;
+       gchar *buffer;
+       gsize length;
+
+       pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+       gdk_pixbuf_fill (pixbuf, 0x00000000); /* transparent black */
+       gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &length, "png", NULL, NULL);
+       g_object_unref (pixbuf);
+
+       return g_memory_input_stream_new_from_data (buffer, length, g_free);
+}
+
+static void
+mail_display_process_contact_photo_uri_scheme_request (GTask *task,
+                                                       gpointer source_object,
+                                                       gpointer task_data,
+                                                       GCancellable *cancellable)
+{
+       EShell *shell;
+       EShellBackend *shell_backend;
+       EMailBackend *mail_backend;
+       EMailSession *mail_session;
+       EPhotoCache *photo_cache;
+       CamelInternetAddress *cia;
+       GInputStream *stream = NULL;
+       const gchar *uri;
+       const gchar *email_address;
+       const gchar *escaped_string;
+       gchar *unescaped_string;
+       GError *error = NULL;
+       SoupURI *soup_uri;
+       GHashTable *uri_query;
+       WebKitURISchemeRequest *request = WEBKIT_URI_SCHEME_REQUEST (task_data);
+
+       /* XXX Is this really the only way to obtain
+        *     the mail session instance from here? */
+       shell = e_shell_get_default ();
+       shell_backend = e_shell_get_backend_by_name (shell, "mail");
+       mail_backend = E_MAIL_BACKEND (shell_backend);
+       mail_session = e_mail_backend_get_session (mail_backend);
+
+       photo_cache = e_mail_ui_session_get_photo_cache (
+               E_MAIL_UI_SESSION (mail_session));
+
+       uri = webkit_uri_scheme_request_get_uri (request);
+
+       soup_uri = soup_uri_new (uri);
+       if (!soup_uri || !soup_uri->query)
+               goto exit;
+
+       uri_query = soup_form_decode (soup_uri->query);
+       escaped_string = g_hash_table_lookup (uri_query, "mailaddr");
+       if (escaped_string == NULL || *escaped_string == '\0')
+               goto exit;
+
+       cia = camel_internet_address_new ();
+
+       unescaped_string = g_uri_unescape_string (escaped_string, NULL);
+       camel_address_decode (CAMEL_ADDRESS (cia), unescaped_string);
+       g_free (unescaped_string);
+
+       if (camel_internet_address_get (cia, 0, NULL, &email_address))
+               e_photo_cache_get_photo_sync (
+                       photo_cache, email_address,
+                       cancellable, &stream, &error);
+
+       g_object_unref (cia);
+
+       /* Ignore cancellations. */
+       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_clear_error (&error);
+       } else if (error != NULL) {
+               g_warning ("%s: %s", G_STRFUNC, error->message);
+               g_clear_error (&error);
+       }
+
+exit:
+       if (!stream)
+               stream = get_empty_image_stream ();
+
+       webkit_uri_scheme_request_finish (request, stream, -1, "image/*");
+
+       g_object_unref (request);
+       g_object_unref (stream);
+
+       if (uri_query)
+               g_hash_table_destroy (uri_query);
+
+       if (soup_uri)
+               soup_uri_free (soup_uri);
+
+       g_task_return_boolean (task, TRUE);
+}
+
+static void
+mail_mail_uri_scheme_appeared_cb (WebKitURISchemeRequest *request,
+                                  EMailDisplay *display)
+{
+       GTask *task;
+       GCancellable *cancellable;
+       const gchar *uri;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       cancellable = g_cancellable_new ();
+
+       uri = webkit_uri_scheme_request_get_uri (request);
+
+       task = g_task_new (
+               display, cancellable,
+               (GAsyncReadyCallback) mail_display_process_uri_scheme_finished_cb,
+               request);
+
+       g_task_set_task_data (task, g_object_ref (request), NULL);
+
+       if (g_ascii_strncasecmp (uri, "mail://contact-photo", 20) == 0)
+               g_task_run_in_thread (task, mail_display_process_contact_photo_uri_scheme_request);
+       else
+               g_task_run_in_thread (task, mail_display_process_mail_uri_scheme_request);
+
+       g_object_unref (task);
+       g_object_unref (cancellable);
+}
+
+static void
+mail_display_update_fonts (EMailDisplay *display)
+{
+       e_web_view_update_fonts (E_WEB_VIEW (display));
+}
+
+static void
 e_mail_display_init (EMailDisplay *display)
 {
        GtkUIManager *ui_manager;
-       const gchar *user_cache_dir;
-       WebKitWebSettings *settings;
-       WebKitWebFrame *main_frame;
        GtkActionGroup *actions;
 
        display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
@@ -1625,26 +2358,21 @@ e_mail_display_init (EMailDisplay *display)
        display->priv->force_image_load = FALSE;
        display->priv->scheduled_reload = 0;
 
-       webkit_web_view_set_full_content_zoom (WEBKIT_WEB_VIEW (display), TRUE);
-
-       settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (display));
-       g_object_set (settings, "enable-frame-flattening", TRUE, NULL);
-
        g_signal_connect (
-               display, "navigation-policy-decision-requested",
-               G_CALLBACK (mail_display_link_clicked), NULL);
+               display, "decide-policy",
+               G_CALLBACK (decide_policy_cb), NULL);
+#if 0
        g_signal_connect (
                display, "resource-request-starting",
                G_CALLBACK (mail_display_resource_requested), NULL);
+#endif
        g_signal_connect (
                display, "process-mailto",
                G_CALLBACK (mail_display_process_mailto), NULL);
+#if 0
        g_signal_connect (
                display, "create-plugin-widget",
                G_CALLBACK (mail_display_plugin_widget_requested), NULL);
-       g_signal_connect (
-               display, "frame-created",
-               G_CALLBACK (mail_display_frame_created), NULL);
        e_signal_connect_notify (
                display, "notify::uri",
                G_CALLBACK (mail_display_uri_changed), NULL);
@@ -1657,7 +2385,7 @@ e_mail_display_init (EMailDisplay *display)
        g_signal_connect_after (
                display, "drag-data-get",
                G_CALLBACK (mail_display_drag_data_get), display);
-
+#endif
        display->priv->settings = e_util_ref_settings ("org.gnome.evolution.mail");
        g_signal_connect_swapped (
                display->priv->settings , "changed::monospace-font",
@@ -1673,7 +2401,10 @@ e_mail_display_init (EMailDisplay *display)
 
        main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (display));
        e_signal_connect_notify (
-               main_frame, "notify::load-status",
+               main_frame, "load-changed",
+               G_CALLBACK (setup_dom_bindings), NULL);
+       e_signal_connect_notify (
+               main_frame, "load-changed",
                G_CALLBACK (mail_parts_bind_dom), NULL);
 
        actions = e_web_view_get_action_group (E_WEB_VIEW (display), "mailto");
@@ -1683,25 +2414,18 @@ e_mail_display_init (EMailDisplay *display)
        ui_manager = e_web_view_get_ui_manager (E_WEB_VIEW (display));
        gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
 
-       e_web_view_install_request_handler (
-               E_WEB_VIEW (display), E_TYPE_MAIL_REQUEST);
-       e_web_view_install_request_handler (
-               E_WEB_VIEW (display), E_TYPE_HTTP_REQUEST);
-       e_web_view_install_request_handler (
-               E_WEB_VIEW (display), E_TYPE_FILE_REQUEST);
-       e_web_view_install_request_handler (
-               E_WEB_VIEW (display), E_TYPE_STOCK_REQUEST);
-
-       if (emd_global_http_cache == NULL) {
-               user_cache_dir = e_get_user_cache_dir ();
-               emd_global_http_cache = camel_data_cache_new (user_cache_dir, NULL);
-
-               /* cache expiry - 2 hour access, 1 day max */
-               camel_data_cache_set_expire_age (
-                       emd_global_http_cache, 24 * 60 * 60);
-               camel_data_cache_set_expire_access (
-                       emd_global_http_cache, 2 * 60 * 60);
-       }
+       e_web_view_register_uri_scheme (
+               E_WEB_VIEW (display), EVO_HTTP_URI_SCHEME,
+               mail_http_uri_scheme_appeared_cb, display);
+       e_web_view_register_uri_scheme (
+               E_WEB_VIEW (display), EVO_HTTPS_URI_SCHEME,
+               mail_http_uri_scheme_appeared_cb, display);
+       e_web_view_register_uri_scheme (
+               E_WEB_VIEW (display), CID_URI_SCHEME,
+               mail_cid_uri_scheme_appeared_cb, display);
+       e_web_view_register_uri_scheme (
+               E_WEB_VIEW (display), MAIL_URI_SCHEME,
+               mail_mail_uri_scheme_appeared_cb, display);
 }
 
 static void
@@ -1919,7 +2643,7 @@ e_mail_display_load (EMailDisplay *display,
 
        g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 
-       display->priv->force_image_load = FALSE;
+       e_mail_display_set_force_load_images (display, FALSE);
 
        part_list = display->priv->part_list;
        if (part_list == NULL) {
@@ -2080,84 +2804,43 @@ e_mail_display_set_status (EMailDisplay *display,
        g_free (str);
 }
 
-static gchar *
-mail_display_get_frame_selection_text (WebKitDOMElement *iframe)
-{
-       WebKitDOMDocument *document;
-       WebKitDOMDOMWindow *window;
-       WebKitDOMDOMSelection *selection;
-       WebKitDOMNodeList *frames;
-       gulong ii, length;
-
-       document = webkit_dom_html_iframe_element_get_content_document (
-               WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
-       window = webkit_dom_document_get_default_view (document);
-       selection = webkit_dom_dom_window_get_selection (window);
-       if (selection && (webkit_dom_dom_selection_get_range_count (selection) > 0)) {
-               WebKitDOMRange *range;
-
-               range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
-               if (range != NULL)
-                       return webkit_dom_range_to_string (range, NULL);
-       }
-
-       frames = webkit_dom_document_get_elements_by_tag_name (
-               document, "IFRAME");
-       length = webkit_dom_node_list_get_length (frames);
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMNode *node;
-               gchar *text;
-
-               node = webkit_dom_node_list_item (frames, ii);
-
-               text = mail_display_get_frame_selection_text (
-                       WEBKIT_DOM_ELEMENT (node));
-
-               if (text != NULL) {
-                       g_object_unref (frames);
-                       return text;
-               }
-       }
-
-       g_object_unref (frames);
-
-       return NULL;
-}
-
-gchar *
-e_mail_display_get_selection_plain_text (EMailDisplay *display)
+const gchar *
+e_mail_display_get_selection_plain_text_sync (EMailDisplay *display,
+                                              GCancellable *cancellable,
+                                              GError **error)
 {
-       WebKitDOMDocument *document;
-       WebKitDOMNodeList *frames;
-       gulong ii, length;
-
-       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
-
-       if (!webkit_web_view_has_selection (WEBKIT_WEB_VIEW (display)))
-               return NULL;
-
-       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
-       frames = webkit_dom_document_get_elements_by_tag_name (document, "IFRAME");
-       length = webkit_dom_node_list_get_length (frames);
-
-       for (ii = 0; ii < length; ii++) {
-               gchar *text;
-               WebKitDOMNode *node;
-
-               node = webkit_dom_node_list_item (frames, ii);
-
-               text = mail_display_get_frame_selection_text (
-                       WEBKIT_DOM_ELEMENT (node));
-
-               if (text != NULL) {
-                       g_object_unref (frames);
-                       return text;
+       GDBusProxy *web_extension;
+
+       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+/* FIXME XXX
+       if (!webkit_web_view_has_selection (WEBKIT_WEB_VIEW (display)))
+               return NULL;
+*/
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+       if (web_extension) {
+               GVariant *result;
+               const gchar *text_content = NULL;
+
+               result = g_dbus_proxy_call_sync (
+                               web_extension,
+                               "GetDocumentContentText",
+                               g_variant_new (
+                                       "(t)",
+                                       webkit_web_view_get_page_id (
+                                               WEBKIT_WEB_VIEW (display))),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               cancellable,
+                               error);
+
+               if (result) {
+                       g_variant_get (result, "(&s)", &text_content);
+                       g_variant_unref (result);
+                       return text_content;
                }
        }
 
-       g_object_unref (frames);
-
-       return NULL;
+       return NULL;
 }
 
 void
@@ -2165,7 +2848,7 @@ e_mail_display_load_images (EMailDisplay *display)
 {
        g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 
-       display->priv->force_image_load = TRUE;
+       e_mail_display_set_force_load_images (display, TRUE);
        e_web_view_reload (E_WEB_VIEW (display));
 }
 
@@ -2173,8 +2856,29 @@ void
 e_mail_display_set_force_load_images (EMailDisplay *display,
                                       gboolean force_load_images)
 {
-       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
-
-       display->priv->force_image_load = force_load_images;
+       GDBusProxy *web_extension;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+       if (web_extension) {
+               g_dbus_connection_call (
+                       g_dbus_proxy_get_connection (web_extension),
+                       g_dbus_proxy_get_name (web_extension),
+                       EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+                       "org.freedesktop.DBus.Properties",
+                       "Set",
+                       g_variant_new (
+                               "(ssv)",
+                               EVOLUTION_WEB_EXTENSION_INTERFACE,
+                               "ForceImageLoad",
+                               g_variant_new_boolean (force_load_images)),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       }
 }
 
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 25fd338..7deefd5 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -88,8 +88,10 @@ GtkAction *  e_mail_display_get_action       (EMailDisplay *display,
                                                 const gchar *action_name);
 void           e_mail_display_set_status       (EMailDisplay *display,
                                                 const gchar *status);
-gchar *                e_mail_display_get_selection_plain_text
-                                               (EMailDisplay *display);
+const gchar *  e_mail_display_get_selection_plain_text_sync
+                                               (EMailDisplay *display,
+                                                GCancellable *cancellable,
+                                                GError **error);
 void           e_mail_display_load_images      (EMailDisplay *display);
 void           e_mail_display_set_force_load_images
                                                (EMailDisplay *display,
diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c
index 3d93196..dd29a19 100644
--- a/mail/e-mail-printer.c
+++ b/mail/e-mail-printer.c
@@ -23,8 +23,6 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
-#include <webkit/webkitdom.h>
-
 #include "e-util/e-util.h"
 
 #include "em-format/e-mail-formatter-print.h"
@@ -192,7 +190,7 @@ mail_printer_print_timeout_cb (gpointer user_data)
        GtkPrintOperation *print_operation;
        GtkPrintOperationAction print_action;
        EMailPrinter *printer;
-       WebKitWebFrame *web_frame;
+//     WebKitWebFrame *web_frame;
        gulong create_custom_widget_handler_id;
        gulong custom_widget_apply_handler_id;
        gulong draw_page_handler_id;
@@ -240,12 +238,12 @@ mail_printer_print_timeout_cb (gpointer user_data)
                print_operation, "draw-page",
                G_CALLBACK (mail_printer_draw_footer_cb),
                async_context->cancellable);
-
+/*
        web_frame = webkit_web_view_get_main_frame (async_context->web_view);
 
        async_context->print_result = webkit_web_frame_print_full (
                web_frame, print_operation, print_action, &error);
-
+*/
        /* Sanity check. */
        switch (async_context->print_result) {
                case GTK_PRINT_OPERATION_RESULT_ERROR:
@@ -294,18 +292,16 @@ exit:
 }
 
 static void
-mail_printer_load_status_cb (WebKitWebView *web_view,
-                             GParamSpec *pspec,
-                             GSimpleAsyncResult *simple)
+mail_printer_load_changed_cb (WebKitWebView *web_view,
+                              WebKitLoadEvent load_event,
+                              GSimpleAsyncResult *simple)
 {
        AsyncContext *async_context;
-       WebKitLoadStatus load_status;
        GCancellable *cancellable;
        GError *error = NULL;
 
        /* Note: we disregard WEBKIT_LOAD_FAILED and print what we can. */
-       load_status = webkit_web_view_get_load_status (web_view);
-       if (load_status != WEBKIT_LOAD_FINISHED)
+       if (load_event != WEBKIT_LOAD_FINISHED)
                return;
 
        /* Signal handlers are holding the only GSimpleAsyncResult
@@ -352,7 +348,7 @@ mail_printer_new_web_view (const gchar *charset,
                            const gchar *default_charset)
 {
        WebKitWebView *web_view;
-       WebKitWebSettings *web_settings;
+       WebKitSettings *web_settings;
        EMailFormatter *formatter;
 
        web_view = g_object_new (
@@ -563,8 +559,8 @@ e_mail_printer_print (EMailPrinter *printer,
        async_context->web_view = g_object_ref_sink (web_view);
 
        handler_id = g_signal_connect_data (
-               web_view, "notify::load-status",
-               G_CALLBACK (mail_printer_load_status_cb),
+               web_view, "load-changed",
+               G_CALLBACK (mail_printer_load_changed_cb),
                g_object_ref (simple),
                (GClosureNotify) g_object_unref, 0);
        async_context->load_status_handler_id = handler_id;
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index e8e6f80..49f6ec4 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -2040,7 +2040,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
        EWebView *web_view;
        struct _camel_header_raw *header;
        const gchar *uid;
-       gchar *selection = NULL;
+       const gchar *selection;
        gint length;
        gchar *mail_uri;
        CamelObjectBag *registry;
@@ -2141,7 +2141,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
        if (!e_web_view_is_selection_active (web_view))
                goto whole_message;
 
-       selection = e_web_view_get_selection_html (web_view);
+       selection = e_web_view_get_selection_content_html_sync (web_view, NULL, NULL);
        if (selection == NULL || *selection == '\0')
                goto whole_message;
 
@@ -2209,8 +2209,6 @@ e_mail_reader_reply_to_message (EMailReader *reader,
 
        g_object_unref (new_message);
 
-       g_free (selection);
-
        goto exit;
 
 whole_message:
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index d86bf44..c35af89 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -1890,6 +1890,7 @@ action_mail_zoom_in_cb (GtkAction *action,
                         EMailReader *reader)
 {
        EMailDisplay *display;
+       gdouble zoom_level;
 
        display = e_mail_reader_get_mail_display (reader);
 
@@ -1901,6 +1902,7 @@ action_mail_zoom_out_cb (GtkAction *action,
                          EMailReader *reader)
 {
        EMailDisplay *display;
+       gdouble zoom_level;
 
        display = e_mail_reader_get_mail_display (reader);
 
@@ -2638,33 +2640,21 @@ mail_reader_key_press_event_cb (EMailReader *reader,
        const gchar *action_name;
 
        if (!gtk_widget_has_focus (GTK_WIDGET (reader))) {
-               WebKitWebFrame *frame;
-               WebKitDOMDocument *dom;
-               WebKitDOMElement *element;
                EMailDisplay *display;
-               gchar *name = NULL;
+               GDBusProxy *web_extension;
 
                display = e_mail_reader_get_mail_display (reader);
-               frame = webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (display));
-
-               if (frame != NULL) {
-                       dom = webkit_web_frame_get_dom_document (frame);
-                       /* intentionally used "static_cast" */
-                       element = webkit_dom_html_document_get_active_element (WEBKIT_DOM_HTML_DOCUMENT 
(dom));
-
-                       if (element != NULL)
-                               name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (element));
-
-                       /* If INPUT or TEXTAREA has focus,
-                        * then any key press should go there. */
-                       if (name != NULL &&
-                           (g_ascii_strcasecmp (name, "INPUT") == 0 ||
-                            g_ascii_strcasecmp (name, "TEXTAREA") == 0)) {
-                               g_free (name);
-                               return FALSE;
-                       }
-                       g_free (name);
-               }
+               web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+               if (web_extension) {
+                       GVariant *result;
+
+                       result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
+                       if (result) {
+                               gboolean need_input = g_variant_get_boolean (result);
+                               g_variant_unref (result);
+
+                               if (need_input)
+                                       return FALSE;
        }
 
        if ((event->state & GDK_CONTROL_MASK) != 0)
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index 898a3e5..f11b3be 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -24,7 +24,7 @@
 #include <libsoup/soup-requester.h>
 #include <libsoup/soup-request-http.h>
 
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
 
 #include <glib/gi18n.h>
 #include <camel/camel.h>
diff --git a/modules/itip-formatter/Makefile.am b/modules/itip-formatter/Makefile.am
index 2e1168b..a49cea6 100644
--- a/modules/itip-formatter/Makefile.am
+++ b/modules/itip-formatter/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = plugin
+SUBDIRS = plugin web-extension
 
 @EVO_PLUGIN_RULE@
 
@@ -27,7 +27,8 @@ module_itip_formatter_la_SOURCES =                                    \
        e-source-conflict-search.h                                      \
        itip-view.c                                                     \
        itip-view.h                                                     \
-       evolution-module-itip-formatter.c
+       evolution-module-itip-formatter.c                               \
+       itip-view-elements-defines.h
 
 module_itip_formatter_la_LIBADD =                                      \
        $(top_builddir)/e-util/libevolution-util.la                     \
diff --git a/modules/itip-formatter/e-mail-formatter-itip.c b/modules/itip-formatter/e-mail-formatter-itip.c
index 1439cf1..581e4a3 100644
--- a/modules/itip-formatter/e-mail-formatter-itip.c
+++ b/modules/itip-formatter/e-mail-formatter-itip.c
@@ -69,7 +69,7 @@ emfe_itip_format (EMailFormatterExtension *extension,
                buffer = g_string_sized_new (1024);
 
                itip_part->view = itip_view_new (
-                       itip_part, itip_part->client_cache);
+                       itip_part, itip_part->client_cache, "", 0);
 
                itip_view_init_view (itip_part->view);
                itip_view_write_for_printing (itip_part->view, buffer);
diff --git a/modules/itip-formatter/e-mail-part-itip.c b/modules/itip-formatter/e-mail-part-itip.c
index bcc48db..b7e9113 100644
--- a/modules/itip-formatter/e-mail-part-itip.c
+++ b/modules/itip-formatter/e-mail-part-itip.c
@@ -76,45 +76,26 @@ mail_part_itip_finalize (GObject *object)
 
 static void
 mail_part_itip_bind_dom_element (EMailPart *part,
-                                 WebKitDOMElement *element)
+                                 GDBusProxy *evolution_web_extension,
+                                 guint64 page_id,
+                                 const gchar *element_id)
 {
-       GString *buffer;
-       WebKitDOMDocument *document;
-       ItipView *view;
        EMailPartItip *pitip;
 
        pitip = E_MAIL_PART_ITIP (part);
 
-       if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
-               WebKitDOMNodeList *nodes;
-               guint length;
-
-               nodes = webkit_dom_element_get_elements_by_tag_name (
-                       element, "iframe");
-               length = webkit_dom_node_list_get_length (nodes);
-               if (length > 0)
-                       element = WEBKIT_DOM_ELEMENT (
-                               webkit_dom_node_list_item (nodes, 0));
-
-               g_object_unref (nodes);
-       }
+       /* FIXME XXX WK2 checks */
+#if 0
+       if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+               element = webkit_dom_element_query_selector (
+                       element, "iframe", NULL);
 
        g_return_if_fail (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element));
 
-       buffer = g_string_new ("");
        document = webkit_dom_html_iframe_element_get_content_document (
                WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
-
-       view = itip_view_new (pitip, pitip->client_cache);
-       g_object_set_data_full (
-               G_OBJECT (element), "view", view,
-               (GDestroyNotify) g_object_unref);
-
-       itip_view_create_dom_bindings (
-               view, webkit_dom_document_get_document_element (document));
-
-       itip_view_init_view (view);
-       g_string_free (buffer, TRUE);
+#endif
+       itip_view_new (pitip, pitip->client_cache, element_id, page_id);
 }
 
 static void
diff --git a/modules/itip-formatter/itip-view-elements-defines.h 
b/modules/itip-formatter/itip-view-elements-defines.h
new file mode 100644
index 0000000..35bf653
--- /dev/null
+++ b/modules/itip-formatter/itip-view-elements-defines.h
@@ -0,0 +1,65 @@
+/*
+ * itip-view-elements-defines.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef ITIP_VIEW_ELEMENTS_DEFINES_H
+#define ITIP_VIEW_ELEMENTS_DEFINES_H
+
+#define TEXT_ROW_SENDER "text_row_sender"
+#define TABLE_ROW_SUMMARY "table_row_summary"
+#define TABLE_ROW_LOCATION "table_row_location"
+#define TABLE_ROW_START_DATE "table_row_start_time"
+#define TABLE_ROW_END_DATE "table_row_end_time"
+#define TABLE_ROW_STATUS "table_row_status"
+#define TABLE_ROW_COMMENT "table_row_comment"
+#define TABLE_ROW_DESCRIPTION "table_row_description"
+#define TABLE_ROW_RSVP_COMMENT "table_row_rsvp_comment"
+#define TABLE_ROW_ESCB "table_row_escb"
+#define TABLE_ROW_BUTTONS "table_row_buttons"
+#define TABLE_ROW_ESCB_LABEL "table_row_escb_label"
+
+#define TABLE_BUTTONS "table_buttons"
+
+#define SELECT_ESOURCE "select_esource"
+#define TEXTAREA_RSVP_COMMENT "textarea_rsvp_comment"
+
+#define CHECKBOX_RSVP "checkbox_rsvp"
+#define CHECKBOX_RECUR "checkbox_recur"
+#define CHECKBOX_UPDATE "checkbox_update"
+#define CHECKBOX_FREE_TIME "checkbox_free_time"
+#define CHECKBOX_KEEP_ALARM "checkbox_keep_alarm"
+#define CHECKBOX_INHERIT_ALARM "checkbox_inherit_alarm"
+
+#define BUTTON_OPEN_CALENDAR "button_open_calendar"
+#define BUTTON_DECLINE "button_decline"
+#define BUTTON_DECLINE_ALL "button_decline_all"
+#define BUTTON_ACCEPT "button_accept"
+#define BUTTON_ACCEPT_ALL "button_accept_all"
+#define BUTTON_TENTATIVE "button_tentative"
+#define BUTTON_TENTATIVE_ALL "button_tentative_all"
+#define BUTTON_SEND_INFORMATION "button_send_information"
+#define BUTTON_UPDATE "button_update"
+#define BUTTON_UPDATE_ATTENDEE_STATUS "button_update_attendee_status"
+#define BUTTON_SAVE "button_save"
+
+#define TABLE_UPPER_ITIP_INFO "table_upper_itip_info"
+#define TABLE_LOWER_ITIP_INFO "table_lower_itip_info"
+
+#define DIV_ITIP_CONTENT "div_itip_content"
+#define DIV_ITIP_ERROR "div_itip_error"
+
+#endif /* ITIP_VIEW_ELEMENTS_DEFINES_H */
diff --git a/modules/itip-formatter/itip-view.c b/modules/itip-formatter/itip-view.c
index 395eabb..6b16d4e 100644
--- a/modules/itip-formatter/itip-view.c
+++ b/modules/itip-formatter/itip-view.c
@@ -25,7 +25,6 @@
 
 #include <string.h>
 #include <glib/gi18n.h>
-#include <webkit/webkitdom.h>
 #include <libedataserver/libedataserver.h>
 
 #include <shell/e-shell.h>
@@ -42,6 +41,10 @@
 #include "itip-view.h"
 #include "e-mail-part-itip.h"
 
+#include "itip-view-elements-defines.h"
+
+#include "web-extension/module-itip-formatter-web-extension.h"
+
 #define d(x)
 
 #define MEETING_ICON "stock_new-meeting"
@@ -107,55 +110,20 @@ struct _ItipViewPrivate {
 
        gint needs_decline : 1;
 
-        WebKitDOMDocument *dom_document;
         EMailPartItip *itip_part;
 
+       GDBusProxy *web_extension;
+       guint web_extension_watch_name_id;
+       guint web_extension_source_changed_signal_id;
+       guint web_extension_button_clicked_signal_id;
+       guint web_extension_recur_toggled_signal_id;
+
+       const gchar *element_id;
+       guint64 page_id;
+
         gchar *error;
 };
 
-#define TEXT_ROW_SENDER "text_row_sender"
-#define TABLE_ROW_SUMMARY "table_row_summary"
-#define TABLE_ROW_LOCATION "table_row_location"
-#define TABLE_ROW_START_DATE "table_row_start_time"
-#define TABLE_ROW_END_DATE "table_row_end_time"
-#define TABLE_ROW_STATUS "table_row_status"
-#define TABLE_ROW_COMMENT "table_row_comment"
-#define TABLE_ROW_DESCRIPTION "table_row_description"
-#define TABLE_ROW_RSVP_COMMENT "table_row_rsvp_comment"
-#define TABLE_ROW_ESCB "table_row_escb"
-#define TABLE_ROW_BUTTONS "table_row_buttons"
-#define TABLE_ROW_ESCB_LABEL "table_row_escb_label"
-
-#define TABLE_BUTTONS "table_buttons"
-
-#define SELECT_ESOURCE "select_esource"
-#define TEXTAREA_RSVP_COMMENT "textarea_rsvp_comment"
-
-#define CHECKBOX_RSVP "checkbox_rsvp"
-#define CHECKBOX_RECUR "checkbox_recur"
-#define CHECKBOX_UPDATE "checkbox_update"
-#define CHECKBOX_FREE_TIME "checkbox_free_time"
-#define CHECKBOX_KEEP_ALARM "checkbox_keep_alarm"
-#define CHECKBOX_INHERIT_ALARM "checkbox_inherit_alarm"
-
-#define BUTTON_OPEN_CALENDAR "button_open_calendar"
-#define BUTTON_DECLINE "button_decline"
-#define BUTTON_DECLINE_ALL "button_decline_all"
-#define BUTTON_ACCEPT "button_accept"
-#define BUTTON_ACCEPT_ALL "button_accept_all"
-#define BUTTON_TENTATIVE "button_tentative"
-#define BUTTON_TENTATIVE_ALL "button_tentative_all"
-#define BUTTON_SEND_INFORMATION "button_send_information"
-#define BUTTON_UPDATE "button_update"
-#define BUTTON_UPDATE_ATTENDEE_STATUS "button_update_attendee_status"
-#define BUTTON_SAVE "button_save"
-
-#define TABLE_UPPER_ITIP_INFO "table_upper_itip_info"
-#define TABLE_LOWER_ITIP_INFO "table_lower_itip_info"
-
-#define DIV_ITIP_CONTENT "div_itip_content"
-#define DIV_ITIP_ERROR "div_itip_error"
-
 enum {
        PROP_0,
        PROP_CLIENT_CACHE,
@@ -614,6 +582,199 @@ set_journal_sender_text (ItipView *view)
 }
 
 static void
+enable_button (ItipView *view,
+              const gchar *button_id,
+               gboolean enable)
+{
+       if (!view->priv->web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "EnableButton",
+               g_variant_new ("(sb)", button_id, enable),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static void
+show_button (ItipView *view,
+             const gchar *id)
+{
+       if (!view->priv->web_extension)
+                       return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "ShowButton",
+               g_variant_new ("(s)", id),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static void
+hide_element (ItipView *view,
+             const gchar *element_id,
+              gboolean hide)
+{
+       if (!view->priv->web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "HideElement",
+               g_variant_new ("(sb)", element_id, hide),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static gboolean
+element_is_hidden (ItipView *view,
+                   const gchar *element_id)
+{
+       GVariant *result;
+       gboolean hidden;
+
+       if (!view->priv->web_extension)
+               return FALSE;
+
+       result = g_dbus_proxy_call_sync (
+                       view->priv->web_extension,
+                       "ElementIsHidden",
+                       g_variant_new ("(s)", element_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL);
+
+       if (result) {
+               g_variant_get (result, "(b)", &hidden);
+               g_variant_unref (result);
+               return hidden;
+       }
+
+       return FALSE;
+}
+
+static void
+set_inner_html (ItipView *view,
+               const gchar *element_id,
+                const gchar *inner_html)
+{
+       if (!view->priv->web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "ElementSetInnerHTML",
+               g_variant_new ("(ss)", element_id, inner_html),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static void
+input_set_checked (ItipView *view,
+                   const gchar *input_id,
+                   gboolean checked)
+{
+       if (!view->priv->web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "InputSetChecked",
+               g_variant_new ("(sb)", input_id, checked),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static gboolean
+input_is_checked (ItipView *view,
+                  const gchar *input_id)
+{
+       GVariant *result;
+       gboolean checked;
+
+       if (!view->priv->web_extension)
+               return FALSE;
+
+       result = g_dbus_proxy_call_sync (
+                       view->priv->web_extension,
+                       "InputIsChecked",
+                       g_variant_new ("(s)", input_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL);
+
+       if (result) {
+               g_variant_get (result, "(b)", &checked);
+               g_variant_unref (result);
+               return checked;
+       }
+
+       return FALSE;
+}
+
+static void
+show_checkbox (ItipView *view,
+               const gchar *id,
+               gboolean show,
+              gboolean update_second)
+{
+       g_return_if_fail (ITIP_IS_VIEW (view));
+
+       if (!view->priv->web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "ShowCheckbox",
+               g_variant_new ("(sbb)", id, show, update_second),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static void
+set_area_text (ItipView *view,
+               const gchar *id,
+               const gchar *text)
+{
+       g_return_if_fail (ITIP_IS_VIEW (view));
+
+       if (!view->priv->web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "SetAreaText",
+               g_variant_new ("(ss)", id, text ? text : ""),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+static void
 set_sender_text (ItipView *view)
 {
        ItipViewPrivate *priv;
@@ -637,21 +798,14 @@ set_sender_text (ItipView *view)
                break;
        }
 
-       if (priv->sender && priv->dom_document) {
-               WebKitDOMElement *div;
-
-               div = webkit_dom_document_get_element_by_id (
-                       priv->dom_document, TEXT_ROW_SENDER);
-               webkit_dom_html_element_set_inner_html (
-                       WEBKIT_DOM_HTML_ELEMENT (div), priv->sender, NULL);
-       }
+       if (priv->sender && priv->web_extension)
+               set_inner_html (view, TEXT_ROW_SENDER, priv->sender);
 }
 
 static void
 update_start_end_times (ItipView *view)
 {
        ItipViewPrivate *priv;
-       WebKitDOMElement *row, *col;
        gchar buffer[256];
        time_t now;
        struct tm *now_tm;
@@ -696,124 +850,92 @@ update_start_end_times (ItipView *view)
        }
        #undef is_same
 
-       if (priv->dom_document) {
-               row = webkit_dom_document_get_element_by_id (
-                       priv->dom_document, TABLE_ROW_START_DATE);
-               if (priv->start_header && priv->start_label) {
-                       webkit_dom_html_element_set_hidden (
-                               WEBKIT_DOM_HTML_ELEMENT (row), FALSE);
-
-                       col = webkit_dom_element_get_first_element_child (row);
-                       webkit_dom_html_element_set_inner_html (
-                               WEBKIT_DOM_HTML_ELEMENT (col), priv->start_header, NULL);
-
-                       col = webkit_dom_element_get_last_element_child (row);
-                       webkit_dom_html_element_set_inner_html (
-                               WEBKIT_DOM_HTML_ELEMENT (col), priv->start_label, NULL);
-               } else {
-                       webkit_dom_html_element_set_hidden (
-                               WEBKIT_DOM_HTML_ELEMENT (row), TRUE);
-               }
-
-               row = webkit_dom_document_get_element_by_id (
-                       priv->dom_document, TABLE_ROW_END_DATE);
-               if (priv->end_header && priv->end_label) {
-                       webkit_dom_html_element_set_hidden (
-                               WEBKIT_DOM_HTML_ELEMENT (row), FALSE);
-
-                       col = webkit_dom_element_get_first_element_child (row);
-                       webkit_dom_html_element_set_inner_html (
-                               WEBKIT_DOM_HTML_ELEMENT (col), priv->end_header, NULL);
+       if (!priv->web_extension)
+               return;
 
-                       col = webkit_dom_element_get_last_element_child (row);
-                       webkit_dom_html_element_set_inner_html (
-                               WEBKIT_DOM_HTML_ELEMENT (col), priv->end_label, NULL);
-               } else {
-                       webkit_dom_html_element_set_hidden (
-                               WEBKIT_DOM_HTML_ELEMENT (row), TRUE);
-               }
-       }
+       if (priv->start_header && priv->start_label) {
+               g_dbus_proxy_call (
+                       priv->web_extension,
+                       "UpdateTimes",
+                       g_variant_new (
+                               "(sss)",
+                               TABLE_ROW_START_DATE,
+                               priv->start_header,
+                               priv->start_label),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       } else
+               hide_element (view, TABLE_ROW_START_DATE, TRUE);
+
+       if (priv->end_header && priv->end_label) {
+               g_dbus_proxy_call (
+                       priv->web_extension,
+                       "UpdateTimes",
+                       g_variant_new (
+                               "(sss)",
+                               TABLE_ROW_END_DATE,
+                               priv->end_header,
+                               priv->end_label),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+       } else
+               hide_element (view, TABLE_ROW_END_DATE, TRUE);
 }
 
 static void
-button_clicked_cb (WebKitDOMElement *element,
-                   WebKitDOMEvent *event,
-                   gpointer data)
+button_clicked (const gchar *button_value,
+                ItipView *view)
 {
        ItipViewResponse response;
-       gchar *responseStr;
 
-       responseStr = webkit_dom_html_button_element_get_value (
-               WEBKIT_DOM_HTML_BUTTON_ELEMENT (element));
+       response = atoi (button_value);
 
-       response = atoi (responseStr);
-
-       g_signal_emit (data, signals[RESPONSE], 0, response);
+       g_signal_emit (view, signals[RESPONSE], 0, response);
 }
 
 static void
-rsvp_toggled_cb (WebKitDOMHTMLInputElement *input,
-                 WebKitDOMEvent *event,
-                 gpointer data)
+button_clicked_signal_cb (GDBusConnection *connection,
+                          const gchar *sender_name,
+                          const gchar *object_path,
+                          const gchar *interface_name,
+                          const gchar *signal_name,
+                          GVariant *parameters,
+                          ItipView *view)
 {
-       WebKitDOMElement *el;
+       const gchar *button_value;
 
-       ItipView *view = data;
-       gboolean rsvp;
+       if (g_strcmp0 (signal_name, "ButtonClicked") != 0)
+               return;
 
-       rsvp = webkit_dom_html_input_element_get_checked (input);
+       if (parameters)
+               g_variant_get (parameters, "(&s)", &button_value);
 
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
-       webkit_dom_html_text_area_element_set_disabled (
-               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp);
+       button_clicked (button_value, view);
 }
 
 static void
-recur_toggled_cb (WebKitDOMHTMLInputElement *input,
-                  WebKitDOMEvent *event,
-                  gpointer data)
-{
-       ItipView *view = data;
+recur_toggled_signal_cb (GDBusConnection *connection,
+                         const gchar *sender_name,
+                         const gchar *object_path,
+                         const gchar *interface_name,
+                         const gchar *signal_name,
+                         GVariant *parameters,
+                         ItipView *view)
+{
+       if (g_strcmp0 (signal_name, "RecurToggled") != 0)
+               return;
 
        itip_view_set_mode (view, view->priv->mode);
 }
 
-/*
-  alarm_check_toggled_cb
-  check1 was changed, so make the second available based on state of the first check.
-*/
 static void
-alarm_check_toggled_cb (WebKitDOMHTMLInputElement *check1,
-                        WebKitDOMEvent *event,
-                        ItipView *view)
-{
-       WebKitDOMElement *check2;
-       gchar *id;
-
-       id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (check1));
-
-       if (g_strcmp0 (id, CHECKBOX_INHERIT_ALARM)) {
-               check2 = webkit_dom_document_get_element_by_id (
-                       view->priv->dom_document, CHECKBOX_KEEP_ALARM);
-       } else {
-               check2 = webkit_dom_document_get_element_by_id (
-                       view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
-       }
-
-       g_free (id);
-
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (check2),
-               (webkit_dom_html_element_get_hidden (
-                               WEBKIT_DOM_HTML_ELEMENT (check1)) &&
-                       webkit_dom_html_input_element_get_checked (check1)));
-}
-
-static void
-source_changed_cb (WebKitDOMElement *select,
-                   WebKitDOMEvent *event,
-                   ItipView *view)
+source_changed (ItipView *view)
 {
        ESource *source;
 
@@ -826,6 +948,21 @@ source_changed_cb (WebKitDOMElement *select,
 }
 
 static void
+source_changed_signal_cb (GDBusConnection *connection,
+                          const gchar *sender_name,
+                          const gchar *object_path,
+                          const gchar *interface_name,
+                          const gchar *signal_name,
+                          GVariant *parameters,
+                          ItipView *view)
+{
+       if (g_strcmp0 (signal_name, "SourceChanged") != 0)
+               return;
+
+       source_changed (view);
+}
+
+static void
 append_checkbox_table_row (GString *buffer,
                            const gchar *name,
                            const gchar *label)
@@ -889,19 +1026,8 @@ append_info_item_row (ItipView *view,
                       const gchar *table_id,
                       ItipViewInfoItem *item)
 {
-       WebKitDOMElement *table;
-       WebKitDOMHTMLElement *row, *cell;
        const gchar *icon_name;
-       gchar *id;
-
-       table = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, table_id);
-       row = webkit_dom_html_table_element_insert_row (
-               WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
-
-       id = g_strdup_printf ("%s_row_%d", table_id, item->id);
-       webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (row), id);
-       g_free (id);
+       gchar *row_id;
 
        switch (item->type) {
                case ITIP_VIEW_INFO_ITEM_TYPE_INFO:
@@ -921,31 +1047,27 @@ append_info_item_row (ItipView *view,
                        icon_name = NULL;
        }
 
-       cell = webkit_dom_html_table_row_element_insert_cell (
-               WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
-
-       if (icon_name) {
-               WebKitDOMElement *image;
-               gchar *icon_uri;
-
-               image = webkit_dom_document_create_element (
-                       view->priv->dom_document, "IMG", NULL);
-
-               icon_uri = g_strdup_printf ("gtk-stock://%s", icon_name);
-               webkit_dom_html_image_element_set_src (
-                       WEBKIT_DOM_HTML_IMAGE_ELEMENT (image), icon_uri);
-               g_free (icon_uri);
-
-               webkit_dom_node_append_child (
-                       WEBKIT_DOM_NODE (cell),
-                       WEBKIT_DOM_NODE (image),
-                       NULL);
-       }
-
-       cell = webkit_dom_html_table_row_element_insert_cell (
-               WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+       row_id = g_strdup_printf ("%s_row_%d", table_id, item->id);
+
+       if (!view->priv->web_extension)
+                       return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "AppendInfoItemRow",
+               g_variant_new (
+                       "(ssss)",
+                       table_id,
+                       row_id,
+                       icon_name,
+                       item->message),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
-       webkit_dom_html_element_set_inner_html (cell, item->message, NULL);
+       g_free (row_id);
 
        d (printf ("Added row %s_row_%d ('%s')\n", table_id, item->id, item->message));
 }
@@ -955,18 +1077,23 @@ remove_info_item_row (ItipView *view,
                       const gchar *table_id,
                       guint id)
 {
-       WebKitDOMElement *row;
        gchar *row_id;
 
        row_id = g_strdup_printf ("%s_row_%d", table_id, id);
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, row_id);
-       g_free (row_id);
 
-       webkit_dom_node_remove_child (
-               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)),
-               WEBKIT_DOM_NODE (row),
-               NULL);
+       if (!view->priv->web_extension)
+                       return;
+
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "RemoveElement",
+               g_variant_new ("(s)", row_id),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+
+       g_free (row_id);
 
        d (printf ("Removed row %s_row_%d\n", table_id, id));
 }
@@ -1054,106 +1181,60 @@ static void
 itip_view_rebuild_source_list (ItipView *view)
 {
        ESourceRegistry *registry;
-       WebKitDOMElement *select;
        GList *list, *link;
        const gchar *extension_name;
-       GHashTable *groups;
 
        d (printf ("Assigning a new source list!\n"));
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
        registry = view->priv->registry;
        extension_name = itip_view_get_extension_name (view);
 
-       select = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, SELECT_ESOURCE);
-
-       while (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (select))) {
-               webkit_dom_node_remove_child (
-                       WEBKIT_DOM_NODE (select),
-                       webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (select)),
-                       NULL);
-       }
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "ElementRemoveChildNodes",
+               g_variant_new ("(s)", SELECT_ESOURCE),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
        if (extension_name == NULL)
                return;
 
        list = e_source_registry_list_enabled (registry, extension_name);
-       groups = g_hash_table_new_full (
-               g_str_hash, g_str_equal,
-               (GDestroyNotify) g_free, NULL);
 
        for (link = list; link != NULL; link = g_list_next (link)) {
                ESource *source = E_SOURCE (link->data);
                ESource *parent;
-               WebKitDOMElement *option;
-               WebKitDOMHTMLOptGroupElement *optgroup;
 
                parent = e_source_registry_ref_source (
                        registry, e_source_get_parent (source));
 
-               optgroup = g_hash_table_lookup (groups, e_source_get_uid (parent));
-               if (!optgroup) {
-                       optgroup = WEBKIT_DOM_HTML_OPT_GROUP_ELEMENT (
-                                       webkit_dom_document_create_element (
-                                               view->priv->dom_document,
-                                               "OPTGROUP", NULL));
-                       webkit_dom_html_opt_group_element_set_label (
-                               optgroup, e_source_get_display_name (parent));
-                       g_hash_table_insert (
-                               groups, g_strdup (e_source_get_uid (parent)), optgroup);
-               }
-               g_object_unref (parent);
-
-               option = webkit_dom_document_create_element (
-                       view->priv->dom_document, "OPTION", NULL);
-               webkit_dom_html_option_element_set_value (
-                       WEBKIT_DOM_HTML_OPTION_ELEMENT (option),
-                       e_source_get_uid (source));
-               webkit_dom_html_option_element_set_label (
-                       WEBKIT_DOM_HTML_OPTION_ELEMENT (option),
-                       e_source_get_display_name (source));
-               webkit_dom_html_element_set_inner_html (
-                       WEBKIT_DOM_HTML_ELEMENT (option),
-                       e_source_get_display_name (source), NULL);
-
-               /* See https://bugzilla.gnome.org/show_bug.cgi?id=681400
-                * FIXME: This can be removed once we require WebKitGtk 1.10+ */
-               #if WEBKIT_CHECK_VERSION (1, 9, 6)
-                       webkit_dom_element_set_class_name (
-                               WEBKIT_DOM_ELEMENT (option), "calendar");
-               #else
-                       webkit_dom_html_element_set_class_name (
-                               WEBKIT_DOM_HTML_ELEMENT (option), "calendar");
-               #endif
-
-               if (!e_source_get_writable (source)) {
-                       webkit_dom_html_option_element_set_disabled (
-                               WEBKIT_DOM_HTML_OPTION_ELEMENT (option), TRUE);
-               }
+               g_dbus_proxy_call (
+                       view->priv->web_extension,
+                       "RebuildSourceList",
+                       g_variant_new (
+                               "(ssssb)",
+                               e_source_get_uid (parent),
+                               e_source_get_display_name (parent),
+                               e_source_get_uid (source),
+                               e_source_get_display_name (source),
+                               e_source_get_writable (source)),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
 
-               webkit_dom_node_append_child (
-                       WEBKIT_DOM_NODE (optgroup),
-                       WEBKIT_DOM_NODE (option),
-                       NULL);
+               g_object_unref (parent);
        }
 
        g_list_free_full (list, (GDestroyNotify) g_object_unref);
 
-       list = g_hash_table_get_values (groups);
-       for (link = list; link != NULL; link = g_list_next (link)) {
-               WebKitDOMNode *optgroup = link->data;
-
-               webkit_dom_node_append_child (
-                       WEBKIT_DOM_NODE (select), optgroup, NULL);
-       }
-       g_list_free (list);
-
-       g_hash_table_destroy (groups);
-
-       source_changed_cb (select, NULL, view);
+       source_changed_cb (view);
 }
 
 static void
@@ -1271,8 +1352,35 @@ itip_view_dispose (GObject *object)
                priv->source_removed_handler_id = 0;
        }
 
+       if (priv->web_extension_watch_name_id > 0) {
+               g_bus_unwatch_name (priv->web_extension_watch_name_id);
+               priv->web_extension_watch_name_id = 0;
+       }
+
+       if (priv->web_extension_recur_toggled_signal_id > 0) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (priv->web_extension),
+                       priv->web_extension_recur_toggled_signal_id);
+               priv->web_extension_recur_toggled_signal_id = 0;
+       }
+
+       if (priv->web_extension_source_changed_signal_id > 0) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (priv->web_extension),
+                       priv->web_extension_source_changed_signal_id);
+               priv->web_extension_source_changed_signal_id = 0;
+       }
+
+       if (priv->web_extension_button_clicked_signal_id > 0) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (priv->web_extension),
+                       priv->web_extension_button_clicked_signal_id);
+               priv->web_extension_button_clicked_signal_id = 0;
+       }
+
        g_clear_object (&priv->client_cache);
        g_clear_object (&priv->registry);
+       g_clear_object (&priv->web_extension);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (itip_view_parent_class)->dispose (object);
@@ -1288,7 +1396,6 @@ itip_view_finalize (GObject *object)
 
        d (printf ("Itip view finalized!\n"));
 
-       g_clear_object (&priv->dom_document);
        g_free (priv->extension_name);
        g_free (priv->sender);
        g_free (priv->organizer);
@@ -1631,130 +1738,149 @@ itip_view_write_for_printing (ItipView *view,
 
 void
 itip_view_create_dom_bindings (ItipView *view,
-                               WebKitDOMElement *element)
+                               const gchar *element_id)
 {
-       WebKitDOMElement *el;
-       WebKitDOMDocument *doc;
-
-       doc = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
-       view->priv->dom_document = g_object_ref (doc);
-
-       el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RECUR);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (recur_toggled_cb), FALSE, view);
-       }
-
-       el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RSVP);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (rsvp_toggled_cb), FALSE, view);
-       }
+       if (!view->priv->web_extension)
+               return;
 
-       el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_INHERIT_ALARM);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (alarm_check_toggled_cb), FALSE, view);
-       }
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "SaveDocumentFromElement",
+               g_variant_new ("(ts)", view->priv->page_id, element_id),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
-       el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_KEEP_ALARM);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (alarm_check_toggled_cb), FALSE, view);
-       }
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "CreateDOMBindings",
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_OPEN_CALENDAR);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+static void
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+                                GAsyncResult *result,
+                                ItipView *view)
+{
+       GError *error = NULL;
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+       view->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
+       if (!view->priv->web_extension) {
+               g_warning ("Error creating web extension proxy: %s\n", error->message);
+               g_error_free (error);
+       }
+
+       view->priv->web_extension_source_changed_signal_id =
+               g_dbus_connection_signal_subscribe (
+                       g_dbus_proxy_get_connection (view->priv->web_extension),
+                       g_dbus_proxy_get_name (view->priv->web_extension),
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+                       "SourceChanged",
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       (GDBusSignalCallback) source_changed_signal_cb,
+                       view,
+                       NULL);
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT_ALL);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+       view->priv->web_extension_button_clicked_signal_id =
+               g_dbus_connection_signal_subscribe (
+                       g_dbus_proxy_get_connection (view->priv->web_extension),
+                       g_dbus_proxy_get_name (view->priv->web_extension),
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+                       "ButtonClicked",
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       (GDBusSignalCallback) button_clicked_signal_cb,
+                       view,
+                       NULL);
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+       view->priv->web_extension_recur_toggled_signal_id =
+               g_dbus_connection_signal_subscribe (
+                       g_dbus_proxy_get_connection (view->priv->web_extension),
+                       g_dbus_proxy_get_name (view->priv->web_extension),
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+                       "RecurToggled",
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       (GDBusSignalCallback) recur_toggled_signal_cb,
+                       view,
+                       NULL);
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE_ALL);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+       itip_view_create_dom_bindings (view, view->priv->element_id);
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+       itip_view_init_view (view);
+}
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE_ALL);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           const gchar *name_owner,
+                           ItipView *view)
+{
+       g_dbus_proxy_new (
+               connection,
+               G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+               G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+               G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+               NULL,
+               name,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+               NULL,
+               (GAsyncReadyCallback)web_extension_proxy_created_cb,
+               view);
+}
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           ItipView *view)
+{
+       g_clear_object (&view->priv->web_extension);
+}
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE_ATTENDEE_STATUS);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+static void
+itip_view_watch_web_extension (ItipView *view)
+{
+       view->priv->web_extension_watch_name_id =
+               g_bus_watch_name (
+                       G_BUS_TYPE_SESSION,
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_SERVICE_NAME,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       (GBusNameAppearedCallback) web_extension_appeared_cb,
+                       (GBusNameVanishedCallback) web_extension_vanished_cb,
+                       view, NULL);
+}
 
-       el = webkit_dom_document_get_element_by_id (doc, BUTTON_SEND_INFORMATION);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
-       }
+GDBusProxy *
+itip_view_get_web_extension_proxy (ItipView *view)
+{
+       g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
 
-       el = webkit_dom_document_get_element_by_id (doc, SELECT_ESOURCE);
-       if (el) {
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "change",
-                       G_CALLBACK (source_changed_cb), FALSE, view);
-       }
+       return view->priv->web_extension;
 }
 
 static void
 itip_view_init (ItipView *view)
 {
        view->priv = ITIP_VIEW_GET_PRIVATE (view);
-
 }
 
 ItipView *
 itip_view_new (EMailPartItip *puri,
-               EClientCache *client_cache)
+               EClientCache *client_cache,
+               const gchar *element_id,
+               guint64 page_id)
 {
        ItipView *view;
 
@@ -1765,46 +1891,35 @@ itip_view_new (EMailPartItip *puri,
                "client-cache", client_cache,
                NULL));
        view->priv->itip_part = puri;
+       view->priv->element_id = element_id;
+       view->priv->page_id = page_id;
 
+       itip_view_watch_web_extension (view);
        return view;
 }
 
-static void
-show_button (ItipView *view,
-             const gchar *id)
-{
-       WebKitDOMElement *button;
-
-       button = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, id);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (button), FALSE);
-}
-
 void
 itip_view_set_mode (ItipView *view,
                     ItipViewMode mode)
 {
-       WebKitDOMElement *row, *cell;
-       WebKitDOMElement *button;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        view->priv->mode = mode;
 
        set_sender_text (view);
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_BUTTONS);
-       cell = webkit_dom_element_get_first_element_child (row);
-       do {
-               button = webkit_dom_element_get_first_element_child (cell);
-               webkit_dom_html_element_set_hidden (
-                       WEBKIT_DOM_HTML_ELEMENT (button), TRUE);
-       } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "ElementHideChildNodes",
+               g_variant_new ("(s)", TABLE_ROW_BUTTONS),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
        view->priv->is_recur_set = itip_view_get_recur_check_state (view);
 
@@ -1870,12 +1985,9 @@ itip_view_set_item_type (ItipView *view,
 
        view->priv->type = type;
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
-       label = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_ESCB_LABEL);
-
        switch (view->priv->type) {
                case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
                        header = _("_Calendar:");
@@ -1898,10 +2010,17 @@ itip_view_set_item_type (ItipView *view,
 
        html_label = e_mail_formatter_parse_html_mnemonics (header, &access_key);
 
-       webkit_dom_html_element_set_access_key (
-               WEBKIT_DOM_HTML_ELEMENT (label), access_key);
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (label), html_label, NULL);
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "ElementSetAccessKey",
+               g_variant_new ("(ss)", TABLE_ROW_ESCB_LABEL, access_key),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+
+       set_inner_html (view, TABLE_ROW_ESCB_LABEL, html_label);
 
        g_free (html_label);
 
@@ -2055,8 +2174,6 @@ void
 itip_view_set_summary (ItipView *view,
                        const gchar *summary)
 {
-       WebKitDOMElement *row, *col;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        if (view->priv->summary)
@@ -2064,19 +2181,7 @@ itip_view_set_summary (ItipView *view,
 
        view->priv->summary = summary ? g_strstrip (e_utf8_ensure_valid (summary)) : NULL;
 
-       if (!view->priv->dom_document)
-               return;
-
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_SUMMARY);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->summary == NULL));
-
-       col = webkit_dom_element_get_last_element_child (row);
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (col),
-               view->priv->summary ? view->priv->summary : "",
-               NULL);
+       set_area_text (view, TABLE_ROW_SUMMARY, view->priv->summary);
 }
 
 const gchar *
@@ -2091,8 +2196,6 @@ void
 itip_view_set_location (ItipView *view,
                         const gchar *location)
 {
-       WebKitDOMElement *row, *col;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        if (view->priv->location)
@@ -2100,19 +2203,7 @@ itip_view_set_location (ItipView *view,
 
        view->priv->location = location ? g_strstrip (e_utf8_ensure_valid (location)) : NULL;
 
-       if (!view->priv->dom_document)
-               return;
-
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_LOCATION);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->location == NULL));
-
-       col = webkit_dom_element_get_last_element_child (row);
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (col),
-               view->priv->location ? view->priv->location : "",
-               NULL);
+       set_area_text (view, TABLE_ROW_LOCATION, view->priv->location);
 }
 
 const gchar *
@@ -2127,8 +2218,6 @@ void
 itip_view_set_status (ItipView *view,
                       const gchar *status)
 {
-       WebKitDOMElement *row, *col;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        if (view->priv->status)
@@ -2136,19 +2225,7 @@ itip_view_set_status (ItipView *view,
 
        view->priv->status = status ? g_strstrip (e_utf8_ensure_valid (status)) : NULL;
 
-       if (!view->priv->dom_document)
-               return;
-
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_STATUS);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->status == NULL));
-
-       col = webkit_dom_element_get_last_element_child (row);
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (col),
-               view->priv->status ? view->priv->status : "",
-               NULL);
+       set_area_text (view, TABLE_ROW_STATUS, view->priv->status);
 }
 
 const gchar *
@@ -2163,8 +2240,6 @@ void
 itip_view_set_comment (ItipView *view,
                        const gchar *comment)
 {
-       WebKitDOMElement *row, *col;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        if (view->priv->comment)
@@ -2172,19 +2247,7 @@ itip_view_set_comment (ItipView *view,
 
        view->priv->comment = comment ? g_strstrip (e_utf8_ensure_valid (comment)) : NULL;
 
-       if (!view->priv->dom_document)
-               return;
-
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_COMMENT);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->comment == NULL));
-
-       col = webkit_dom_element_get_last_element_child (row);
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (col),
-               view->priv->comment ? view->priv->comment : "",
-               NULL);
+       set_area_text (view, TABLE_ROW_COMMENT, view->priv->comment);
 }
 
 const gchar *
@@ -2199,8 +2262,6 @@ void
 itip_view_set_description (ItipView *view,
                            const gchar *description)
 {
-       WebKitDOMElement *div;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        if (view->priv->description)
@@ -2208,18 +2269,11 @@ itip_view_set_description (ItipView *view,
 
        view->priv->description = description ? g_strstrip (e_utf8_ensure_valid (description)) : NULL;
 
-       if (!view->priv->dom_document)
-               return;
-
-       div = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_DESCRIPTION);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (div), (view->priv->description == NULL));
-
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (div),
-               view->priv->description ? view->priv->description : "",
-               NULL);
+       hide_element (view, TABLE_ROW_DESCRIPTION, (view->priv->description == NULL));
+       set_inner_html (
+               view,
+               TABLE_ROW_DESCRIPTION,
+               view->priv->description ? view->priv->description : "");
 }
 
 const gchar *
@@ -2326,7 +2380,7 @@ itip_view_add_upper_info_item (ItipView *view,
 
        priv->upper_info_items = g_slist_append (priv->upper_info_items, item);
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return item->id;
 
        append_info_item_row (view, TABLE_UPPER_ITIP_INFO, item);
@@ -2376,8 +2430,7 @@ itip_view_remove_upper_info_item (ItipView *view,
                        g_free (item->message);
                        g_free (item);
 
-                       if (!view->priv->dom_document)
-                               remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, id);
+                       remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, id);
 
                        return;
                }
@@ -2397,8 +2450,7 @@ itip_view_clear_upper_info_items (ItipView *view)
        for (l = priv->upper_info_items; l; l = l->next) {
                ItipViewInfoItem *item = l->data;
 
-               if (view->priv->dom_document)
-                       remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, item->id);
+               remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, item->id);
 
                g_free (item->message);
                g_free (item);
@@ -2428,7 +2480,7 @@ itip_view_add_lower_info_item (ItipView *view,
 
        priv->lower_info_items = g_slist_append (priv->lower_info_items, item);
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return item->id;
 
        append_info_item_row (view, TABLE_LOWER_ITIP_INFO, item);
@@ -2514,105 +2566,123 @@ void
 itip_view_set_source (ItipView *view,
                       ESource *source)
 {
-       WebKitDOMElement *select;
-       WebKitDOMElement *row;
        ESource *selected_source;
-       gulong i, len;
 
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        d (printf ("Settings default source '%s'\n", e_source_get_display_name (source)));
 
-       if (!view->priv->dom_document)
-               return;
+       hide_element (view, TABLE_ROW_ESCB, (source == NULL));
 
-       row = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_ESCB);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (row), (source == NULL));
-       if (source == NULL)
+       if (!source)
                return;
 
-       select = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, SELECT_ESOURCE);
-
         /* <select> does not emit 'change' event when already selected
         * <option> is re-selected, but we need to notify itip formatter,
         * so that it would make all the buttons sensitive */
        selected_source = itip_view_ref_source (view);
        if (source == selected_source) {
-               source_changed_cb (select, NULL, view);
+               source_changed (view);
                return;
        }
 
        if (selected_source != NULL)
                g_object_unref (selected_source);
 
-       if (webkit_dom_html_select_element_get_disabled (
-                       WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) {
-               webkit_dom_html_select_element_set_disabled (
-                       WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE);
-       }
-
-       len = webkit_dom_html_select_element_get_length (
-               WEBKIT_DOM_HTML_SELECT_ELEMENT (select));
-       for (i = 0; i < len; i++) {
-
-               WebKitDOMNode *node;
-               WebKitDOMHTMLOptionElement *option;
-               gchar *value;
-
-               node = webkit_dom_html_select_element_item (
-                       WEBKIT_DOM_HTML_SELECT_ELEMENT (select), i);
-               option = WEBKIT_DOM_HTML_OPTION_ELEMENT (node);
-
-               value = webkit_dom_html_option_element_get_value (option);
-               if (g_strcmp0 (value, e_source_get_uid (source)) == 0) {
-                       webkit_dom_html_option_element_set_selected (
-                               option, TRUE);
+       if (!view->priv->web_extension)
+               return;
 
-                       g_free (value);
-                       break;
-               }
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "EnableSelect",
+               g_variant_new ("(sb)", SELECT_ESOURCE, TRUE),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
-               g_free (value);
-       }
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "SelectSetSelected",
+               g_variant_new (
+                       "(ss)",
+                       SELECT_ESOURCE, e_source_get_uid (source)),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
-       source_changed_cb (select, NULL, view);
+       source_changed (view);
 }
 
 ESource *
 itip_view_ref_source (ItipView *view)
 {
-       WebKitDOMElement *select;
-       gchar *uid;
        ESource *source;
-       gboolean disable = FALSE;
+       gboolean disable = FALSE, enabled = FALSE;
 
        g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return NULL;
 
-       select = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, SELECT_ESOURCE);
-       if (webkit_dom_html_select_element_get_disabled (
-                       WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) {
-               webkit_dom_html_select_element_set_disabled (
-               WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE);
+       result = g_dbus_proxy_call_sync (
+                       view->priv->web_extension,
+                       "SelectIsEnabled",
+                       g_variant_new ("(s)", SELECT_ESOURCE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL);
+
+       if (result) {
+               g_variant_get (result, "(b)", &enabled);
+               g_variant_unref (result);
+       }
+
+       if (enabled) {
+               g_dbus_proxy_call (
+                       view->priv->web_extension,
+                       "EnableSelect",
+                       g_variant_new ("(sb)", SELECT_ESOURCE, TRUE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
+
                disable = TRUE;
        }
 
-       uid = webkit_dom_html_select_element_get_value (
-               WEBKIT_DOM_HTML_SELECT_ELEMENT (select));
+       result = g_dbus_proxy_call_sync (
+                       view->priv->web_extension,
+                       "SelectGetValue",
+                       g_variant_new ("(s)", SELECT_ESOURCE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL);
 
-       source = e_source_registry_ref_source (view->priv->registry, uid);
+       if (result) {
+               const gchar *uid;
 
-       g_free (uid);
+               g_variant_get (result, "(&s)", &uid);
+               source = e_source_registry_ref_source (view->priv->registry, uid);
+               g_variant_unref (result);
+       }
 
        if (disable) {
-               webkit_dom_html_select_element_set_disabled (
-                       WEBKIT_DOM_HTML_SELECT_ELEMENT (select), TRUE);
+               g_dbus_proxy_call (
+                       view->priv->web_extension,
+                       "EnableSelect",
+                       g_variant_new ("(sb)", SELECT_ESOURCE, FALSE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
        }
 
        return source;
@@ -2622,201 +2692,139 @@ void
 itip_view_set_rsvp (ItipView *view,
                     gboolean rsvp)
 {
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RSVP);
-       webkit_dom_html_input_element_set_checked (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), rsvp);
+       input_set_checked (view, CHECKBOX_RSVP, rsvp);
 
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
-       webkit_dom_html_text_area_element_set_disabled (
-               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp);
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "EnableTextArea",
+               g_variant_new ("(sb)", TEXTAREA_RSVP_COMMENT, !rsvp),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 }
 
 gboolean
 itip_view_get_rsvp (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RSVP);
-       return webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
+       return input_is_checked (view, CHECKBOX_RSVP);
 }
 
 void
 itip_view_set_show_rsvp_check (ItipView *view,
                                gboolean show)
 {
-       WebKitDOMElement *label;
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, "table_row_" CHECKBOX_RSVP);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RSVP);
-       label = webkit_dom_element_get_next_element_sibling (el);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
-
-       if (!show) {
-               webkit_dom_html_input_element_set_checked (
-                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
-       }
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_RSVP_COMMENT);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
+       show_checkbox (view, CHECKBOX_RSVP, show, FALSE);
+       hide_element (view, TABLE_ROW_RSVP_COMMENT, !show);
 }
 
 gboolean
 itip_view_get_show_rsvp_check (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RSVP);
-       return !webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el));
+       return !element_is_hidden (view, CHECKBOX_RSVP);
 }
 
 void
 itip_view_set_update (ItipView *view,
                       gboolean update)
 {
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_UPDATE);
-
-       webkit_dom_html_input_element_set_checked (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), update);
+       input_set_checked (view, CHECKBOX_UPDATE, update);
 }
 
 gboolean
 itip_view_get_update (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_UPDATE);
-       return webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
+       return input_is_checked (view, CHECKBOX_UPDATE);
 }
 
 void
 itip_view_set_show_update_check (ItipView *view,
                                  gboolean show)
 {
-       WebKitDOMElement *label;
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, "table_row_" CHECKBOX_UPDATE);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_UPDATE);
-       label = webkit_dom_element_get_next_element_sibling (el);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
-
-       if (!show) {
-               webkit_dom_html_input_element_set_checked (
-                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
-       }
+       show_checkbox (view, CHECKBOX_UPDATE, show, FALSE);
 }
 
 gboolean
 itip_view_get_show_update_check (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_UPDATE);
-       return !webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el));
+       return !element_is_hidden (view, CHECKBOX_UPDATE);
 }
 
 void
 itip_view_set_rsvp_comment (ItipView *view,
                             const gchar *comment)
 {
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (el), (comment == NULL));
-
        if (comment) {
-               webkit_dom_html_text_area_element_set_value (
-                       WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), comment);
+               g_dbus_proxy_call (
+                       view->priv->web_extension,
+                       "TextAreaSetValue",
+                       g_variant_new (
+                               "(ss)", TEXTAREA_RSVP_COMMENT, comment),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
        }
 }
 
 gchar *
 itip_view_get_rsvp_comment (ItipView *view)
 {
-       WebKitDOMElement *el;
+       GVariant *result;
 
        g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return NULL;
 
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
+       if (element_is_hidden (view, TEXTAREA_RSVP_COMMENT))
+               return NULL;
 
-       if (webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el))) {
-               return NULL;
-       }
+       result = g_dbus_proxy_call_sync (
+                       view->priv->web_extension,
+                       "TextAreaGetValue",
+                       g_variant_new (
+                               "(s)", TEXTAREA_RSVP_COMMENT),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL);
+
+       if (result) {
+               const gchar *value;
+
+               g_variant_get (result, "(&s)", &value);
+               g_variant_unref (result);
+               return value;
+       }
 
-       return webkit_dom_html_text_area_element_get_value (
-               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el));
+       return NULL;
 }
 
 void
@@ -2832,64 +2840,24 @@ void
 itip_view_set_buttons_sensitive (ItipView *view,
                                  gboolean sensitive)
 {
-       WebKitDOMElement *el, *cell;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
        d (printf ("Settings buttons %s\n", sensitive ? "sensitive" : "insensitive"));
 
        view->priv->buttons_sensitive = sensitive;
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_UPDATE);
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RECUR);
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_FREE_TIME);
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_KEEP_ALARM);
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RSVP);
-       webkit_dom_html_input_element_set_disabled (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
-       webkit_dom_html_text_area_element_set_disabled (
-               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !sensitive);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, TABLE_ROW_BUTTONS);
-       cell = webkit_dom_element_get_first_element_child (el);
-       do {
-               WebKitDOMElement *btn;
-               btn = webkit_dom_element_get_first_element_child (cell);
-               if (!webkit_dom_html_element_get_hidden (
-                       WEBKIT_DOM_HTML_ELEMENT (btn))) {
-                       webkit_dom_html_button_element_set_disabled (
-                               WEBKIT_DOM_HTML_BUTTON_ELEMENT (btn), !sensitive);
-               }
-       } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
+       g_dbus_proxy_call (
+               view->priv->web_extension,
+               "SetButtonsSensitive",
+               g_variant_new ("(b)", sensitive),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 }
 
 gboolean
@@ -2903,193 +2871,69 @@ itip_view_get_buttons_sensitive (ItipView *view)
 gboolean
 itip_view_get_recur_check_state (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RECUR);
-       return webkit_dom_html_input_element_get_checked (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
+       return input_is_checked (view, CHECKBOX_RECUR);
 }
 
 void
 itip_view_set_show_recur_check (ItipView *view,
                                 gboolean show)
 {
-       WebKitDOMElement *label;
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, "table_row_" CHECKBOX_RECUR);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_RECUR);
-       label = webkit_dom_element_get_next_element_sibling (el);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
-
-       if (!show) {
-               webkit_dom_html_input_element_set_checked (
-                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
-       }
-
-        /* and update state of the second check */
-       alarm_check_toggled_cb (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
-               NULL, view);
+       show_checkbox (view, CHECKBOX_RECUR, show, TRUE);
 }
 
 void
 itip_view_set_show_free_time_check (ItipView *view,
                                     gboolean show)
 {
-       WebKitDOMElement *label;
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, "table_row_" CHECKBOX_FREE_TIME);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_FREE_TIME);
-       label = webkit_dom_element_get_next_element_sibling (el);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
-
-       if (!show) {
-               webkit_dom_html_input_element_set_checked (
-                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
-       }
-
-        /* and update state of the second check */
-       alarm_check_toggled_cb (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
-               NULL, view);
+       show_checkbox (view, CHECKBOX_FREE_TIME, show, TRUE);
 }
 
 gboolean
 itip_view_get_free_time_check_state (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_FREE_TIME);
-       return webkit_dom_html_input_element_get_checked (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
+       return input_is_checked (view, CHECKBOX_FREE_TIME);
 }
 
 void
 itip_view_set_show_keep_alarm_check (ItipView *view,
                                      gboolean show)
 {
-       WebKitDOMElement *label;
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, "table_row_" CHECKBOX_KEEP_ALARM);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_KEEP_ALARM);
-       label = webkit_dom_element_get_next_element_sibling (el);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
-
-       if (!show) {
-               webkit_dom_html_input_element_set_checked (
-                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
-       }
-
-        /* and update state of the second check */
-       alarm_check_toggled_cb (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
-               NULL, view);
+       show_checkbox (view, CHECKBOX_KEEP_ALARM, show, TRUE);
 }
 
 gboolean
 itip_view_get_keep_alarm_check_state (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_KEEP_ALARM);
-       return webkit_dom_html_input_element_get_checked (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
+       return input_is_checked (view, CHECKBOX_KEEP_ALARM);
 }
 
 void
 itip_view_set_show_inherit_alarm_check (ItipView *view,
                                         gboolean show)
 {
-       WebKitDOMElement *label;
-       WebKitDOMElement *el;
-
        g_return_if_fail (ITIP_IS_VIEW (view));
 
-       if (!view->priv->dom_document)
-               return;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, "table_row_" CHECKBOX_INHERIT_ALARM);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
-       label = webkit_dom_element_get_next_element_sibling (el);
-       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
-
-       if (!show) {
-               webkit_dom_html_input_element_set_checked (
-                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
-       }
-
-       /* and update state of the second check */
-       alarm_check_toggled_cb (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
-               NULL, view);
+       show_checkbox (view, CHECKBOX_INHERIT_ALARM, show, TRUE);
 }
 
 gboolean
 itip_view_get_inherit_alarm_check_state (ItipView *view)
 {
-       WebKitDOMElement *el;
-
        g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
 
-       if (!view->priv->dom_document)
-               return FALSE;
-
-       el = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
-       return webkit_dom_html_input_element_get_checked (
-               WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
+       return input_is_checked (view, CHECKBOX_INHERIT_ALARM);
 }
 
 void
@@ -3097,7 +2941,6 @@ itip_view_set_error (ItipView *view,
                      const gchar *error_html,
                      gboolean show_save_btn)
 {
-       WebKitDOMElement *content, *error;
        GString *str;
 
        g_return_if_fail (ITIP_IS_VIEW (view));
@@ -3121,34 +2964,26 @@ itip_view_set_error (ItipView *view,
        view->priv->error = str->str;
        g_string_free (str, FALSE);
 
-       if (!view->priv->dom_document)
+       if (!view->priv->web_extension)
                return;
 
-       content = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, DIV_ITIP_CONTENT);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (content), TRUE);
-
-       error = webkit_dom_document_get_element_by_id (
-               view->priv->dom_document, DIV_ITIP_ERROR);
-       webkit_dom_html_element_set_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (error), FALSE);
-
-       webkit_dom_html_element_set_inner_html (
-               WEBKIT_DOM_HTML_ELEMENT (error), view->priv->error, NULL);
+       hide_element (view, DIV_ITIP_CONTENT, TRUE);
+       hide_element (view, DIV_ITIP_ERROR, FALSE);
+       set_inner_html (view, DIV_ITIP_ERROR, view->priv->error);
 
        if (show_save_btn) {
-               WebKitDOMElement *el;
-
-               show_button (view, BUTTON_SAVE);
+               show_button (view, BUTTON_SAVE);
+               enable_button (view, BUTTON_SAVE, TRUE);
 
-               el = webkit_dom_document_get_element_by_id (
-                       view->priv->dom_document, BUTTON_SAVE);
-               webkit_dom_html_button_element_set_disabled (
-                       WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), FALSE);
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (el), "click",
-                       G_CALLBACK (button_clicked_cb), FALSE, view);
+               g_dbus_proxy_call (
+                       view->priv->web_extension,
+                       "BindSaveButton",
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       NULL,
+                       NULL);
        }
 }
 
@@ -3574,14 +3409,7 @@ set_buttons_sensitive (EMailPartItip *pitip,
                        view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
                        _("Attendee status updated"));
 
-               if (view->priv->dom_document) {
-                       WebKitDOMElement *el;
-
-                       el = webkit_dom_document_get_element_by_id (
-                               view->priv->dom_document, BUTTON_UPDATE_ATTENDEE_STATUS);
-                       webkit_dom_html_button_element_set_disabled (
-                               WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), TRUE);
-               }
+               enable_button (view, BUTTON_UPDATE_ATTENDEE_STATUS, FALSE);
        }
 }
 
@@ -4550,7 +4378,7 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
                icalproperty *prop;
                icalvalue *value;
                const gchar *attendee;
-               gchar *comment;
+               const gchar *comment;
                GSList *l, *list = NULL;
                gboolean found;
 
@@ -4609,8 +4437,6 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
                        comments.next = NULL;
 
                        e_cal_component_set_comment_list (comp, &comments);
-
-                       g_free (comment);
                }
 
                e_cal_component_rescan (comp);
@@ -5021,14 +4847,7 @@ modify_object_cb (GObject *ecalclient,
                        view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
                        _("Attendee status updated"));
 
-               if (view->priv->dom_document) {
-                       WebKitDOMElement *el;
-
-                       el = webkit_dom_document_get_element_by_id (
-                               view->priv->dom_document, BUTTON_UPDATE_ATTENDEE_STATUS);
-                       webkit_dom_html_button_element_set_disabled (
-                               WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), TRUE);
-               }
+               enable_button (view, BUTTON_UPDATE_ATTENDEE_STATUS, FALSE);
 
                if (pitip->delete_message && pitip->folder)
                        camel_folder_delete_message (pitip->folder, pitip->uid);
@@ -6262,13 +6081,8 @@ itip_view_init_view (ItipView *view)
                        find_server (info, view, info->comp);
                        set_buttons_sensitive (info, view);
                }
-       } else if (view->priv->dom_document) {
+       } else if (view->priv->web_extension) {
                /* The Open Calendar button can be shown, thus enable it */
-               WebKitDOMElement *el;
-
-               el = webkit_dom_document_get_element_by_id (
-                       view->priv->dom_document, BUTTON_OPEN_CALENDAR);
-               webkit_dom_html_button_element_set_disabled (
-                       WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), FALSE);
+               enable_button (view, BUTTON_OPEN_CALENDAR, TRUE);
        }
 }
diff --git a/modules/itip-formatter/itip-view.h b/modules/itip-formatter/itip-view.h
index 0ffd96f..97ecdfd 100644
--- a/modules/itip-formatter/itip-view.h
+++ b/modules/itip-formatter/itip-view.h
@@ -27,7 +27,6 @@
 #include <unistd.h>
 
 #include <gtk/gtk.h>
-#include <webkit/webkitdom.h>
 
 #include <libecal/libecal.h>
 
@@ -110,14 +109,16 @@ struct _ItipViewClass {
 
 GType          itip_view_get_type              (void);
 ItipView *     itip_view_new                   (struct _EMailPartItip *puri,
-                                                EClientCache *client_cache);
+                                                EClientCache *client_cache,
+                                                const gchar *element_id,
+                                                guint64 page_id);
 void           itip_view_init_view             (ItipView *view);
 void           itip_view_write                 (EMailFormatter *formatter,
                                                 GString *buffer);
 void           itip_view_write_for_printing    (ItipView *view,
                                                 GString *buffer);
 void           itip_view_create_dom_bindings   (ItipView *view,
-                                                WebKitDOMElement *element);
+                                                const gchar *element_id);
 struct _EMailPartItip *
                itip_view_get_mail_part         (ItipView *view);
 EClientCache * itip_view_get_client_cache      (ItipView *view);
@@ -217,7 +218,7 @@ void                itip_view_set_update            (ItipView *view,
 gboolean       itip_view_get_show_update_check (ItipView *view);
 void           itip_view_set_show_update_check (ItipView *view,
                                                 gboolean show);
-gchar *                itip_view_get_rsvp_comment      (ItipView *view);
+const gchar *  itip_view_get_rsvp_comment      (ItipView *view);
 void           itip_view_set_rsvp_comment      (ItipView *view,
                                                 const gchar *comment);
 gboolean       itip_view_get_buttons_sensitive (ItipView *view);
@@ -246,6 +247,8 @@ void                itip_view_set_show_inherit_alarm_check
 void           itip_view_set_error             (ItipView *view,
                                                 const gchar *error_html,
                                                 gboolean show_save_btn);
+GDBusProxy *   itip_view_get_web_extension_proxy
+                                               (ItipView *view);
 
 G_END_DECLS
 
diff --git a/modules/itip-formatter/module-itip-formatter-dom-utils.c 
b/modules/itip-formatter/module-itip-formatter-dom-utils.c
new file mode 100644
index 0000000..0f71a7a
--- /dev/null
+++ b/modules/itip-formatter/module-itip-formatter-dom-utils.c
@@ -0,0 +1,723 @@
+/*
+ * module-itip-formatter-dom-utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "module-itip-formatter-dom-utils.h"
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+
+#include "web-extension/module-itip-formatter-web-extension.h"
+#include "itip-view-elements-defines.h"
+
+#include <e-util/e-util.h>
+
+void
+module_itip_formatter_dom_utils_show_button (WebKitDOMDocument *document,
+                                             const gchar *button_id)
+{
+       WebKitDOMElement *button;
+
+       button = webkit_dom_document_get_element_by_id (document, button_id);
+       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (button), FALSE);
+}
+
+void
+module_itip_formatter_dom_utils_enable_button (WebKitDOMDocument *document,
+                                               const gchar *button_id,
+                                               gboolean enable)
+{
+       WebKitDOMElement *el;
+
+       el = webkit_dom_document_get_element_by_id (document, button_id);
+       webkit_dom_html_button_element_set_disabled (
+               WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), !enable);
+}
+
+static void
+recur_toggled_cb (WebKitDOMHTMLInputElement *input,
+                  WebKitDOMEvent *event,
+                  GDBusConnection *connection)
+{
+       GError *error = NULL;
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+               "RecurToggled",
+               NULL,
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal RecurToggled: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+source_changed_cb (WebKitDOMElement *element,
+                   WebKitDOMEvent *event,
+                   GDBusConnection *connection)
+{
+       GError *error = NULL;
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+               "SourceChanged",
+               NULL,
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal SourceChanged: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+button_clicked_cb (WebKitDOMElement *element,
+                   WebKitDOMEvent *event,
+                   GDBusConnection *connection)
+{
+       GError *error = NULL;
+       gchar *button_value;
+
+       button_value = webkit_dom_html_button_element_get_value (
+               WEBKIT_DOM_HTML_BUTTON_ELEMENT (element));
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+               "ButtonClicked",
+               g_variant_new ("(s)", button_value),
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal ButtonClicked: %s\n", error->message);
+               g_error_free (error);
+       }
+
+       g_free (button_value);
+}
+
+static void
+rsvp_toggled_cb (WebKitDOMHTMLInputElement *input,
+                 WebKitDOMEvent *event,
+                 GDBusConnection *connection)
+{
+       WebKitDOMElement *el;
+       WebKitDOMDocument *document;
+       gboolean rsvp;
+
+               document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (input));
+       rsvp = webkit_dom_html_input_element_get_checked (input);
+       el = webkit_dom_document_get_element_by_id (
+               document, TEXTAREA_RSVP_COMMENT);
+       webkit_dom_html_text_area_element_set_disabled (
+               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp);
+}
+
+/**
+  alarm_check_toggled_cb
+  check1 was changed, so make the second available based on state of the first check.
+*/
+static void
+alarm_check_toggled_cb (WebKitDOMHTMLInputElement *check1,
+                        WebKitDOMEvent *event,
+                        GDBusConnection *connection)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *check2;
+       gchar *id;
+
+               document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (check1));
+#if WEBKIT_CHECK_VERSION(2,2,0) /* XXX should really be (2,1,something) */
+       id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (check1));
+#else
+       id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (check1));
+#endif
+
+       if (g_strcmp0 (id, CHECKBOX_INHERIT_ALARM)) {
+               check2 = webkit_dom_document_get_element_by_id (
+                       document, CHECKBOX_KEEP_ALARM);
+       } else {
+               check2 = webkit_dom_document_get_element_by_id (
+                       document, CHECKBOX_INHERIT_ALARM);
+       }
+
+       g_free (id);
+
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (check2),
+               (webkit_dom_html_element_get_hidden (
+                               WEBKIT_DOM_HTML_ELEMENT (check1)) &&
+                       webkit_dom_html_input_element_get_checked (check1)));
+}
+
+void
+module_itip_formatter_dom_utils_create_dom_bindings (WebKitDOMDocument *document,
+                                                     GDBusConnection *connection)
+{
+       WebKitDOMElement *el;
+
+       el = webkit_dom_document_get_element_by_id (document, CHECKBOX_RECUR);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (recur_toggled_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, CHECKBOX_RSVP);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (rsvp_toggled_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, CHECKBOX_INHERIT_ALARM);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (alarm_check_toggled_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, CHECKBOX_KEEP_ALARM);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (alarm_check_toggled_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_OPEN_CALENDAR);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_ACCEPT);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_ACCEPT_ALL);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_TENTATIVE);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_TENTATIVE_ALL);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_DECLINE);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_DECLINE_ALL);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_UPDATE);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_UPDATE_ATTENDEE_STATUS);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_SEND_INFORMATION);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+
+       el = webkit_dom_document_get_element_by_id (document, SELECT_ESOURCE);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "change",
+                       G_CALLBACK (source_changed_cb), FALSE, connection);
+       }
+}
+
+void
+module_itip_formatter_dom_utils_bind_save_button (WebKitDOMDocument *document,
+                                                  GDBusConnection *connection)
+{
+       WebKitDOMElement *el;
+
+       el = webkit_dom_document_get_element_by_id (document, BUTTON_SAVE);
+       if (el) {
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (el), "click",
+                       G_CALLBACK (button_clicked_cb), FALSE, connection);
+       }
+}
+
+gboolean
+module_itip_formatter_dom_utils_input_is_checked (WebKitDOMDocument *document,
+                                                  const gchar *input_id)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, input_id);
+
+       if (!element)
+               return FALSE;
+
+       return webkit_dom_html_input_element_get_checked (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (element));
+}
+
+void
+module_itip_formatter_dom_utils_input_set_checked (WebKitDOMDocument *document,
+                                                   const gchar *input_id,
+                                                   gboolean checked)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, input_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_input_element_set_checked (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (element), checked);
+}
+
+void
+module_itip_formatter_dom_utils_show_checkbox (WebKitDOMDocument *document,
+                                               const gchar *id,
+                                               gboolean show,
+                                              gboolean update_second)
+{
+       WebKitDOMElement *label;
+       WebKitDOMElement *el;
+       gchar *row_id;
+
+       el = webkit_dom_document_get_element_by_id (document, id);
+       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
+
+       label = webkit_dom_element_get_next_element_sibling (el);
+       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
+
+       if (!show) {
+               webkit_dom_html_input_element_set_checked (
+                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
+       }
+
+       if (update_second) {
+               /* and update state of the second check */
+               alarm_check_toggled_cb (
+                       WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
+                       NULL, NULL);
+       }
+
+       row_id = g_strconcat ("table_row_", id, NULL);
+       el = webkit_dom_document_get_element_by_id (document, row_id);
+       webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
+       g_free (row_id);
+}
+
+void
+module_itip_formatter_dom_utils_set_buttons_sensitive (WebKitDOMDocument *document,
+                                                       gboolean sensitive)
+{
+       WebKitDOMElement *el, *cell;
+
+       el = webkit_dom_document_get_element_by_id (
+               document, CHECKBOX_UPDATE);
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, CHECKBOX_RECUR);
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, CHECKBOX_FREE_TIME);
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, CHECKBOX_KEEP_ALARM);
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, CHECKBOX_INHERIT_ALARM);
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, CHECKBOX_RSVP);
+       webkit_dom_html_input_element_set_disabled (
+               WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, TEXTAREA_RSVP_COMMENT);
+       webkit_dom_html_text_area_element_set_disabled (
+               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !sensitive);
+
+       el = webkit_dom_document_get_element_by_id (
+               document, TABLE_ROW_BUTTONS);
+       cell = webkit_dom_element_get_first_element_child (el);
+       do {
+               WebKitDOMElement *btn;
+               btn = webkit_dom_element_get_first_element_child (cell);
+               if (!webkit_dom_html_element_get_hidden (
+                       WEBKIT_DOM_HTML_ELEMENT (btn))) {
+                       webkit_dom_html_button_element_set_disabled (
+                               WEBKIT_DOM_HTML_BUTTON_ELEMENT (btn), !sensitive);
+               }
+       } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
+}
+
+void
+module_itip_formatter_dom_utils_set_area_text (WebKitDOMDocument *document,
+                                               const gchar *area_id,
+                                               const gchar *text)
+{
+       WebKitDOMElement *row, *col;
+
+       row = webkit_dom_document_get_element_by_id (document, area_id);
+       webkit_dom_html_element_set_hidden (
+               WEBKIT_DOM_HTML_ELEMENT (row), (g_strcmp0 (text, "") == 0));
+
+       col = webkit_dom_element_get_last_element_child (row);
+       webkit_dom_html_element_set_inner_html (
+               WEBKIT_DOM_HTML_ELEMENT (col),
+               text,
+               NULL);
+}
+
+void
+module_itip_formatter_dom_utils_element_set_access_key (WebKitDOMDocument *document,
+                                                        const gchar *element_id,
+                                                        const gchar *access_key)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_element_set_access_key (
+               WEBKIT_DOM_HTML_ELEMENT (element), access_key);
+}
+
+void
+module_itip_formatter_dom_utils_element_hide_child_nodes (WebKitDOMDocument *document,
+                                                          const gchar *element_id)
+{
+       WebKitDOMElement *element, *cell, *button;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+       cell = webkit_dom_element_get_first_element_child (element);
+       do {
+               button = webkit_dom_element_get_first_element_child (cell);
+               webkit_dom_html_element_set_hidden (
+                       WEBKIT_DOM_HTML_ELEMENT (button), TRUE);
+       } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
+}
+
+void
+module_itip_formatter_dom_utils_enable_select (WebKitDOMDocument *document,
+                                               const gchar *select_id,
+                                               gboolean enabled)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, select_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_select_element_set_disabled (
+               WEBKIT_DOM_HTML_SELECT_ELEMENT (element), !enabled);
+}
+
+gboolean
+module_itip_formatter_dom_utils_select_is_enabled (WebKitDOMDocument *document,
+                                                   const gchar *select_id)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, select_id);
+
+       if (!element)
+               return FALSE;
+
+       return !webkit_dom_html_select_element_get_disabled (
+               WEBKIT_DOM_HTML_SELECT_ELEMENT (element));
+}
+
+gchar *
+module_itip_formatter_dom_utils_select_get_value (WebKitDOMDocument *document,
+                                                  const gchar *select_id)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_get_element_by_id (document, select_id);
+
+       if (!element)
+               return NULL;
+
+       return webkit_dom_html_select_element_get_value (
+               WEBKIT_DOM_HTML_SELECT_ELEMENT (element));
+}
+
+void
+module_itip_formatter_dom_utils_select_set_selected (WebKitDOMDocument *document,
+                                                     const gchar *select_id,
+                                                     const gchar *option)
+{
+       WebKitDOMElement *element;
+       gint length, ii;
+
+       element = webkit_dom_document_get_element_by_id (document, select_id);
+
+       if (!element)
+               return;
+
+       length = webkit_dom_html_select_element_get_length (
+               WEBKIT_DOM_HTML_SELECT_ELEMENT (select));
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+               WebKitDOMHTMLOptionElement *option_element;
+               gchar *value;
+
+               node = webkit_dom_html_select_element_item (
+                       WEBKIT_DOM_HTML_SELECT_ELEMENT (select), ii);
+               option_element = WEBKIT_DOM_HTML_OPTION_ELEMENT (node);
+
+               value = webkit_dom_html_option_element_get_value (option_element);
+               if (g_strcmp0 (value, option) == 0) {
+                       webkit_dom_html_option_element_set_selected (
+                               option_element, TRUE);
+
+                       g_free (value);
+                       break;
+               }
+
+               g_free (value);
+       }
+}
+
+void
+module_itip_formatter_dom_utils_update_times (WebKitDOMDocument *document,
+                                              const gchar *element_id,
+                                              const gchar *header,
+                                              const gchar *label)
+{
+       WebKitDOMElement *element, *col;
+
+       element = webkit_dom_document_get_element_by_id (document, element_id);
+
+       if (!element)
+               return;
+
+       webkit_dom_html_element_set_hidden (
+               WEBKIT_DOM_HTML_ELEMENT (element), FALSE);
+
+       col = webkit_dom_element_get_first_element_child (element);
+       webkit_dom_html_element_set_inner_html (
+               WEBKIT_DOM_HTML_ELEMENT (col), header, NULL);
+
+       col = webkit_dom_element_get_last_element_child (element);
+       webkit_dom_html_element_set_inner_html (
+               WEBKIT_DOM_HTML_ELEMENT (col), label, NULL);
+}
+
+void
+module_itip_formatter_dom_utils_append_info_item_row (WebKitDOMDocument *document,
+                                                      const gchar *table_id,
+                                                      const gchar *row_id,
+                                                      const gchar *icon_name,
+                                                      const gchar *message)
+{
+       WebKitDOMElement *table;
+        WebKitDOMHTMLElement *cell, *row;
+
+       table = webkit_dom_document_get_element_by_id (document, table_id);
+
+       if (!table)
+               return;
+
+       table = webkit_dom_document_get_element_by_id (document, table_id);
+       row = webkit_dom_html_table_element_insert_row (
+               WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
+
+#if WEBKIT_CHECK_VERSION(2,2,0) /* XXX should really be (2,1,something) */
+       webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (row), row_id);
+#else
+       webkit_dom_html_element_set_id (row, row_id);
+#endif
+
+       cell = webkit_dom_html_table_row_element_insert_cell (
+               WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+
+       if (icon_name) {
+               WebKitDOMElement *image;
+               gchar *icon_uri;
+
+               image = webkit_dom_document_create_element (
+                       document, "IMG", NULL);
+
+               icon_uri = g_strdup_printf ("gtk-stock://%s", icon_name);
+               webkit_dom_html_image_element_set_src (
+                       WEBKIT_DOM_HTML_IMAGE_ELEMENT (image), icon_uri);
+               g_free (icon_uri);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (cell),
+                       WEBKIT_DOM_NODE (image),
+                       NULL);
+       }
+
+       cell = webkit_dom_html_table_row_element_insert_cell (
+               WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+
+       webkit_dom_html_element_set_inner_html (cell, message, NULL);
+}
+
+void
+module_itip_formatter_dom_utils_enable_text_area (WebKitDOMDocument *document,
+                                                  const gchar *area_id,
+                                                  gboolean enable)
+{
+       WebKitDOMElement *el;
+
+       el = webkit_dom_document_get_element_by_id (document, area_id);
+       webkit_dom_html_text_area_element_set_disabled (
+               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !enable);
+}
+
+void
+module_itip_formatter_dom_utils_text_area_set_value (WebKitDOMDocument *document,
+                                                     const gchar *area_id,
+                                                     const gchar *value)
+{
+       WebKitDOMElement *el;
+
+       el = webkit_dom_document_get_element_by_id (document, area_id);
+       webkit_dom_html_text_area_element_set_value (
+               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), value);
+}
+
+gchar *
+module_itip_formatter_dom_utils_text_area_get_value (WebKitDOMDocument *document,
+                                                     const gchar *area_id)
+{
+       WebKitDOMElement *el;
+
+       el = webkit_dom_document_get_element_by_id (document, area_id);
+       return webkit_dom_html_text_area_element_get_value (
+               WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el));
+}
+
+void
+module_itip_formatter_dom_utils_rebuild_source_list (WebKitDOMDocument *document,
+                                                     const gchar *optgroup_id,
+                                                     const gchar *optgroup_label,
+                                                     const gchar *option_id,
+                                                     const gchar *option_label,
+                                                    gboolean writable)
+{
+       WebKitDOMElement *option;
+       WebKitDOMElement *select;
+       WebKitDOMHTMLOptGroupElement *optgroup;
+
+       select = webkit_dom_document_get_element_by_id (document, SELECT_ESOURCE);
+
+       if (!select)
+               return;
+
+       optgroup = WEBKIT_DOM_HTML_OPT_GROUP_ELEMENT (
+                       webkit_dom_document_get_element_by_id (
+                               document, optgroup_id));
+
+       if (!optgroup) {
+               optgroup = WEBKIT_DOM_HTML_OPT_GROUP_ELEMENT (
+                               webkit_dom_document_create_element (
+                                       document, "OPTGROUP", NULL));
+               webkit_dom_html_opt_group_element_set_label (
+                       optgroup, optgroup_label);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (select), WEBKIT_DOM_NODE (optgroup), NULL);
+       }
+
+       option = webkit_dom_document_create_element (document, "OPTION", NULL);
+       webkit_dom_html_option_element_set_value (
+               WEBKIT_DOM_HTML_OPTION_ELEMENT (option), option_id);
+       webkit_dom_html_option_element_set_label (
+               WEBKIT_DOM_HTML_OPTION_ELEMENT (option), option_label);
+       webkit_dom_html_element_set_inner_html (
+               WEBKIT_DOM_HTML_ELEMENT (option), option_label, NULL);
+
+       webkit_dom_element_set_class_name (
+               WEBKIT_DOM_ELEMENT (option), "calendar");
+
+       if (!writable) {
+               webkit_dom_html_option_element_set_disabled (
+                       WEBKIT_DOM_HTML_OPTION_ELEMENT (option), TRUE);
+       }
+
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (optgroup),
+               WEBKIT_DOM_NODE (option),
+               NULL);
+}
diff --git a/modules/itip-formatter/module-itip-formatter-dom-utils.h 
b/modules/itip-formatter/module-itip-formatter-dom-utils.h
new file mode 100644
index 0000000..b34e2d2
--- /dev/null
+++ b/modules/itip-formatter/module-itip-formatter-dom-utils.h
@@ -0,0 +1,112 @@
+/*
+ * module-itip-formatter-dom-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef MODULE_ITIP_FORMATTER_DOM_UTILS_H
+#define MODULE_ITIP_FORMATTER_DOM_UTILS_H
+
+#include <webkitdom/webkitdom.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void           module_itip_formatter_dom_utils_show_button
+                                               (WebKitDOMDocument *document,
+                                                const gchar *button_id);
+void           module_itip_formatter_dom_utils_enable_button
+                                               (WebKitDOMDocument *document,
+                                                const gchar *button_id,
+                                                gboolean enable);
+void           module_itip_formatter_dom_utils_create_dom_bindings
+                                               (WebKitDOMDocument *document,
+                                                GDBusConnection *connection);
+void           module_itip_formatter_dom_utils_bind_save_button
+                                               (WebKitDOMDocument *document,
+                                                 GDBusConnection *connection);
+void           module_itip_formatter_dom_utils_input_set_checked
+                                               (WebKitDOMDocument *document,
+                                                const gchar *input_id,
+                                                gboolean checked);
+gboolean       module_itip_formatter_dom_utils_input_is_checked
+                                               (WebKitDOMDocument *document,
+                                                const gchar *input_id);
+void           module_itip_formatter_dom_utils_show_checkbox
+                                               (WebKitDOMDocument *document,
+                                                const gchar *id,
+                                                gboolean show,
+                                                gboolean update_second);
+void           module_itip_formatter_dom_utils_set_buttons_sensitive
+                                               (WebKitDOMDocument *document,
+                                                gboolean sensitive);
+void           module_itip_formatter_dom_utils_set_area_text
+                                               (WebKitDOMDocument *document,
+                                                const gchar *area_id,
+                                                const gchar *text);
+void           module_itip_formatter_dom_utils_element_set_access_key
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id,
+                                                const gchar *access_key);
+void           module_itip_formatter_dom_utils_element_hide_child_nodes
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id);
+void           module_itip_formatter_dom_utils_enable_select
+                                               (WebKitDOMDocument *document,
+                                                const gchar *select_id,
+                                                gboolean enabled);
+gboolean       module_itip_formatter_dom_utils_select_is_enabled
+                                               (WebKitDOMDocument *document,
+                                                const gchar *select_id);
+gchar *                module_itip_formatter_dom_utils_select_get_value
+                                               (WebKitDOMDocument *document,
+                                                const gchar *select_id);
+void           module_itip_formatter_dom_utils_select_set_selected
+                                               (WebKitDOMDocument *document,
+                                                const gchar *select_id,
+                                                const gchar *option);
+void           module_itip_formatter_dom_utils_update_times
+                                               (WebKitDOMDocument *document,
+                                                const gchar *element_id,
+                                                const gchar *header,
+                                                const gchar *label);
+void           module_itip_formatter_dom_utils_append_info_item_row
+                                               (WebKitDOMDocument *document,
+                                                const gchar *table_id,
+                                                const gchar *row_id,
+                                                const gchar *icon_name,
+                                                const gchar *message);
+void           module_itip_formatter_dom_utils_enable_text_area
+                                               (WebKitDOMDocument *document,
+                                                const gchar *area_id,
+                                                gboolean enable);
+void           module_itip_formatter_dom_utils_text_area_set_value
+                                               (WebKitDOMDocument *document,
+                                                const gchar *area_id,
+                                                const gchar *value);
+gchar *                module_itip_formatter_dom_utils_text_area_get_value
+                                               (WebKitDOMDocument *document,
+                                                const gchar *area_id);
+void           module_itip_formatter_dom_utils_rebuild_source_list
+                                               (WebKitDOMDocument *document,
+                                                const gchar *optgroup_id,
+                                                const gchar *optgroup_label,
+                                                const gchar *option_id,
+                                                const gchar *option_label,
+                                                gboolean writable);
+G_END_DECLS
+
+#endif /* MODULE_ITIP_FORMATTER_DOM_UTILS_H */
diff --git a/modules/itip-formatter/web-extension/Makefile.am 
b/modules/itip-formatter/web-extension/Makefile.am
new file mode 100644
index 0000000..ab62dff
--- /dev/null
+++ b/modules/itip-formatter/web-extension/Makefile.am
@@ -0,0 +1,25 @@
+webextensions_LTLIBRARIES = libmoduleitipformatterwebextension.la
+
+libmoduleitipformatterwebextension_la_SOURCES =                \
+       module-itip-formatter-web-extension.c           \
+       module-itip-formatter-web-extension.h           \
+       ../module-itip-formatter-dom-utils.c            \
+       ../module-itip-formatter-dom-utils.h
+
+libmoduleitipformatterwebextension_la_CPPFLAGS =       \
+       $(AM_CPPFLAGS)                                  \
+       -I$(top_srcdir)                                 \
+       $(EVOLUTION_DATA_SERVER_CFLAGS)                 \
+       $(GNOME_PLATFORM_CFLAGS)                        \
+       $(GTKHTML_CFLAGS)                               \
+       $(WEB_EXTENSIONS_CFLAGS)
+
+libmoduleitipformatterwebextension_la_LIBADD =         \
+       $(top_builddir)/e-util/libevolution-util.la     \
+       $(EVOLUTION_DATA_SERVER_LIBS)                   \
+       $(GNOME_PLATFORM_LIBS)                          \
+       $(GTKHTML_LIBS)                                 \
+       $(WEB_EXTENSIONS_LIBS)
+
+libmoduleitipformatterwebextension_la_LDFLAGS =                \
+       -module -avoid-version -no-undefined
diff --git a/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.c 
b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.c
new file mode 100644
index 0000000..7fc005d
--- /dev/null
+++ b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.c
@@ -0,0 +1,619 @@
+/*
+ * module-itip-formatter-web-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "module-itip-formatter-web-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include <e-util/e-dom-utils.h>
+
+#include "../module-itip-formatter-dom-utils.h"
+
+/* FIXME Clean it */
+static GDBusConnection *dbus_connection;
+
+static const char introspection_xml[] =
+"<node>"
+"  <interface name='org.gnome.Evolution.Module.ItipFormatter.WebExtension'>"
+"    <signal name='RecurToggled'>"
+"    </signal>"
+"    <signal name='SourceChanged'>"
+"    </signal>"
+"    <signal name='ButtonClicked'>"
+"      <arg type='s' name='button_value' direction='out'/>"
+"    </signal>"
+"    <method name='SaveDocumentFromElement'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"    </method>"
+"    <method name='ShowButton'>"
+"      <arg type='s' name='button_id' direction='in'/>"
+"    </method>"
+"    <method name='CreateDOMBindings'>"
+"    </method>"
+"    <method name='ElementSetInnerHTML'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='s' name='inner_html' direction='in'/>"
+"    </method>"
+"    <method name='RemoveElement'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"    </method>"
+"    <method name='ElementRemoveChildNodes'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"    </method>"
+"    <method name='EnableButton'>"
+"      <arg type='s' name='button_id' direction='in'/>"
+"      <arg type='b' name='enable' direction='in'/>"
+"    </method>"
+"    <method name='ElementIsHidden'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='b' name='is_hidden' direction='out'/>"
+"    </method>"
+"    <method name='HideElement'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='b' name='hide' direction='in'/>"
+"    </method>"
+"    <method name='BindSaveButton'>"
+"    </method>"
+"    <method name='InputSetChecked'>"
+"      <arg type='s' name='input_id' direction='in'/>"
+"      <arg type='b' name='checked' direction='in'/>"
+"    </method>"
+"    <method name='InputIsChecked'>"
+"      <arg type='s' name='input_id' direction='in'/>"
+"      <arg type='b' name='checked' direction='out'/>"
+"    </method>"
+"    <method name='ShowCheckbox'>"
+"      <arg type='s' name='id' direction='in'/>"
+"      <arg type='b' name='show' direction='in'/>"
+"      <arg type='b' name='update_second' direction='in'/>"
+"    </method>"
+"    <method name='SetButtonsSensitive'>"
+"      <arg type='b' name='sensitive' direction='in'/>"
+"    </method>"
+"    <method name='SetAreaText'>"
+"      <arg type='s' name='id' direction='in'/>"
+"      <arg type='s' name='text' direction='in'/>"
+"    </method>"
+"    <method name='ElementSetAccessKey'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='s' name='access_key' direction='in'/>"
+"    </method>"
+"    <method name='ElementHideChildNodes'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"    </method>"
+"    <method name='EnableSelect'>"
+"      <arg type='s' name='select_id' direction='in'/>"
+"      <arg type='b' name='enable' direction='in'/>"
+"    </method>"
+"    <method name='SelectIsEnabled'>"
+"      <arg type='s' name='select_id' direction='in'/>"
+"      <arg type='b' name='enable' direction='out'/>"
+"    </method>"
+"    <method name='SelectGetValue'>"
+"      <arg type='s' name='select_id' direction='in'/>"
+"      <arg type='s' name='value' direction='out'/>"
+"    </method>"
+"    <method name='SelectSetSelected'>"
+"      <arg type='s' name='select_id' direction='in'/>"
+"      <arg type='s' name='option' direction='in'/>"
+"    </method>"
+"    <method name='UpdateTimes'>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='s' name='header' direction='in'/>"
+"      <arg type='s' name='label' direction='in'/>"
+"    </method>"
+"    <method name='AppendInfoItemRow'>"
+"      <arg type='s' name='table_id' direction='in'/>"
+"      <arg type='s' name='row_id' direction='in'/>"
+"      <arg type='s' name='icon_name' direction='in'/>"
+"      <arg type='s' name='message' direction='in'/>"
+"    </method>"
+"    <method name='EnableTextArea'>"
+"      <arg type='s' name='area_id' direction='in'/>"
+"      <arg type='b' name='enable' direction='in'/>"
+"    </method>"
+"    <method name='TextAreaSetValue'>"
+"      <arg type='s' name='area_id' direction='in'/>"
+"      <arg type='s' name='value' direction='in'/>"
+"    </method>"
+"    <method name='TextAreaGetValue'>"
+"      <arg type='s' name='area_id' direction='in'/>"
+"      <arg type='s' name='value' direction='out'/>"
+"    </method>"
+"    <method name='RebuildSourceList'>"
+"      <arg type='s' name='optgroup_id' direction='in'/>"
+"      <arg type='s' name='optgroup_label' direction='in'/>"
+"      <arg type='s' name='option_id' direction='in'/>"
+"      <arg type='s' name='option_label' direction='in'/>"
+"      <arg type='b' name='writable' direction='in'/>"
+"    </method>"
+"  </interface>"
+"</node>";
+
+static WebKitDOMDocument *document_saved = NULL;
+
+static WebKitWebPage *
+get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+                                          WebKitWebExtension *web_extension,
+                                          guint64 page_id)
+{
+       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+       if (!web_page) {
+               g_dbus_method_invocation_return_error (
+                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                       "Invalid page ID: %"G_GUINT64_FORMAT, page_id);
+       }
+       return web_page;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+                    const char *sender,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer user_data)
+{
+       WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+       WebKitWebPage *web_page;
+       WebKitDOMDocument *document;
+       guint64 page_id;
+
+       if (g_strcmp0 (interface_name, MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE) != 0)
+               return;
+
+       if (g_strcmp0 (method_name, "SaveDocumentFromElement") == 0) {
+               WebKitDOMElement *element;
+               const gchar *element_id;
+
+               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               document_saved = document;
+
+               element = e_dom_utils_find_element_by_id (document, element_id);
+
+               if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+                       element = webkit_dom_element_query_selector (
+                               element, "iframe", NULL);
+
+               if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+                       document_saved =
+                               webkit_dom_html_iframe_element_get_content_document (
+                                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+               else
+                       document_saved = document;
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ShowButton") == 0) {
+               const gchar *button_id;
+
+               g_variant_get (parameters, "(&s)", &button_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_show_button (document_saved, button_id);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "EnableButton") == 0) {
+               const gchar *button_id;
+               gboolean enable;
+
+               g_variant_get (parameters, "(&sb)", &button_id, &enable);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_enable_button (
+                       document_saved, button_id, enable);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "CreateDOMBindings") == 0) {
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_create_dom_bindings (
+                       document_saved, connection);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ElementSetInnerHTML") == 0) {
+               const gchar *element_id, *inner_html;
+
+               g_variant_get (parameters, "(&s&s)", &element_id, &inner_html);
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               e_dom_utils_element_set_inner_html (
+                       document_saved, element_id, inner_html);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "RemoveElement") == 0) {
+               const gchar *element_id;
+
+               g_variant_get (parameters, "(&s)", &element_id);
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               e_dom_utils_remove_element (document_saved, element_id);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ElementRemoveChildNodes") == 0) {
+               const gchar *element_id;
+
+               g_variant_get (parameters, "(&s)", &element_id);
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               e_dom_utils_element_remove_child_nodes (document_saved, element_id);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "HideElement") == 0) {
+               const gchar *element_id;
+               gboolean hide;
+
+               g_variant_get (parameters, "(&sb)", &element_id, &hide);
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               e_dom_utils_hide_element (document_saved, element_id, hide);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ElementIsHidden") == 0) {
+               const gchar *element_id;
+               gboolean hidden;
+
+               g_variant_get (parameters, "(&s)", &element_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               hidden = e_dom_utils_element_is_hidden (document_saved, element_id);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(b)", hidden));
+       } else if (g_strcmp0 (method_name, "BindSaveButton") == 0) {
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_bind_save_button (
+                       document_saved, connection);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "InputSetChecked") == 0) {
+               const gchar *input_id;
+               gboolean checked;
+
+               g_variant_get (parameters, "(&sb)", &input_id, &checked);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_input_set_checked (
+                       document_saved, input_id, checked);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "InputIsChecked") == 0) {
+               const gchar *input_id;
+               gboolean checked;
+
+               g_variant_get (parameters, "(&s)", &input_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               checked = module_itip_formatter_dom_utils_input_is_checked (
+                       document_saved, input_id);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(b)", checked));
+       } else if (g_strcmp0 (method_name, "ShowCheckbox") == 0) {
+               const gchar *id;
+               gboolean show, update_second;
+
+               g_variant_get (parameters, "(&sbb)", &id, &show, &update_second);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_show_checkbox (
+                       document_saved, id, show, update_second);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SetButtonsSensitive") == 0) {
+               gboolean sensitive;
+
+               g_variant_get (parameters, "(b)", &sensitive);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_set_buttons_sensitive (
+                       document_saved, sensitive);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SetAreaText") == 0) {
+               const gchar *id, *text;
+
+               g_variant_get (parameters, "(&s&s)", &id, &text);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_set_area_text (
+                       document_saved, id, text);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ElementSetAccessKey") == 0) {
+               const gchar *element_id, *access_key;
+
+               g_variant_get (parameters, "(&s&s)", &element_id, &access_key);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_element_set_access_key (
+                       document_saved, element_id, access_key);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ElementHideChildNodes") == 0) {
+               const gchar *element_id;
+
+               g_variant_get (parameters, "(&s)", &element_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_element_hide_child_nodes (
+                       document_saved, element_id);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "EnableSelect") == 0) {
+               const gchar *select_id;
+               gboolean enable;
+
+               g_variant_get (parameters, "(&sb)", &select_id, &enable);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_enable_select (
+                       document_saved, select_id, enable);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SelectIsEnabled") == 0) {
+               const gchar *select_id;
+               gboolean enabled;
+
+               g_variant_get (parameters, "(&s)", &select_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               enabled = module_itip_formatter_dom_utils_select_is_enabled (
+                       document_saved, select_id);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(b)", enabled));
+       } else if (g_strcmp0 (method_name, "SelectGetValue") == 0) {
+               const gchar *select_id;
+               gchar *value;
+
+               g_variant_get (parameters, "(&s)", &select_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               value = module_itip_formatter_dom_utils_select_get_value (
+                       document_saved, select_id);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", value));
+
+               g_free (value);
+       } else if (g_strcmp0 (method_name, "SelectSetSelected") == 0) {
+               const gchar *select_id, *option;
+
+               g_variant_get (parameters, "(&s&s)", &select_id, &option);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_select_set_selected (
+                       document_saved, select_id, option);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "UpdateTimes") == 0) {
+               const gchar *element_id, *header, *label;
+
+               g_variant_get (parameters, "(&s&s&s)", &element_id, &header, &label);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_update_times (
+                       document_saved, element_id, header, label);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "AppendInfoItemRow") == 0) {
+               const gchar *table_id, *row_id, *icon_name, *message;
+
+               g_variant_get (
+                       parameters,
+                       "(&s&s&s&s)",
+                       &table_id, &row_id, &icon_name, &message);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_append_info_item_row (
+                       document_saved, table_id, row_id, icon_name, message);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "EnableTextArea") == 0) {
+               const gchar *area_id;
+               gboolean enable;
+
+               g_variant_get (parameters, "(&sb)", &area_id, &enable);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_enable_text_area (
+                       document_saved, area_id, enable);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "TextAreaSetValue") == 0) {
+               const gchar *area_id, *value;
+
+               g_variant_get (parameters, "(&s&s)", &area_id, &value);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_text_area_set_value (
+                       document_saved, area_id, value);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "TextAreaGetValue") == 0) {
+               const gchar *area_id;
+               gchar *value;
+
+               g_variant_get (parameters, "(&s)", &area_id);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               value = module_itip_formatter_dom_utils_text_area_get_value (
+                               document_saved, area_id);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", value));
+
+               g_free (value);
+       } else if (g_strcmp0 (method_name, "RebuildSourceList") == 0) {
+               const gchar *optgroup_id, *optgroup_label, *option_id, *option_label;
+               gboolean writable;
+
+               g_variant_get (
+                       parameters,
+                       "(&s&s&s&sb)",
+                       &optgroup_id, &optgroup_label, &option_id, &option_label, &writable);
+
+               /* FIXME return error */
+               if (!document_saved)
+                       g_dbus_method_invocation_return_value (invocation, NULL);
+
+               module_itip_formatter_dom_utils_rebuild_source_list (
+                       document_saved,
+                       optgroup_id,
+                       optgroup_label,
+                       option_id,
+                       option_label,
+                       writable);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+       handle_method_call,
+       NULL,
+       NULL
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+       guint registration_id;
+       GError *error = NULL;
+       static GDBusNodeInfo *introspection_data = NULL;
+
+       if (!introspection_data)
+               introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+       registration_id =
+               g_dbus_connection_register_object (
+                       connection,
+                       MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+                       introspection_data->interfaces[0],
+                       &interface_vtable,
+                       g_object_ref (user_data),
+                       g_object_unref,
+                       &error);
+
+       if (!registration_id) {
+               g_warning ("Failed to register object: %s\n", error->message);
+               g_error_free (error);
+       } else {
+               dbus_connection = connection;
+               g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+       }
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+       g_bus_own_name (
+               G_BUS_TYPE_SESSION,
+               MODULE_ITIP_FORMATTER_WEB_EXTENSION_SERVICE_NAME,
+               G_BUS_NAME_OWNER_FLAGS_NONE,
+               bus_acquired_cb,
+               NULL, NULL,
+               g_object_ref (extension),
+               g_object_unref);
+}
diff --git a/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.h 
b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.h
new file mode 100644
index 0000000..b9ffae0
--- /dev/null
+++ b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ * module-itip-formatter-web-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef MODULE_ITIP_FORMATTER_WEB_EXTENSION_H
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_H
+
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_SERVICE_NAME 
"org.gnome.Evolution.Module.ItipFormatter.WebExtension"
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH  
"/org/gnome/Evolution/Module/ItipFormatter/WebExtension"
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE    
"org.gnome.Evolution.Module.ItipFormatter.WebExtension"
+
+#endif /* MODULE_ITIP_FORMATTER_WEB_EXTENSION_H */
diff --git a/modules/mail/Makefile.am b/modules/mail/Makefile.am
index 770975e..efb31c9 100644
--- a/modules/mail/Makefile.am
+++ b/modules/mail/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS=web-extension
+
 module_LTLIBRARIES = module-mail.la
 
 module_mail_la_CPPFLAGS = \
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
index bf2d1a3..ff83c9f 100644
--- a/modules/mail/e-mail-shell-backend.c
+++ b/modules/mail/e-mail-shell-backend.c
@@ -112,7 +112,8 @@ message_parsed_cb (GObject *source_object,
 
        parts_list = e_mail_parser_parse_finish (parser, res, NULL);
 
-       soup_session = webkit_get_default_session ();
+//     soup_session = webkit_get_default_session ();
+       soup_session = NULL;
        mails = g_object_get_data (G_OBJECT (soup_session), "mails");
        if (!mails) {
                mails = g_hash_table_new_full (
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index 14b0830..0dd73b6 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -26,6 +26,8 @@
 
 #include "e-util/e-util-private.h"
 
+#include "web-extension/module-mail-web-extension.h"
+
 typedef struct _AsyncContext AsyncContext;
 
 struct _AsyncContext {
@@ -250,35 +252,30 @@ mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
 }
 
 static gboolean
-mail_shell_view_mail_display_needs_key (EMailDisplay *mail_display,
-                                        gboolean with_input)
+mail_shell_view_mail_display_needs_key (EMailShellView *mail_shell_view,
+                                        EMailDisplay *mail_display)
 {
-       gboolean needs_key = FALSE;
-
        if (gtk_widget_has_focus (GTK_WIDGET (mail_display))) {
-               WebKitWebFrame *frame;
-               WebKitDOMDocument *dom;
-               WebKitDOMElement *element;
-               gchar *name = NULL;
+               GDBusProxy *web_extension;
 
-               frame = webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display));
-               if (!frame)
-                       return FALSE;
-               dom = webkit_web_frame_get_dom_document (frame);
-               element = webkit_dom_html_document_get_active_element (WEBKIT_DOM_HTML_DOCUMENT (dom));
+               /* Intentionally use Evolution Web Extension */
+               web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (mail_display));
+               if (web_extension) {
+                       GVariant *result;
 
-               if (element)
-                       name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (element));
+                       result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
+                       if (result) {
+                               gboolean need_input;
 
-               /* if INPUT or TEXTAREA has focus, then any key press should go there */
-               if (name && ((with_input && g_ascii_strcasecmp (name, "INPUT") == 0) || g_ascii_strcasecmp 
(name, "TEXTAREA") == 0)) {
-                       needs_key = TRUE;
-               }
+                               need_input = g_variant_get_boolean (result);
+                               g_variant_unref (result);
 
-               g_free (name);
+                               return need_input;
+                       }
+               }
        }
 
-       return needs_key;
+       return FALSE;
 }
 
 static gboolean
@@ -313,42 +310,11 @@ mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
                        action = ACTION (MAIL_SMART_BACKWARD);
                        break;
 
-               case GDK_KEY_Home:
-               case GDK_KEY_Left:
-               case GDK_KEY_Up:
-               case GDK_KEY_Right:
-               case GDK_KEY_Down:
-               case GDK_KEY_Next:
-               case GDK_KEY_End:
-               case GDK_KEY_Begin:
-                       /* If Caret mode is enabled don't try to process these keys */
-                       if (e_web_view_get_caret_mode (E_WEB_VIEW (mail_display)))
-                               return FALSE;
-               case GDK_KEY_Prior:
-                       if (!mail_shell_view_mail_display_needs_key (mail_display, FALSE) &&
-                           webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display)) !=
-                           webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display))) {
-                               WebKitDOMDocument *document;
-                               WebKitDOMDOMWindow *window;
-
-                               document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (mail_display));
-                               window = webkit_dom_document_get_default_view (document);
-
-                               /* Workaround WebKit bug for key navigation, when inner IFRAME is focused.
-                                * EMailView's inner IFRAMEs have disabled scrolling, but WebKit doesn't post
-                                * key navigation events to parent's frame, thus the view doesn't scroll.
-                                * This is a poor workaround for this issue, the main frame is focused,
-                                * which has scrolling enabled.
-                               */
-                               webkit_dom_dom_window_focus (window);
-                       }
-
-                       return FALSE;
                default:
                        return FALSE;
        }
 
-       if (mail_shell_view_mail_display_needs_key (mail_display, TRUE))
+       if (mail_shell_view_mail_display_needs_key (mail_shell_view, mail_display))
                return FALSE;
 
        gtk_action_activate (action);
@@ -563,12 +529,77 @@ mail_shell_view_search_filter_changed_cb (EMailShellView *mail_shell_view)
        e_mail_reader_avoid_next_mark_as_seen (E_MAIL_READER (mail_view));
 }
 
+static void
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+                                GAsyncResult *result,
+                                EMailShellView *mail_shell_view)
+{
+       GError *error = NULL;
+
+       mail_shell_view->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
+       if (!mail_shell_view->priv->web_extension) {
+               g_warning ("Error creating web extension proxy: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           const gchar *name_owner,
+                           EMailShellView *mail_shell_view)
+{
+       g_dbus_proxy_new (
+               connection,
+               G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+               G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+               G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+               NULL,
+               name,
+               MODULE_MAIL_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_MAIL_WEB_EXTENSION_INTERFACE,
+               NULL,
+               (GAsyncReadyCallback)web_extension_proxy_created_cb,
+               mail_shell_view);
+}
+
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           EMailShellView *mail_shell_view)
+{
+       g_clear_object (&mail_shell_view->priv->web_extension);
+}
+
+static void
+mail_shell_view_watch_web_extension (EMailShellView *mail_shell_view)
+{
+       mail_shell_view->priv->web_extension_watch_name_id =
+               g_bus_watch_name (
+                       G_BUS_TYPE_SESSION,
+                       MODULE_MAIL_WEB_EXTENSION_SERVICE_NAME,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       (GBusNameAppearedCallback) web_extension_appeared_cb,
+                       (GBusNameVanishedCallback) web_extension_vanished_cb,
+                       mail_shell_view, NULL);
+}
+
+GDBusProxy *
+e_mail_shell_view_get_web_extension_proxy (EMailShellView *mail_shell_view)
+{
+       g_return_val_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view), NULL);
+
+       return mail_shell_view->priv->web_extension;
+}
+
 void
 e_mail_shell_view_private_init (EMailShellView *mail_shell_view)
 {
        e_signal_connect_notify (
                mail_shell_view, "notify::view-id",
                G_CALLBACK (mail_shell_view_notify_view_id_cb), NULL);
+
+       mail_shell_view_watch_web_extension (mail_shell_view);
 }
 
 void
@@ -799,6 +830,12 @@ e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view)
                priv->prepare_for_quit_handler_id = 0;
        }
 
+       if (priv->web_extension_watch_name_id > 0) {
+               g_bus_unwatch_name (priv->web_extension_watch_name_id);
+               priv->web_extension_watch_name_id = 0;
+       }
+
+       g_clear_object (&priv->web_extension);
        g_clear_object (&priv->mail_shell_backend);
        g_clear_object (&priv->mail_shell_content);
        g_clear_object (&priv->mail_shell_sidebar);
diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h
index e42222d..29869f4 100644
--- a/modules/mail/e-mail-shell-view-private.h
+++ b/modules/mail/e-mail-shell-view-private.h
@@ -137,6 +137,9 @@ struct _EMailShellViewPrivate {
 
        GtkToolItem *send_receive_tool_item;
        GtkToolItem *send_receive_tool_separator;
+
+       GDBusProxy *web_extension;
+       guint web_extension_watch_name_id;
 };
 
 void           e_mail_shell_view_private_init
@@ -162,6 +165,8 @@ void                e_mail_shell_view_update_sidebar
                                        (EMailShellView *mail_shell_view);
 void           e_mail_shell_view_update_send_receive_menus
                                        (EMailShellView *mail_shell_view);
+GDBusProxy *   e_mail_shell_view_get_web_extension_proxy
+                                       (EMailShellView *mail_shell_view);
 
 G_END_DECLS
 
diff --git a/modules/mail/web-extension/Makefile.am b/modules/mail/web-extension/Makefile.am
new file mode 100644
index 0000000..b89d112
--- /dev/null
+++ b/modules/mail/web-extension/Makefile.am
@@ -0,0 +1,23 @@
+webextensions_LTLIBRARIES = libmodulemailwebextension.la
+
+libmodulemailwebextension_la_SOURCES =                 \
+       module-mail-web-extension.c                     \
+       module-mail-web-extension.h
+
+libmodulemailwebextension_la_CPPFLAGS =                        \
+       $(AM_CPPFLAGS)                                  \
+       -I$(top_srcdir)                                 \
+       $(EVOLUTION_DATA_SERVER_CFLAGS)                 \
+       $(GNOME_PLATFORM_CFLAGS)                        \
+       $(GTKHTML_CFLAGS)                               \
+       $(WEB_EXTENSIONS_CFLAGS)
+
+libmodulemailwebextension_la_LIBADD =                  \
+       $(top_builddir)/e-util/libevolution-util.la     \
+       $(EVOLUTION_DATA_SERVER_LIBS)                   \
+       $(GNOME_PLATFORM_LIBS)                          \
+       $(GTKHTML_LIBS)                                 \
+       $(WEB_EXTENSIONS_LIBS)
+
+libmodulemailwebextension_la_LDFLAGS =                 \
+       -module -avoid-version -no-undefined
diff --git a/modules/mail/web-extension/module-mail-web-extension.c 
b/modules/mail/web-extension/module-mail-web-extension.c
new file mode 100644
index 0000000..a3c9a7e
--- /dev/null
+++ b/modules/mail/web-extension/module-mail-web-extension.c
@@ -0,0 +1,141 @@
+/*
+ * module-mail-web-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "module-mail-web-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include <e-util/e-dom-utils.h>
+
+/* FIXME Clean it */
+static GDBusConnection *dbus_connection;
+
+static const char introspection_xml[] =
+"<node>"
+"  <interface name='org.gnome.Evolution.Module.Mail.WebExtension'>"
+"    <method name='GetActiveElementName'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_name' direction='out'/>"
+"    </method>"
+"  </interface>"
+"</node>";
+
+static WebKitWebPage *
+get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+                                          WebKitWebExtension *web_extension,
+                                          guint64 page_id)
+{
+       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+       if (!web_page) {
+               g_dbus_method_invocation_return_error (
+                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                       "Invalid page ID: %"G_GUINT64_FORMAT, page_id);
+       }
+       return web_page;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+                    const char *sender,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer user_data)
+{
+       WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+       WebKitWebPage *web_page;
+       WebKitDOMDocument *document;
+       guint64 page_id;
+
+       if (g_strcmp0 (interface_name, MODULE_MAIL_WEB_EXTENSION_INTERFACE) != 0)
+               return;
+
+       if (g_strcmp0 (method_name, "GetActiveElementName") == 0) {
+               gchar *element_name;
+
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               element_name = e_dom_utils_get_active_element_name (document);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", element_name));
+
+               g_free (element_name);
+       }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+       handle_method_call,
+       NULL,
+       NULL
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+       guint registration_id;
+       GError *error = NULL;
+       static GDBusNodeInfo *introspection_data = NULL;
+
+       if (!introspection_data)
+               introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+       registration_id =
+               g_dbus_connection_register_object (
+                       connection,
+                       MODULE_MAIL_WEB_EXTENSION_OBJECT_PATH,
+                       introspection_data->interfaces[0],
+                       &interface_vtable,
+                       g_object_ref (user_data),
+                       g_object_unref,
+                       &error);
+
+       if (!registration_id) {
+               g_warning ("Failed to register object: %s\n", error->message);
+               g_error_free (error);
+       } else {
+               dbus_connection = connection;
+               g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+       }
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+       g_bus_own_name (
+               G_BUS_TYPE_SESSION,
+               MODULE_MAIL_WEB_EXTENSION_SERVICE_NAME,
+               G_BUS_NAME_OWNER_FLAGS_NONE,
+               bus_acquired_cb,
+               NULL, NULL,
+               g_object_ref (extension),
+               g_object_unref);
+}
diff --git a/modules/mail/web-extension/module-mail-web-extension.h 
b/modules/mail/web-extension/module-mail-web-extension.h
new file mode 100644
index 0000000..f1fe0a8
--- /dev/null
+++ b/modules/mail/web-extension/module-mail-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ * module-mail-web-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef MODULE_MAIL_WEB_EXTENSION_H
+#define MODULE_MAIL_WEB_EXTENSION_H
+
+#define MODULE_MAIL_WEB_EXTENSION_SERVICE_NAME "org.gnome.Evolution.Module.Mail.WebExtension"
+#define MODULE_MAIL_WEB_EXTENSION_OBJECT_PATH  "/org/gnome/Evolution/Module/Mail/WebExtension"
+#define MODULE_MAIL_WEB_EXTENSION_INTERFACE    "org.gnome.Evolution.Module.Mail.WebExtension"
+
+#endif /* MODULE_MAIL_WEB_EXTENSION_H */
diff --git a/modules/prefer-plain/Makefile.am b/modules/prefer-plain/Makefile.am
index 9b6c8b3..99ec301 100644
--- a/modules/prefer-plain/Makefile.am
+++ b/modules/prefer-plain/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=plugin
+SUBDIRS=plugin web-extension
 
 module_LTLIBRARIES = module-prefer-plain.la
 
diff --git a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c 
b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
index c23e5d2..d916e40 100644
--- a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
+++ b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
@@ -23,6 +23,8 @@
 #include <shell/e-shell-window.h>
 #include "mail/e-mail-browser.h"
 
+#include "web-extension/module-prefer-plain-web-extension.h"
+
 #include <libebackend/libebackend.h>
 
 #include <glib/gi18n-lib.h>
@@ -35,12 +37,13 @@ typedef struct _EMailDisplayPopupPreferPlainClass EMailDisplayPopupPreferPlainCl
 struct _EMailDisplayPopupPreferPlain {
        EExtension parent;
 
-       WebKitDOMDocument *document;
        gchar *text_plain_id;
        gchar *text_html_id;
 
        GtkActionGroup *action_group;
 
+       GDBusProxy *web_extension;
+       gint web_extension_watch_name_id;
 };
 
 struct _EMailDisplayPopupPreferPlainClass {
@@ -90,20 +93,85 @@ static const gchar *ui_reader =
 "</ui>";
 
 static void
-toggle_part (GtkAction *action,
-             EMailDisplayPopupExtension *extension)
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+                                GAsyncResult *result,
+                                EMailDisplayPopupPreferPlain *pp_extension)
+{
+       GError *error = NULL;
+
+       pp_extension->web_extension = g_dbus_proxy_new_finish (result, &error);
+       if (!pp_extension->web_extension) {
+               g_warning ("Error creating web extension proxy: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           const gchar *name_owner,
+                           EMailDisplayPopupPreferPlain *pp_extension)
+{
+       g_dbus_proxy_new (
+               connection,
+               G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+               G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+               G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+               NULL,
+               name,
+               MODULE_PREFER_PLAIN_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_PREFER_PLAIN_WEB_EXTENSION_INTERFACE,
+               NULL,
+               (GAsyncReadyCallback)web_extension_proxy_created_cb,
+               pp_extension);
+}
+
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           EMailDisplayPopupPreferPlain *pp_extension)
+{
+       g_clear_object (&pp_extension->web_extension);
+}
+
+static void
+mail_display_popup_prefer_plain_watch_web_extension (EMailDisplayPopupPreferPlain *pp_extension)
+{
+       pp_extension->web_extension_watch_name_id =
+               g_bus_watch_name (
+                       G_BUS_TYPE_SESSION,
+                       MODULE_PREFER_PLAIN_WEB_EXTENSION_SERVICE_NAME,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       (GBusNameAppearedCallback) web_extension_appeared_cb,
+                       (GBusNameVanishedCallback) web_extension_vanished_cb,
+                       pp_extension, NULL);
+}
+
+static void
+toggle_part_get_document_uri_cb (GDBusProxy *web_extension,
+                                 GAsyncResult *result,
+                                 EMailDisplayPopupExtension *extension)
 {
        EMailDisplayPopupPreferPlain *pp_extension = (EMailDisplayPopupPreferPlain *) extension;
-       WebKitDOMDocument *doc = pp_extension->document;
-       WebKitDOMDOMWindow *window;
-       WebKitDOMElement *frame_element;
        SoupURI *soup_uri;
        GHashTable *query;
        gchar *uri;
+       GVariant *result_variant;
 
-       uri = webkit_dom_document_get_document_uri (doc);
-       soup_uri = soup_uri_new (uri);
-       g_free (uri);
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               const gchar *document_uri;
+
+               g_variant_get (result_variant, "(&s)", &document_uri);
+               soup_uri = soup_uri_new (document_uri);
+               g_variant_unref (result_variant);
+       }
+
+       if (!soup_uri || !soup_uri->query) {
+               if (soup_uri)
+                       soup_uri_free (soup_uri);
+               return;
+       }
 
        query = soup_form_decode (soup_uri->query);
        g_hash_table_replace (
@@ -123,15 +191,40 @@ toggle_part (GtkAction *action,
        uri = soup_uri_to_string (soup_uri, FALSE);
        soup_uri_free (soup_uri);
 
-       /* Get frame's window and from the window the actual <iframe> element */
-       window = webkit_dom_document_get_default_view (doc);
-       frame_element = webkit_dom_dom_window_get_frame_element (window);
-       webkit_dom_html_iframe_element_set_src (
-               WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), uri);
+       g_dbus_proxy_call (
+               pp_extension->web_extension,
+               "ChangeIFrameSource",
+               g_variant_new ("(s)", uri),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
        g_free (uri);
 }
 
+static void
+toggle_part (GtkAction *action,
+             EMailDisplayPopupExtension *extension)
+{
+       EMailDisplayPopupPreferPlain *pp_extension = (EMailDisplayPopupPreferPlain *) extension;
+
+       if (!pp_extension->web_extension)
+               return;
+
+       /* Get URI from saved document */
+       g_dbus_proxy_call (
+               pp_extension->web_extension,
+               "GetDocumentURI",
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               (GAsyncReadyCallback) toggle_part_get_document_uri_cb,
+               extension);
+}
+
 GtkActionEntry entries[] = {
 
        { "show-plain-text-part",
@@ -217,13 +310,13 @@ create_group (EMailDisplayPopupExtension *extension)
 }
 
 static void
-mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *extension,
-                                                WebKitHitTestResult *context)
+get_document_uri_cb (GDBusProxy *web_extension,
+                     GAsyncResult *result,
+                     EMailDisplayPopupExtension *extension)
 {
        EMailDisplay *display;
        GtkAction *action;
-       WebKitDOMNode *node;
-       gchar *uri, *part_id, *pos, *prefix;
+       gchar *part_id, *pos, *prefix;
        SoupURI *soup_uri;
        GHashTable *query;
        EMailPartList *part_list;
@@ -232,31 +325,26 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
        EMailDisplayPopupPreferPlain *pp_extension;
        GQueue queue = G_QUEUE_INIT;
        GList *head, *link;
+       GVariant *result_variant;
 
        display = E_MAIL_DISPLAY (e_extension_get_extensible (
                        E_EXTENSION (extension)));
 
        pp_extension = E_MAIL_DISPLAY_POPUP_PREFER_PLAIN (extension);
 
-       if (!pp_extension->action_group)
-               pp_extension->action_group = create_group (extension);
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               const gchar *document_uri;
 
-       g_object_get (context, "inner-node", &node, NULL);
-
-       if (!node) {
-               gtk_action_group_set_visible (pp_extension->action_group, FALSE);
-               return;
+               g_variant_get (result_variant, "(&s)", &document_uri);
+               soup_uri = soup_uri_new (document_uri);
+               g_variant_unref (result_variant);
        }
 
-       pp_extension->document = webkit_dom_node_get_owner_document (node);
-       uri = webkit_dom_document_get_document_uri (pp_extension->document);
-
-       soup_uri = soup_uri_new (uri);
        if (!soup_uri || !soup_uri->query) {
                gtk_action_group_set_visible (pp_extension->action_group, FALSE);
                if (soup_uri)
                        soup_uri_free (soup_uri);
-               g_free (uri);
                return;
        }
 
@@ -264,28 +352,19 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
        part_id = g_hash_table_lookup (query, "part_id");
        if (part_id == NULL) {
                gtk_action_group_set_visible (pp_extension->action_group, FALSE);
-               g_hash_table_destroy (query);
-               soup_uri_free (soup_uri);
-               g_free (uri);
-               return;
+               goto out;
        }
 
        pos = strstr (part_id, ".alternative-prefer-plain.");
        if (!pos) {
                gtk_action_group_set_visible (pp_extension->action_group, FALSE);
-               g_hash_table_destroy (query);
-               soup_uri_free (soup_uri);
-               g_free (uri);
-               return;
+               goto out;
        }
 
        /* Don't display the actions on any other than text/plain or text/html parts */
        if (!strstr (pos, "plain_text") && !strstr (pos, "text_html")) {
                gtk_action_group_set_visible (pp_extension->action_group, FALSE);
-               g_hash_table_destroy (query);
-               soup_uri_free (soup_uri);
-               g_free (uri);
-               return;
+               goto out;
        }
 
        /* Check whether the displayed part is text_plain */
@@ -353,9 +432,63 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
        }
 
        g_free (prefix);
+ out:
        g_hash_table_destroy (query);
        soup_uri_free (soup_uri);
-       g_free (uri);
+}
+
+static void
+mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *extension)
+{
+       EMailDisplay *display;
+       EMailDisplayPopupPreferPlain *pp_extension;
+       gint32 x, y;
+       GdkDeviceManager *device_manager;
+       GdkDevice *pointer;
+
+       display = E_MAIL_DISPLAY (e_extension_get_extensible (
+                       E_EXTENSION (extension)));
+
+       pp_extension = E_MAIL_DISPLAY_POPUP_PREFER_PLAIN (extension);
+
+       if (!pp_extension->action_group)
+               pp_extension->action_group = create_group (extension);
+
+       /* In WK2 you can't get the node on what WebKitHitTest was performed,
+        * we have to use other way */
+       device_manager = gdk_display_get_device_manager (
+               gtk_widget_get_display (GTK_WIDGET(display)));
+       pointer = gdk_device_manager_get_client_pointer (device_manager);
+       gdk_window_get_device_position (
+               gtk_widget_get_window (GTK_WIDGET (display)), pointer, &x, &y, NULL);
+
+       if (!pp_extension->web_extension)
+                       return;
+
+       g_dbus_proxy_call (
+               pp_extension->web_extension,
+               "SaveDocumentFromPoint",
+               g_variant_new (
+                       "(tii)",
+                       webkit_web_view_get_page_id (
+                               WEBKIT_WEB_VIEW (display)),
+                       x, y),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+
+       /* Get URI from saved document */
+       g_dbus_proxy_call (
+               pp_extension->web_extension,
+               "GetDocumentURI",
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               (GAsyncReadyCallback) get_document_uri_cb,
+               extension);
 }
 
 void
@@ -376,6 +509,13 @@ e_mail_display_popup_prefer_plain_dispose (GObject *object)
                extension->action_group = NULL;
        }
 
+       if (extension->web_extension_watch_name_id > 0) {
+               g_bus_unwatch_name (extension->web_extension_watch_name_id);
+               extension->web_extension_watch_name_id = 0;
+       }
+
+       g_clear_object (&extension->web_extension);
+
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_mail_display_popup_prefer_plain_parent_class)->
                dispose (object);
@@ -428,5 +568,7 @@ e_mail_display_popup_prefer_plain_init (EMailDisplayPopupPreferPlain *extension)
        extension->action_group = NULL;
        extension->text_html_id = NULL;
        extension->text_plain_id = NULL;
-       extension->document = NULL;
+       extension->web_extension = NULL;
+
+       mail_display_popup_prefer_plain_watch_web_extension (extension);
 }
diff --git a/modules/prefer-plain/web-extension/Makefile.am b/modules/prefer-plain/web-extension/Makefile.am
new file mode 100644
index 0000000..d11385e
--- /dev/null
+++ b/modules/prefer-plain/web-extension/Makefile.am
@@ -0,0 +1,23 @@
+webextensions_LTLIBRARIES = libmodulepreferplainwebextension.la
+
+libmodulepreferplainwebextension_la_SOURCES =          \
+       module-prefer-plain-web-extension.c             \
+       module-prefer-plain-web-extension.h
+
+libmodulepreferplainwebextension_la_CPPFLAGS =         \
+       $(AM_CPPFLAGS)                                  \
+       -I$(top_srcdir)                                 \
+       $(EVOLUTION_DATA_SERVER_CFLAGS)                 \
+       $(GNOME_PLATFORM_CFLAGS)                        \
+       $(GTKHTML_CFLAGS)                               \
+       $(WEB_EXTENSIONS_CFLAGS)
+
+libmodulepreferplainwebextension_la_LIBADD =           \
+       $(top_builddir)/e-util/libevolution-util.la     \
+       $(EVOLUTION_DATA_SERVER_LIBS)                   \
+       $(GNOME_PLATFORM_LIBS)                          \
+       $(GTKHTML_LIBS)                                 \
+       $(WEB_EXTENSIONS_LIBS)
+
+libmodulepreferplainwebextension_la_LDFLAGS =          \
+       -module -avoid-version -no-undefined
diff --git a/modules/prefer-plain/web-extension/module-prefer-plain-web-extension.c 
b/modules/prefer-plain/web-extension/module-prefer-plain-web-extension.c
new file mode 100644
index 0000000..e83efb0
--- /dev/null
+++ b/modules/prefer-plain/web-extension/module-prefer-plain-web-extension.c
@@ -0,0 +1,176 @@
+/*
+ * module-prefer-plain-web-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "module-prefer-plain-web-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+
+#include <e-util/e-dom-utils.h>
+
+/* FIXME Clean it */
+static GDBusConnection *dbus_connection;
+
+static const char introspection_xml[] =
+"<node>"
+"  <interface name='org.gnome.Evolution.Module.PreferPlain.WebExtension'>"
+"    <method name='ChangeIFrameSource'>"
+"      <arg type='s' name='new_uri' direction='in'/>"
+"    </method>"
+"    <method name='SaveDocumentFromPoint'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='i' name='x' direction='in'/>"
+"      <arg type='i' name='y' direction='in'/>"
+"    </method>"
+"    <method name='GetDocumentURI'>"
+"      <arg type='s' name='document_uri' direction='out'/>"
+"    </method>"
+"  </interface>"
+"</node>";
+
+static WebKitDOMDocument *document_saved = NULL;
+
+static WebKitWebPage *
+get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+                                          WebKitWebExtension *web_extension,
+                                          guint64 page_id)
+{
+       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+       if (!web_page) {
+               g_dbus_method_invocation_return_error (
+                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                       "Invalid page ID: %"G_GUINT64_FORMAT, page_id);
+       }
+       return web_page;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+                    const char *sender,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer user_data)
+{
+       WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+       WebKitWebPage *web_page;
+       WebKitDOMDocument *document;
+       guint64 page_id;
+
+       if (g_strcmp0 (interface_name, MODULE_PREFER_PLAIN_WEB_EXTENSION_INTERFACE) != 0)
+               return;
+
+       if (g_strcmp0 (method_name, "ChangeIFrameSource") == 0) {
+               WebKitDOMDOMWindow *window;
+               WebKitDOMElement *frame_element;
+               const gchar *new_uri;
+
+               g_variant_get (parameters, "(&s)", &new_uri);
+
+               /* Get frame's window and from the window the actual <iframe> element */
+               window = webkit_dom_document_get_default_view (document_saved);
+               frame_element = webkit_dom_dom_window_get_frame_element (window);
+               webkit_dom_html_iframe_element_set_src (
+                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), new_uri);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SaveDocumentFromPoint") == 0) {
+               gint32 x = 0, y = 0;
+
+               g_variant_get (parameters, "(tii)", &page_id, &x, &y);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               document_saved = e_dom_utils_get_document_from_point (document, x, y);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "GetDocumentURI") == 0) {
+               gchar *document_uri;
+
+               if (document_saved)
+                       document_uri = webkit_dom_document_get_document_uri (document_saved);
+               else
+                       document_uri = g_strdup ("");
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", document_uri));
+
+               g_free (document_uri);
+       }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+       handle_method_call,
+       NULL,
+       NULL
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+       guint registration_id;
+       GError *error = NULL;
+       static GDBusNodeInfo *introspection_data = NULL;
+
+       if (!introspection_data)
+               introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+       registration_id =
+               g_dbus_connection_register_object (
+                       connection,
+                       MODULE_PREFER_PLAIN_WEB_EXTENSION_OBJECT_PATH,
+                       introspection_data->interfaces[0],
+                       &interface_vtable,
+                       g_object_ref (user_data),
+                       g_object_unref,
+                       &error);
+
+       if (!registration_id) {
+               g_warning ("Failed to register object: %s\n", error->message);
+               g_error_free (error);
+       } else {
+               dbus_connection = connection;
+               g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+       }
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+       g_bus_own_name (
+               G_BUS_TYPE_SESSION,
+               MODULE_PREFER_PLAIN_WEB_EXTENSION_SERVICE_NAME,
+               G_BUS_NAME_OWNER_FLAGS_NONE,
+               bus_acquired_cb,
+               NULL, NULL,
+               g_object_ref (extension),
+               g_object_unref);
+}
diff --git a/modules/prefer-plain/web-extension/module-prefer-plain-web-extension.h 
b/modules/prefer-plain/web-extension/module-prefer-plain-web-extension.h
new file mode 100644
index 0000000..a50a992
--- /dev/null
+++ b/modules/prefer-plain/web-extension/module-prefer-plain-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ * module-prefer-plain-web-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef MODULE_PREFER_PLAIN_WEB_EXTENSION_H
+#define MODULE_PREFER_PLAIN_WEB_EXTENSION_H
+
+#define MODULE_PREFER_PLAIN_WEB_EXTENSION_SERVICE_NAME "org.gnome.Evolution.Module.PreferPlain.WebExtension"
+#define MODULE_PREFER_PLAIN_WEB_EXTENSION_OBJECT_PATH  "/org/gnome/Evolution/Module/PreferPlain/WebExtension"
+#define MODULE_PREFER_PLAIN_WEB_EXTENSION_INTERFACE    "org.gnome.Evolution.Module.PreferPlain.WebExtension"
+
+#endif /* MODULE_PREFER_PLAIN_WEB_EXTENSION_H */
diff --git a/modules/text-highlight/Makefile.am b/modules/text-highlight/Makefile.am
index ab5df67..2a0f45f 100644
--- a/modules/text-highlight/Makefile.am
+++ b/modules/text-highlight/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = web-extension
+
 module_LTLIBRARIES = module-text-highlight.la
 
 module_text_highlight_la_CPPFLAGS =                                    \
diff --git a/modules/text-highlight/e-mail-display-popup-text-highlight.c 
b/modules/text-highlight/e-mail-display-popup-text-highlight.c
index eb072a0..d90ab27 100644
--- a/modules/text-highlight/e-mail-display-popup-text-highlight.c
+++ b/modules/text-highlight/e-mail-display-popup-text-highlight.c
@@ -23,6 +23,8 @@
 #include <shell/e-shell-window.h>
 #include "mail/e-mail-browser.h"
 
+#include "web-extension/module-text-highlight-web-extension.h"
+
 #include <libebackend/libebackend.h>
 
 #include <glib/gi18n-lib.h>
@@ -36,7 +38,8 @@ typedef struct _EMailDisplayPopupTextHighlight {
 
        GtkActionGroup *action_group;
 
-       WebKitDOMDocument *document;
+       GDBusProxy *web_extension;
+       gint web_extension_watch_name_id;
 } EMailDisplayPopupTextHighlight;
 
 typedef struct _EMailDisplayPopupTextHighlightClass {
@@ -107,33 +110,85 @@ static GtkActionEntry entries[] = {
 };
 
 static void
-reformat (GtkAction *old,
-          GtkAction *action,
-          gpointer user_data)
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+                                GAsyncResult *result,
+                                EMailDisplayPopupTextHighlight *th_extension)
+{
+       GError *error = NULL;
+
+       th_extension->web_extension = g_dbus_proxy_new_finish (result, &error);
+       if (!th_extension->web_extension) {
+               g_warning ("Error creating web extension proxy: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           const gchar *name_owner,
+                           EMailDisplayPopupTextHighlight *th_extension)
+{
+       g_dbus_proxy_new (
+               connection,
+               G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+               G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+               G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+               NULL,
+               name,
+               MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_OBJECT_PATH,
+               MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_INTERFACE,
+               NULL,
+               (GAsyncReadyCallback)web_extension_proxy_created_cb,
+               th_extension);
+}
+
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           EMailDisplayPopupTextHighlight *th_extension)
+{
+       g_clear_object (&th_extension->web_extension);
+}
+
+static void
+mail_display_popup_prefer_plain_watch_web_extension (EMailDisplayPopupTextHighlight *th_extension)
+{
+       th_extension->web_extension_watch_name_id =
+               g_bus_watch_name (
+                       G_BUS_TYPE_SESSION,
+                       MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_SERVICE_NAME,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       (GBusNameAppearedCallback) web_extension_appeared_cb,
+                       (GBusNameVanishedCallback) web_extension_vanished_cb,
+                       th_extension, NULL);
+}
+
+static void
+reformat_get_document_uri_cb (GDBusProxy *web_extension,
+                              GAsyncResult *result,
+                              GtkAction *action)
 {
-       EMailDisplayPopupTextHighlight *th_extension;
-       WebKitDOMDocument *doc;
-       WebKitDOMDOMWindow *window;
-       WebKitDOMElement *frame_element;
        SoupURI *soup_uri;
        GHashTable *query;
        gchar *uri;
+       GVariant *result_variant;
 
-       th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (user_data);
-       doc = th_extension->document;
-       if (!doc)
-               return;
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               const gchar *document_uri;
 
-       uri = webkit_dom_document_get_document_uri (doc);
-       soup_uri = soup_uri_new (uri);
-       g_free (uri);
+               g_variant_get (result_variant, "(&s)", &document_uri);
+               soup_uri = soup_uri_new (document_uri);
+               g_variant_unref (result_variant);
+       }
 
        if (!soup_uri)
-               goto exit;
+               return;
 
        if (!soup_uri->query) {
                soup_uri_free (soup_uri);
-               goto exit;
+               return;
        }
 
        query = soup_form_decode (soup_uri->query);
@@ -149,16 +204,31 @@ reformat (GtkAction *old,
        soup_uri_free (soup_uri);
 
        /* Get frame's window and from the window the actual <iframe> element */
-       window = webkit_dom_document_get_default_view (doc);
-       frame_element = webkit_dom_dom_window_get_frame_element (window);
-       webkit_dom_html_iframe_element_set_src (
-               WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), uri);
+       g_dbus_proxy_call (
+               web_extension,
+               "ChangeIFrameSource",
+               g_variant_new ("(s)", uri),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
        g_free (uri);
 
-       /* The frame has been reloaded, the document pointer is invalid now */
-exit:
-       th_extension->document = NULL;
+       if (!th_extension->web_extension)
+               return;
+
+       /* Get URI from saved document */
+       g_dbus_proxy_call (
+               th_extension->web_extension,
+               "GetDocumentURI",
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               (GAsyncReadyCallback) reformat_get_document_uri_cb,
+               action);
 }
 
 static GtkActionGroup *
@@ -272,34 +342,28 @@ create_group (EMailDisplayPopupExtension *extension)
 }
 
 static void
-update_actions (EMailDisplayPopupExtension *extension,
-                WebKitHitTestResult *context)
+get_document_uri_cb (GDBusProxy *web_extension,
+                     GAsyncResult *result,
+                     EMailDisplayPopupTextHighlight *th_extension)
 {
-       EMailDisplayPopupTextHighlight *th_extension;
-       WebKitDOMNode *node;
-       WebKitDOMDocument *document;
-       gchar *uri;
-
-       th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (extension);
+       GVariant *result_variant;
+       gchar *document_uri;
 
-       if (th_extension->action_group == NULL) {
-               th_extension->action_group = create_group (extension);
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+       if (result_variant) {
+               g_variant_get (result_variant, "(s)", &document_uri);
+               g_variant_unref (result_variant);
        }
 
-       th_extension->document = NULL;
-       g_object_get (G_OBJECT (context), "inner-node", &node, NULL);
-       document = webkit_dom_node_get_owner_document (node);
-       uri = webkit_dom_document_get_document_uri (document);
-
        /* If the part below context menu was made by text-highlight formatter,
         * then try to check what formatter it's using at the moment and set
         * it as active in the popup menu */
-       if (uri && strstr (uri, ".text-highlight") != NULL) {
+       if (document_uri && strstr (document_uri, ".text-highlight") != NULL) {
                SoupURI *soup_uri;
                gtk_action_group_set_visible (
                        th_extension->action_group, TRUE);
 
-               soup_uri = soup_uri_new (uri);
+               soup_uri = soup_uri_new (document_uri);
                if (soup_uri && soup_uri->query) {
                        GHashTable *query = soup_form_decode (soup_uri->query);
                        gchar *highlighter;
@@ -329,12 +393,63 @@ update_actions (EMailDisplayPopupExtension *extension,
                        th_extension->action_group, FALSE);
        }
 
-       /* Set the th_extension->document AFTER changing the active action to
-        * prevent the reformat() from doing some crazy reformatting
-        * (reformat() returns immediatelly when th_extension->document is NULL) */
-       th_extension->document = document;
 
-       g_free (uri);
+       g_free (document_uri);
+}
+
+static void
+update_actions (EMailDisplayPopupExtension *extension)
+{
+       EMailDisplay *display;
+       EMailDisplayPopupTextHighlight *th_extension;
+       gint32 x, y;
+       GdkDeviceManager *device_manager;
+       GdkDevice *pointer;
+
+       display = E_MAIL_DISPLAY (e_extension_get_extensible (
+                       E_EXTENSION (extension)));
+
+       th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (extension);
+
+       if (th_extension->action_group == NULL) {
+               th_extension->action_group = create_group (extension);
+       }
+
+       /* In WK2 you can't get the node on what WebKitHitTest was performed,
+        * we have to use other way */
+       device_manager = gdk_display_get_device_manager (
+               gtk_widget_get_display (GTK_WIDGET(display)));
+       pointer = gdk_device_manager_get_client_pointer (device_manager);
+       gdk_window_get_device_position (
+               gtk_widget_get_window (GTK_WIDGET (display)), pointer, &x, &y, NULL);
+
+       if (!th_extension->web_extension)
+                       return;
+
+       g_dbus_proxy_call (
+               th_extension->web_extension,
+               "SaveDocumentFromPoint",
+               g_variant_new (
+                       "(tii)",
+                       webkit_web_view_get_page_id (
+                               WEBKIT_WEB_VIEW (display)),
+                       x, y),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+
+       /* Get URI from saved document */
+       g_dbus_proxy_call (
+               th_extension->web_extension,
+               "GetDocumentURI",
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               (GAsyncReadyCallback) get_document_uri_cb,
+               th_extension);
 }
 
 void
@@ -370,4 +485,6 @@ static void
 e_mail_display_popup_text_highlight_init (EMailDisplayPopupTextHighlight *extension)
 {
        extension->action_group = NULL;
+
+       mail_display_popup_prefer_plain_watch_web_extension (extension);
 }
diff --git a/modules/text-highlight/web-extension/Makefile.am 
b/modules/text-highlight/web-extension/Makefile.am
new file mode 100644
index 0000000..e9e3faf
--- /dev/null
+++ b/modules/text-highlight/web-extension/Makefile.am
@@ -0,0 +1,23 @@
+webextensions_LTLIBRARIES = libmoduletexthighlightwebextension.la
+
+libmoduletexthighlightwebextension_la_SOURCES =                \
+       module-text-highlight-web-extension.c           \
+       module-text-highlight-web-extension.h
+
+libmoduletexthighlightwebextension_la_CPPFLAGS =       \
+       $(AM_CPPFLAGS)                                  \
+       -I$(top_srcdir)                                 \
+       $(EVOLUTION_DATA_SERVER_CFLAGS)                 \
+       $(GNOME_PLATFORM_CFLAGS)                        \
+       $(GTKHTML_CFLAGS)                               \
+       $(WEB_EXTENSIONS_CFLAGS)
+
+libmoduletexthighlightwebextension_la_LIBADD =         \
+       $(top_builddir)/e-util/libevolution-util.la     \
+       $(EVOLUTION_DATA_SERVER_LIBS)                   \
+       $(GNOME_PLATFORM_LIBS)                          \
+       $(GTKHTML_LIBS)                                 \
+       $(WEB_EXTENSIONS_LIBS)
+
+libmoduletexthighlightwebextension_la_LDFLAGS =                \
+       -module -avoid-version -no-undefined
diff --git a/modules/text-highlight/web-extension/module-text-highlight-web-extension.c 
b/modules/text-highlight/web-extension/module-text-highlight-web-extension.c
new file mode 100644
index 0000000..229b981
--- /dev/null
+++ b/modules/text-highlight/web-extension/module-text-highlight-web-extension.c
@@ -0,0 +1,176 @@
+/*
+ * module-text-highlight-web-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "module-text-highlight-web-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+
+#include <e-util/e-dom-utils.h>
+
+/* FIXME Clean it */
+static GDBusConnection *dbus_connection;
+
+static const char introspection_xml[] =
+"<node>"
+"  <interface name='org.gnome.Evolution.Module.TextHighlight.WebExtension'>"
+"    <method name='ChangeIFrameSource'>"
+"      <arg type='s' name='new_uri' direction='in'/>"
+"    </method>"
+"    <method name='SaveDocumentFromPoint'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='i' name='x' direction='in'/>"
+"      <arg type='i' name='y' direction='in'/>"
+"    </method>"
+"    <method name='GetDocumentURI'>"
+"      <arg type='s' name='document_uri' direction='out'/>"
+"    </method>"
+"  </interface>"
+"</node>";
+
+static WebKitDOMDocument *document_saved = NULL;
+
+static WebKitWebPage *
+get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+                                          WebKitWebExtension *web_extension,
+                                          guint64 page_id)
+{
+       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+       if (!web_page) {
+               g_dbus_method_invocation_return_error (
+                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                       "Invalid page ID: %"G_GUINT64_FORMAT, page_id);
+       }
+       return web_page;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+                    const char *sender,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer user_data)
+{
+       WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+       WebKitWebPage *web_page;
+       WebKitDOMDocument *document;
+       guint64 page_id;
+
+       if (g_strcmp0 (interface_name, MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_INTERFACE) != 0)
+               return;
+
+       if (g_strcmp0 (method_name, "ChangeIFrameSource") == 0) {
+               WebKitDOMDOMWindow *window;
+               WebKitDOMElement *frame_element;
+               const gchar *new_uri;
+
+               g_variant_get (parameters, "(&s)", &new_uri);
+
+               /* Get frame's window and from the window the actual <iframe> element */
+               window = webkit_dom_document_get_default_view (document_saved);
+               frame_element = webkit_dom_dom_window_get_frame_element (window);
+               webkit_dom_html_iframe_element_set_src (
+                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), new_uri);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SaveDocumentFromPoint") == 0) {
+               gint32 x = 0, y = 0;
+
+               g_variant_get (parameters, "(tii)", &page_id, &x, &y);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               document_saved = e_dom_utils_get_document_from_point (document, x, y);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "GetDocumentURI") == 0) {
+               gchar *document_uri;
+
+               if (document_saved)
+                       document_uri = webkit_dom_document_get_document_uri (document_saved);
+               else
+                       document_uri = g_strdup ("");
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", document_uri));
+
+               g_free (document_uri);
+       }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+       handle_method_call,
+       NULL,
+       NULL
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+       guint registration_id;
+       GError *error = NULL;
+       static GDBusNodeInfo *introspection_data = NULL;
+
+       if (!introspection_data)
+               introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+       registration_id =
+               g_dbus_connection_register_object (
+                       connection,
+                       MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_OBJECT_PATH,
+                       introspection_data->interfaces[0],
+                       &interface_vtable,
+                       g_object_ref (user_data),
+                       g_object_unref,
+                       &error);
+
+       if (!registration_id) {
+               g_warning ("Failed to register object: %s\n", error->message);
+               g_error_free (error);
+       } else {
+               dbus_connection = connection;
+               g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+       }
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+       g_bus_own_name (
+               G_BUS_TYPE_SESSION,
+               MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_SERVICE_NAME,
+               G_BUS_NAME_OWNER_FLAGS_NONE,
+               bus_acquired_cb,
+               NULL, NULL,
+               g_object_ref (extension),
+               g_object_unref);
+}
diff --git a/modules/text-highlight/web-extension/module-text-highlight-web-extension.h 
b/modules/text-highlight/web-extension/module-text-highlight-web-extension.h
new file mode 100644
index 0000000..7308f65
--- /dev/null
+++ b/modules/text-highlight/web-extension/module-text-highlight-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ * module-text-highlight-web-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_H
+#define MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_H
+
+#define MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_SERVICE_NAME 
"org.gnome.Evolution.Module.TextHighlight.WebExtension"
+#define MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_OBJECT_PATH  
"/org/gnome/Evolution/Module/TextHighlight/WebExtension"
+#define MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_INTERFACE    
"org.gnome.Evolution.Module.TextHighlight.WebExtension"
+
+#endif /* MODULE_TEXT_HIGHLIGHT_WEB_EXTENSION_H */
diff --git a/modules/vcard-inline/e-mail-formatter-vcard.c b/modules/vcard-inline/e-mail-formatter-vcard.c
index f13d677..40e573c 100644
--- a/modules/vcard-inline/e-mail-formatter-vcard.c
+++ b/modules/vcard-inline/e-mail-formatter-vcard.c
@@ -146,9 +146,12 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                str = g_strdup_printf (
                        "<button type=\"button\" "
                                "name=\"set-display-mode\" "
+                               "id=\"%s\" "
                                "class=\"org-gnome-vcard-display-mode-button\" "
                                "value=\"%d\" "
+                               "style=\"margin-left: 0px\""
                                "accesskey=\"%s\">%s</button>",
+                       e_mail_part_get_id (part),
                        mode, access_key, html_label);
                g_output_stream_write_all (
                        stream, str, strlen (str), NULL, cancellable, NULL);
@@ -166,8 +169,10 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
                                "class=\"org-gnome-vcard-save-button\" "
                                "value=\"%s\" "
                                "accesskey=\"%s\">%s</button><br>"
-                       "<iframe width=\"100%%\" height=\"auto\" frameborder=\"0\""
-                               "src=\"%s\" name=\"%s\"></iframe>"
+                               "<iframe width=\"100%%\" height=\"auto\" "
+                               " class=\"-e-mail-formatter-frame-color -e-web-view-background-color\" "
+                               " style=\"border: 1px solid;\""
+                               " src=\"%s\" name=\"%s\"></iframe>"
                        "</div>",
                        e_mail_part_get_id (part),
                        access_key, html_label, uri,
diff --git a/modules/vcard-inline/e-mail-part-vcard.c b/modules/vcard-inline/e-mail-part-vcard.c
index 4335f30..4768295 100644
--- a/modules/vcard-inline/e-mail-part-vcard.c
+++ b/modules/vcard-inline/e-mail-part-vcard.c
@@ -32,6 +32,12 @@
 
 struct _EMailPartVCardPrivate {
        gint placeholder;
+
+       guint display_mode_toggled_signal_id;
+       guint save_vcard_button_pressed_signal_id;
+
+       GDBusProxy *web_extension;
+       guint64 page_id;
 };
 
 G_DEFINE_DYNAMIC_TYPE (
@@ -85,8 +91,12 @@ client_connect_cb (GObject *source_object,
 }
 
 static void
-save_vcard_cb (WebKitDOMEventTarget *button,
-               WebKitDOMEvent *event,
+save_vcard_cb (GDBusConnection *connection,
+               const gchar *sender_name,
+               const gchar *object_path,
+               const gchar *interface_name,
+               const gchar *signal_name,
+               GVariant *parameters,
                EMailPartVCard *vcard_part)
 {
        EShell *shell;
@@ -94,9 +104,19 @@ save_vcard_cb (WebKitDOMEventTarget *button,
        ESourceRegistry *registry;
        ESourceSelector *selector;
        GSList *contact_list;
-       const gchar *extension_name;
+       const gchar *extension_name, *button_value, *part_id;
        GtkWidget *dialog;
 
+       if (g_strcmp0 (signal_name, "VCardInlineSaveButtonPressed") != 0)
+               return;
+
+       g_variant_get (parameters, "(&s)", &button_value);
+
+       part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
+
+       if (!strstr (part_id, button_value))
+               return;
+
        shell = e_shell_get_default ();
        registry = e_shell_get_registry (shell);
        extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
@@ -131,8 +151,12 @@ save_vcard_cb (WebKitDOMEventTarget *button,
 }
 
 static void
-display_mode_toggle_cb (WebKitDOMEventTarget *button,
-                        WebKitDOMEvent *event,
+display_mode_toggle_cb (GDBusConnection *connection,
+                        const gchar *sender_name,
+                        const gchar *object_path,
+                        const gchar *interface_name,
+                        const gchar *signal_name,
+                        GVariant *parameters,
                         EMailPartVCard *vcard_part)
 {
        EABContactDisplayMode mode;
@@ -140,47 +164,54 @@ display_mode_toggle_cb (WebKitDOMEventTarget *button,
        gchar *html_label;
        gchar *access_key;
        const gchar *part_id;
+       const gchar *button_id;
+
+       if (g_strcmp0 (signal_name, "VCardInlineDisplayModeToggled") != 0)
+               return;
+
+       if (!vcard_part->priv->web_extension)
+               return;
+
+       g_variant_get (parameters, "(&s)", &button_id);
 
        part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
 
+       if (!strstr (part_id, button_id))
+               return;
+
        mode = eab_contact_formatter_get_display_mode (vcard_part->formatter);
        if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
                mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
 
                html_label = e_mail_formatter_parse_html_mnemonics (
                                _("Show F_ull vCard"), &access_key);
-
-               webkit_dom_html_element_set_inner_html (
-                       WEBKIT_DOM_HTML_ELEMENT (button),
-                       html_label, NULL);
-               if (access_key) {
-                       webkit_dom_html_element_set_access_key (
-                               WEBKIT_DOM_HTML_ELEMENT (button),
-                               access_key);
-                       g_free (access_key);
-               }
-
-               g_free (html_label);
-
        } else {
                mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
 
                html_label = e_mail_formatter_parse_html_mnemonics (
                                _("Show Com_pact vCard"), &access_key);
-
-               webkit_dom_html_element_set_inner_html (
-                       WEBKIT_DOM_HTML_ELEMENT (button),
-                       html_label, NULL);
-               if (access_key) {
-                       webkit_dom_html_element_set_access_key (
-                               WEBKIT_DOM_HTML_ELEMENT (button),
-                               access_key);
-                       g_free (access_key);
-               }
-
-               g_free (html_label);
        }
 
+       g_dbus_proxy_call (
+               vcard_part->priv->web_extension,
+               "VCardInlineUpdateButton",
+               g_variant_new (
+                       "(tsss)",
+                       vcard_part->priv->page_id,
+                       button_id,
+                       html_label,
+                       access_key),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+
+       if (access_key)
+               g_free (access_key);
+
+       g_free (html_label);
+
        eab_contact_formatter_set_display_mode (vcard_part->formatter, mode);
 
        uri = e_mail_part_build_uri (
@@ -188,8 +219,19 @@ display_mode_toggle_cb (WebKitDOMEventTarget *button,
                "part_id", G_TYPE_STRING, part_id,
                "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL);
 
-       webkit_dom_html_iframe_element_set_src (
-               WEBKIT_DOM_HTML_IFRAME_ELEMENT (vcard_part->iframe), uri);
+       g_dbus_proxy_call (
+               vcard_part->priv->web_extension,
+               "VCardInlineSetIFrameSrc",
+               g_variant_new (
+                       "(tss)",
+                       vcard_part->priv->page_id,
+                       button_id,
+                       uri),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 
        g_free (uri);
 }
@@ -202,11 +244,22 @@ mail_part_vcard_dispose (GObject *object)
        g_clear_object (&part->contact_display);
        g_clear_object (&part->message_label);
        g_clear_object (&part->formatter);
-       g_clear_object (&part->iframe);
-       g_clear_object (&part->save_button);
-       g_clear_object (&part->toggle_button);
        g_clear_object (&part->folder);
 
+       if (part->priv->display_mode_toggled_signal_id > 0) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (part->priv->web_extension),
+                       part->priv->display_mode_toggled_signal_id);
+               part->priv->display_mode_toggled_signal_id = 0;
+       }
+
+       if (part->priv->save_vcard_button_pressed_signal_id > 0) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (part->priv->web_extension),
+                       part->priv->save_vcard_button_pressed_signal_id);
+               part->priv->save_vcard_button_pressed_signal_id = 0;
+       }
+
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->dispose (object);
 }
@@ -249,60 +302,55 @@ mail_part_vcard_constructed (GObject *object)
 
 static void
 mail_part_vcard_bind_dom_element (EMailPart *part,
-                                  WebKitDOMElement *element)
+                                  GDBusProxy *evolution_web_extension,
+                                  guint64 page_id,
+                                  const gchar *element_id)
 {
        EMailPartVCard *vcard_part;
-       WebKitDOMNodeList *list;
-       WebKitDOMElement *iframe;
-       WebKitDOMElement *toggle_button;
-       WebKitDOMElement *save_button;
 
        vcard_part = E_MAIL_PART_VCARD (part);
 
-       /* IFRAME */
-       list = webkit_dom_element_get_elements_by_tag_name (
-               element, "iframe");
-       if (webkit_dom_node_list_get_length (list) != 1)
-               return;
-       iframe = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
-       g_clear_object (&vcard_part->iframe);
-       vcard_part->iframe = g_object_ref (iframe);
-       g_object_unref (list);
-
-       /* TOGGLE DISPLAY MODE BUTTON */
-       list = webkit_dom_element_get_elements_by_class_name (
-               element, "org-gnome-vcard-display-mode-button");
-       if (webkit_dom_node_list_get_length (list) != 1)
-               return;
-       toggle_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
-       g_clear_object (&vcard_part->toggle_button);
-       vcard_part->toggle_button = g_object_ref (toggle_button);
-       g_object_unref (list);
-
-       /* SAVE TO ADDRESSBOOK BUTTON */
-       list = webkit_dom_element_get_elements_by_class_name (
-               element, "org-gnome-vcard-save-button");
-       if (webkit_dom_node_list_get_length (list) != 1)
-               return;
-       save_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
-       g_clear_object (&vcard_part->save_button);
-       vcard_part->save_button = g_object_ref (save_button);
-       g_object_unref (list);
-
-       webkit_dom_event_target_add_event_listener (
-               WEBKIT_DOM_EVENT_TARGET (toggle_button),
-               "click", G_CALLBACK (display_mode_toggle_cb),
-               FALSE, vcard_part);
-
-       webkit_dom_event_target_add_event_listener (
-               WEBKIT_DOM_EVENT_TARGET (save_button),
-               "click", G_CALLBACK (save_vcard_cb),
-               FALSE, vcard_part);
-
-       /* Bind collapse buttons for contact lists. */
-       eab_contact_formatter_bind_dom (
-               webkit_dom_html_iframe_element_get_content_document (
-                       WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)));
+       vcard_part->priv->web_extension = evolution_web_extension;
+       vcard_part->priv->page_id = page_id;
+
+       vcard_part->priv->display_mode_toggled_signal_id =
+               g_dbus_connection_signal_subscribe (
+                       g_dbus_proxy_get_connection (evolution_web_extension),
+                       g_dbus_proxy_get_name (evolution_web_extension),
+                       g_dbus_proxy_get_interface_name (evolution_web_extension),
+                       "VCardInlineDisplayModeToggled",
+                       g_dbus_proxy_get_object_path (evolution_web_extension),
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       (GDBusSignalCallback) display_mode_toggle_cb,
+                       vcard_part,
+                       NULL);
+
+       vcard_part->priv->save_vcard_button_pressed_signal_id =
+               g_dbus_connection_signal_subscribe (
+                       g_dbus_proxy_get_connection (evolution_web_extension),
+                       g_dbus_proxy_get_name (evolution_web_extension),
+                       g_dbus_proxy_get_interface_name (evolution_web_extension),
+                       "VCardInlineSaveButtonPressed",
+                       g_dbus_proxy_get_object_path (evolution_web_extension),
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       (GDBusSignalCallback) save_vcard_cb,
+                       vcard_part,
+                       NULL);
+
+       g_dbus_proxy_call (
+               vcard_part->priv->web_extension,
+               "VCardInlineBindDOM",
+               g_variant_new (
+                       "(ts)",
+                       vcard_part->priv->page_id,
+                       element_id),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
 }
 
 static void
diff --git a/modules/vcard-inline/e-mail-part-vcard.h b/modules/vcard-inline/e-mail-part-vcard.h
index d9409c5..9aeb595 100644
--- a/modules/vcard-inline/e-mail-part-vcard.h
+++ b/modules/vcard-inline/e-mail-part-vcard.h
@@ -21,7 +21,6 @@
 #include <em-format/e-mail-part.h>
 
 #include <addressbook/gui/widgets/eab-contact-formatter.h>
-#include <webkit/webkitdom.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_PART_VCARD \
@@ -57,9 +56,6 @@ struct _EMailPartVCard {
        GtkWidget *message_label;
 
        EABContactFormatter *formatter;
-       WebKitDOMElement *iframe;
-       WebKitDOMElement *toggle_button;
-       WebKitDOMElement *save_button;
 
        CamelFolder *folder;
        gchar *message_uid;
diff --git a/modules/web-inspector/evolution-web-inspector.c b/modules/web-inspector/evolution-web-inspector.c
index 6ccba80..fd8606a 100644
--- a/modules/web-inspector/evolution-web-inspector.c
+++ b/modules/web-inspector/evolution-web-inspector.c
@@ -85,51 +85,24 @@ web_inspector_key_press_event_cb (WebKitWebView *web_view,
        return handled;
 }
 
-static WebKitWebView *
-web_inspector_inspect_web_view_cb (WebKitWebInspector *inspector)
-{
-       GtkWidget *web_view;
-       GtkWidget *window;
-       const gchar *title;
-
-       title = _("Evolution Web Inspector");
-       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-       gtk_window_set_title (GTK_WINDOW (window), title);
-       gtk_widget_set_size_request (window, 600, 400);
-       gtk_widget_show (window);
-
-       web_view = webkit_web_view_new ();
-       gtk_container_add (GTK_CONTAINER (window), web_view);
-       gtk_widget_show (web_view);
-
-       return WEBKIT_WEB_VIEW (web_view);
-}
-
 static void
 web_inspector_constructed (GObject *object)
 {
        EWebInspector *extension;
        WebKitWebView *web_view;
-       WebKitWebSettings *settings;
-       WebKitWebInspector *inspector;
+       WebKitSettings *settings;
 
        /* Chain up to parent's method. */
        G_OBJECT_CLASS (e_web_inspector_parent_class)->constructed (object);
 
        extension = E_WEB_INSPECTOR (object);
        web_view = web_inspector_get_web_view (extension);
-       settings = webkit_web_view_get_settings (web_view);
-       inspector = webkit_web_view_get_inspector (web_view);
-
-       g_object_set (settings, "enable-developer-extras", TRUE, NULL);
++      settings = webkit_web_view_get_settings (web_view);
+       webkit_settings_set_enable_developer_extras (settings, TRUE);
 
        g_signal_connect (
                web_view, "key-press-event",
                G_CALLBACK (web_inspector_key_press_event_cb), NULL);
-
-       g_signal_connect (
-               inspector, "inspect-web-view",
-               G_CALLBACK (web_inspector_inspect_web_view_cb), NULL);
 }
 
 static void
diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c
index 065df23..a07feed 100644
--- a/plugins/mail-to-task/mail-to-task.c
+++ b/plugins/mail-to-task/mail-to-task.c
@@ -828,7 +828,7 @@ typedef struct {
        ECalClientSourceType source_type;
        CamelFolder *folder;
        GPtrArray *uids;
-       gchar *selected_text;
+       const gchar *selected_text;
        gboolean with_attendees;
 }AsyncData;
 
@@ -1037,7 +1037,6 @@ do_mail_to_event (AsyncData *data)
        g_object_unref (folder);
 
        g_object_unref (data->source);
-       g_free (data->selected_text);
        g_free (data);
        data = NULL;
 
@@ -1073,24 +1072,21 @@ text_contains_nonwhitespace (const gchar *text,
        return p - text < len - 1 && c != 0;
 }
 
-/* should be freed with g_free after done with it */
-static gchar *
+static const gchar *
 get_selected_text (EMailReader *reader)
 {
        EMailDisplay *display;
-       gchar *text = NULL;
+       const gchar *text = NULL;
 
        display = e_mail_reader_get_mail_display (reader);
 
        if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
                return NULL;
 
-       text = e_mail_display_get_selection_plain_text (display);
+       text = e_mail_display_get_selection_plain_text_sync (display, NULL, NULL);
 
-       if (text == NULL || !text_contains_nonwhitespace (text, strlen (text))) {
-               g_free (text);
+       if (text == NULL || !text_contains_nonwhitespace (text, strlen (text)))
                return NULL;
-       }
 
        return text;
 }
@@ -1203,6 +1199,7 @@ mail_to_event (ECalClientSourceType source_type,
                data->uids = g_ptr_array_ref (uids);
                data->with_attendees = with_attendees;
 
+               /* FIXME XXX WK2 move data->selected_text to const gchar * */
                if (uids->len == 1)
                        data->selected_text = get_selected_text (reader);
                else
diff --git a/shell/main.c b/shell/main.c
index 972c0bd..0bc42d4 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -52,7 +52,7 @@
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
 
 #include "e-shell.h"
 #include "e-shell-migrate.h"
@@ -571,6 +571,7 @@ main (gint argc,
        g_object_unref (settings);
 #endif
 
+       /* FIXME XXX WK2 - Look if we still need this it looks like it's not. */
        /* Workaround https://bugzilla.gnome.org/show_bug.cgi?id=683548 */
        if (!quit)
                g_type_ensure (WEBKIT_TYPE_WEB_VIEW);
diff --git a/web-extensions/Makefile.am b/web-extensions/Makefile.am
new file mode 100644
index 0000000..3577cfb
--- /dev/null
+++ b/web-extensions/Makefile.am
@@ -0,0 +1,23 @@
+webextensions_LTLIBRARIES = libevolutionwebextension.la
+
+libevolutionwebextension_la_SOURCES =                  \
+       evolution-web-extension.c                       \
+       evolution-web-extension.h
+
+libevolutionwebextension_la_CPPFLAGS =                 \
+       $(AM_CPPFLAGS)                                  \
+       -I$(top_srcdir)                                 \
+       $(EVOLUTION_DATA_SERVER_CFLAGS)                 \
+       $(GNOME_PLATFORM_CFLAGS)                        \
+       $(GTKHTML_CFLAGS)                               \
+       $(WEB_EXTENSIONS_CFLAGS)
+
+libevolutionwebextension_la_LIBADD =                   \
+       $(top_builddir)/e-util/libevolution-util.la     \
+       $(EVOLUTION_DATA_SERVER_LIBS)                   \
+       $(GNOME_PLATFORM_LIBS)                          \
+       $(GTKHTML_LIBS)                                 \
+       $(WEB_EXTENSIONS_LIBS)
+
+libevolutionwebextension_la_LDFLAGS =                  \
+       -module -avoid-version -no-undefined
diff --git a/web-extensions/evolution-web-extension.c b/web-extensions/evolution-web-extension.c
new file mode 100644
index 0000000..908e79e
--- /dev/null
+++ b/web-extensions/evolution-web-extension.c
@@ -0,0 +1,636 @@
+/*
+ * evolution-web-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "evolution-web-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include <libemail-engine/e-mail-enums.h>
+
+#include <string.h>
+
+#include <e-util/e-dom-utils.h>
+#include <libedataserver/libedataserver.h>
+
+/* FIXME Clean it */
+static GDBusConnection *dbus_connection;
+static gboolean need_input = FALSE;
+static gboolean force_image_load = FALSE;
+static CamelDataCache *emd_global_http_cache = NULL;
+
+static const char introspection_xml[] =
+"<node>"
+"  <interface name='org.gnome.Evolution.WebExtension'>"
+"    <signal name='HeadersCollapsed'>"
+"      <arg type='b' name='expanded' direction='out'/>"
+"    </signal>"
+"    <method name='ReplaceLocalImageLinks'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"    </method>"
+"    <method name='GetDocumentContentHTML'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='html_content' direction='out'/>"
+"    </method>"
+"    <method name='GetSelectionContentHTML'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='html_content' direction='out'/>"
+"    </method>"
+"    <method name='GetSelectionContentText'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='text_content' direction='out'/>"
+"    </method>"
+"    <method name='CreateAndAddCSSStyleSheet'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='style_sheet_id' direction='in'/>"
+"    </method>"
+"    <method name='AddCSSRuleIntoStyleSheet'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='style_sheet_id' direction='in'/>"
+"      <arg type='s' name='selector' direction='in'/>"
+"      <arg type='s' name='style' direction='in'/>"
+"    </method>"
+"    <method name='EABContactFormatterBindDOM'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"    </method>"
+"    <method name='EMailDisplayBindDOM'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"    </method>"
+"    <method name='ElementExists'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='b' name='element_exists' direction='out'/>"
+"      <arg type='t' name='page_id' direction='out'/>"
+"    </method>"
+"    <method name='GetActiveElementName'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_name' direction='out'/>"
+"    </method>"
+"    <method name='EMailPartHeadersBindDOMElement'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"    </method>"
+"    <signal name='VCardInlineDisplayModeToggled'>"
+"      <arg type='s' name='button_id' direction='out'/>"
+"    </signal>"
+"    <signal name='VCardInlineSaveButtonPressed'>"
+"      <arg type='s' name='button_value' direction='out'/>"
+"    </signal>"
+"    <method name='VCardInlineBindDOM'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"    </method>"
+"    <method name='VCardInlineUpdateButton'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='button_id' direction='in'/>"
+"      <arg type='s' name='html_label' direction='in'/>"
+"      <arg type='s' name='access_key' direction='in'/>"
+"    </method>"
+"    <method name='VCardInlineSetIFrameSrc'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='button_id' direction='in'/>"
+"      <arg type='s' name='src' direction='in'/>"
+"    </method>"
+"    <property type='b' name='NeedInput' access='readwrite'/>"
+"    <property type='b' name='ForceImageLoad' access='readwrite'/>"
+"  </interface>"
+"</node>";
+
+static gboolean
+image_exists_in_cache (const gchar *image_uri)
+{
+       gchar *filename;
+       gchar *hash;
+       gboolean exists = FALSE;
+
+       g_return_val_if_fail (emd_global_http_cache != NULL, FALSE);
+
+       hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, image_uri, -1);
+       filename = camel_data_cache_get_filename (
+               emd_global_http_cache, "http", hash);
+
+       if (filename != NULL) {
+               exists = g_file_test (filename, G_FILE_TEST_EXISTS);
+               g_free (filename);
+       }
+
+       g_free (hash);
+
+       return exists;
+}
+
+static EMailImageLoadingPolicy
+get_image_loading_policy (void)
+{
+       GSettings *settings;
+       EMailImageLoadingPolicy image_policy;
+
+       settings = g_settings_new ("org.gnome.evolution.mail");
+       image_policy = g_settings_get_enum (settings, "image-loading-policy");
+       g_object_unref (settings);
+
+       return image_policy;
+}
+
+static void
+redirect_http_uri (WebKitWebPage *web_page,
+                   WebKitURIRequest *request)
+{
+       const gchar *uri, *page_uri;
+       gchar *new_uri, *mail_uri, *enc;
+       SoupURI *soup_uri;
+       GHashTable *query;
+       gboolean image_exists;
+       EMailImageLoadingPolicy image_policy;
+
+       uri = webkit_uri_request_get_uri (request);
+       page_uri = webkit_web_page_get_uri (web_page);
+
+       /* Check Evolution's cache */
+       image_exists = image_exists_in_cache (uri);
+
+       /* If the URI is not cached and we are not allowed to load it
+        * then redirect to invalid URI, so that webkit would display
+        * a native placeholder for it. */
+       image_policy = get_image_loading_policy ();
+       if (!image_exists && !force_image_load &&
+           (image_policy == E_MAIL_IMAGE_LOADING_POLICY_NEVER)) {
+               webkit_uri_request_set_uri (request, "about:blank");
+               return;
+       }
+
+       new_uri = g_strconcat ("evo-", uri, NULL);
+       mail_uri = g_strndup (page_uri, strstr (page_uri, "?") - page_uri);
+
+       soup_uri = soup_uri_new (new_uri);
+       if (soup_uri->query)
+               query = soup_form_decode (soup_uri->query);
+       else
+               query = g_hash_table_new_full (
+                       g_str_hash, g_str_equal,
+                       g_free, g_free);
+
+       enc = soup_uri_encode (mail_uri, NULL);
+       g_hash_table_insert (query, g_strdup ("__evo-mail"), enc);
+
+       if (force_image_load) {
+               g_hash_table_insert (
+                       query,
+                       g_strdup ("__evo-load-images"),
+                       g_strdup ("true"));
+       }
+
+       g_free (mail_uri);
+
+       soup_uri_set_query_from_form (soup_uri, query);
+       g_free (new_uri);
+
+       new_uri = soup_uri_to_string (soup_uri, FALSE);
+
+       webkit_uri_request_set_uri (request, new_uri);
+
+       soup_uri_free (soup_uri);
+       g_hash_table_unref (query);
+       g_free (new_uri);
+}
+
+static gboolean
+web_page_send_request (WebKitWebPage *web_page,
+                       WebKitURIRequest *request,
+                       WebKitURIResponse *redirected_response,
+                       gpointer user_data)
+{
+       const char *request_uri;
+       const char *page_uri;
+       gboolean uri_is_http;
+
+       request_uri = webkit_uri_request_get_uri (request);
+       page_uri = webkit_web_page_get_uri (web_page);
+
+       /* Always load the main resource. */
+       if (g_strcmp0 (request_uri, page_uri) == 0)
+               return FALSE;
+
+       uri_is_http =
+               g_str_has_prefix (request_uri, "http:") ||
+               g_str_has_prefix (request_uri, "https:") ||
+               g_str_has_prefix (request_uri, "evo-http:") ||
+               g_str_has_prefix (request_uri, "evo-https:");
+
+       if (uri_is_http)
+               redirect_http_uri (web_page, request);
+
+       return FALSE;
+}
+
+static void
+web_page_document_loaded (WebKitWebPage *web_page,
+                          gpointer user_data)
+{
+
+}
+
+static void
+web_page_created_callback (WebKitWebExtension *extension,
+                           WebKitWebPage *web_page,
+                           gpointer user_data)
+{
+       g_signal_connect_object (
+               web_page, "send-request",
+               G_CALLBACK (web_page_send_request),
+               NULL, 0);
+
+       g_signal_connect_object (
+               web_page, "document-loaded",
+               G_CALLBACK (web_page_document_loaded),
+               NULL, 0);
+
+}
+
+static WebKitWebPage *
+get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+                                          WebKitWebExtension *web_extension,
+                                          guint64 page_id)
+{
+       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+       if (!web_page) {
+               g_dbus_method_invocation_return_error (
+                       invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                       "Invalid page ID: %"G_GUINT64_FORMAT, page_id);
+       }
+       return web_page;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+                    const char *sender,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer user_data)
+{
+       WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+       WebKitWebPage *web_page;
+       WebKitDOMDocument *document;
+       guint64 page_id;
+
+       if (g_strcmp0 (interface_name, EVOLUTION_WEB_EXTENSION_INTERFACE) != 0)
+               return;
+
+       if (g_strcmp0 (method_name, "ReplaceLocalImageLinks") == 0) {
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_replace_local_image_links (document);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "GetDocumentContentHTML") == 0) {
+               gchar *html_content;
+
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               html_content = e_dom_utils_get_document_content_html (document);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", html_content));
+
+               g_free (html_content);
+       } else if (g_strcmp0 (method_name, "GetSelectionContentHTML") == 0) {
+               gchar *html_content;
+
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               html_content = e_dom_utils_get_selection_content_html (document);
+
+               g_dbus_method_invocation_return_value (invocation,
+                       g_variant_new ("(s)", html_content));
+
+               g_free (html_content);
+       } else if (g_strcmp0 (method_name, "GetSelectionContentText") == 0) {
+               gchar *text_content;
+
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               text_content = e_dom_utils_get_selection_content_html (document);
+
+               g_dbus_method_invocation_return_value (invocation,
+                       g_variant_new ("(s)", text_content));
+
+               g_free (text_content);
+       } else if (g_strcmp0 (method_name, "AddCSSRuleIntoStyleSheet") == 0) {
+               const gchar *style_sheet_id, *selector, *style;
+
+               g_variant_get (
+                       parameters,
+                       "(t&s&s&s)",
+                       &page_id, &style_sheet_id, &selector, &style);
+
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_add_css_rule_into_style_sheet (document, style_sheet_id, selector, style);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "CreateAndAddCSSStyleSheet") == 0) {
+               const gchar *style_sheet_id;
+
+               g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_create_and_add_css_style_sheet (document, style_sheet_id);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "EABContactFormatterBindDOM") == 0) {
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_eab_contact_formatter_bind_dom (document);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "EMailDisplayBindDOM") == 0) {
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_e_mail_display_bind_dom (document, connection);
+               e_dom_utils_bind_focus_on_elements (document, connection);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "ElementExists") == 0) {
+               const gchar *element_id;
+               gboolean element_exists;
+
+               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               element_exists = e_dom_utils_element_exists (document, element_id);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(bt)", element_exists, page_id));
+       } else if (g_strcmp0 (method_name, "GetActiveElementName") == 0) {
+               gchar *element_name;
+
+               g_variant_get (parameters, "(t)", &page_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               element_name = e_dom_utils_get_active_element_name (document);
+
+               g_dbus_method_invocation_return_value (
+                       invocation, g_variant_new ("(s)", element_name));
+
+               g_free (element_name);
+       } else if (g_strcmp0 (method_name, "EMailPartHeadersBindDOMElement") == 0) {
+               const gchar *element_id;
+
+               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_e_mail_part_headers_bind_dom_element (document, element_id);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "VCardInlineBindDOM") == 0) {
+               const gchar *element_id;
+
+               g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_module_vcard_inline_bind_dom (
+                       document, element_id, connection);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "VCardInlineUpdateButton") == 0) {
+               const gchar *button_id, *html_label, *access_key;
+
+               g_variant_get (
+                       parameters,
+                       "(t&s&s&s)",
+                       &page_id, &button_id, &html_label, &access_key);
+
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_module_vcard_inline_update_button (
+                       document, button_id, html_label, access_key);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "VCardInlineSetIFrameSrc") == 0) {
+               const gchar *src, *button_id;
+
+               g_variant_get (parameters, "(t&s&s)", &page_id, &button_id, &src);
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               document = webkit_web_page_get_dom_document (web_page);
+               e_dom_utils_module_vcard_inline_set_iframe_src (document, button_id, src);
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       }
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+                     const gchar *sender,
+                     const gchar *object_path,
+                     const gchar *interface_name,
+                     const gchar *property_name,
+                     GError **error,
+                     gpointer user_data)
+{
+       GVariant *variant;
+
+       if (g_strcmp0 (property_name, "NeedInput") == 0) {
+               variant = g_variant_new_boolean (need_input);
+       } else if (g_strcmp0 (property_name, "ForceImageLoad") == 0) {
+               variant = g_variant_new_boolean (force_image_load);
+       }
+
+       return variant;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+                     const gchar *sender,
+                     const gchar *object_path,
+                     const gchar *interface_name,
+                     const gchar *property_name,
+                     GVariant *variant,
+                     GError **error,
+                     gpointer user_data)
+{
+       GError *local_error = NULL;
+       GVariantBuilder *builder;
+
+       builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+
+       if (g_strcmp0 (property_name, "NeedInput") == 0) {
+               gboolean value = g_variant_get_boolean (variant);
+
+               if (value == need_input)
+                       goto exit;
+
+               need_input = value;
+
+               g_variant_builder_add (builder,
+                       "{sv}",
+                       "NeedInput",
+                       g_variant_new_boolean (need_input));
+       } else if (g_strcmp0 (property_name, "ForceImageLoad") == 0) {
+               gboolean value = g_variant_get_boolean (variant);
+
+               if (value == force_image_load)
+                       goto exit;
+
+               force_image_load = value;
+
+               g_variant_builder_add (builder,
+                       "{sv}",
+                       "ForceImageLoad",
+                       g_variant_new_boolean (force_image_load));
+       }
+
+       g_dbus_connection_emit_signal (connection,
+               NULL,
+               object_path,
+               "org.freedesktop.DBus.Properties",
+               "PropertiesChanged",
+               g_variant_new (
+                       "(sa{sv}as)",
+                       interface_name,
+                       builder,
+                       NULL),
+               &local_error);
+
+       g_assert_no_error (local_error);
+
+ exit:
+       g_variant_builder_unref (builder);
+
+       return TRUE;
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+       handle_method_call,
+       handle_get_property,
+       handle_set_property
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+       guint registration_id;
+       GError *error = NULL;
+       static GDBusNodeInfo *introspection_data = NULL;
+
+       if (!introspection_data)
+               introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+       registration_id =
+               g_dbus_connection_register_object (
+                       connection,
+                       EVOLUTION_WEB_EXTENSION_OBJECT_PATH,
+                       introspection_data->interfaces[0],
+                       &interface_vtable,
+                       g_object_ref (user_data),
+                       g_object_unref,
+                       &error);
+
+       if (!registration_id) {
+               g_warning ("Failed to register object: %s\n", error->message);
+               g_error_free (error);
+       } else {
+               dbus_connection = connection;
+               g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+
+               if (emd_global_http_cache == NULL) {
+                       emd_global_http_cache = camel_data_cache_new (
+                               e_get_user_cache_dir (), NULL);
+
+                       /* cache expiry - 2 hour access, 1 day max */
+                       camel_data_cache_set_expire_age (
+                               emd_global_http_cache, 24 * 60 * 60);
+                       camel_data_cache_set_expire_access (
+                               emd_global_http_cache, 2 * 60 * 60);
+               }
+       }
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+       g_signal_connect (
+               extension, "page-created",
+               G_CALLBACK (web_page_created_callback),
+               NULL);
+
+       g_bus_own_name (
+               G_BUS_TYPE_SESSION,
+               EVOLUTION_WEB_EXTENSION_SERVICE_NAME,
+               G_BUS_NAME_OWNER_FLAGS_NONE,
+               bus_acquired_cb,
+               NULL, NULL,
+               g_object_ref (extension),
+               g_object_unref);
+}
diff --git a/web-extensions/evolution-web-extension.h b/web-extensions/evolution-web-extension.h
new file mode 100644
index 0000000..ccee49f
--- /dev/null
+++ b/web-extensions/evolution-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ * evolution-web-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EVOLUTION_WEB_EXTENSION_H
+#define EVOLUTION_WEB_EXTENSION_H
+
+#define EVOLUTION_WEB_EXTENSION_SERVICE_NAME "org.gnome.Evolution.WebExtension"
+#define EVOLUTION_WEB_EXTENSION_OBJECT_PATH  "/org/gnome/Evolution/WebExtension"
+#define EVOLUTION_WEB_EXTENSION_INTERFACE    "org.gnome.Evolution.WebExtension"
+
+#endif /* EVOLUTION_WEB_EXTENSION_H */


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