[evince/gpoo/revert-browser: 1/2] Revert "browser-plugin: Remove browser-plugin support"



commit e060c5ae937c3d35f69b72741c45d4bd036d2efa
Author: Germán Poo-Caamaño <gpoo gnome org>
Date:   Thu Jan 31 00:16:28 2019 -0300

    Revert "browser-plugin: Remove browser-plugin support"
    
    This reverts commit f620476809ec6157b312b2f787bbed4d95850b53.
    
    Reverting the browser-plugin as I became aware of actual
    users of this feature.

 Makefile.am                                  |   4 +
 browser-plugin/EvBrowserPlugin.cpp           | 746 ++++++++++++++++++++++
 browser-plugin/EvBrowserPlugin.gresource.xml |  23 +
 browser-plugin/EvBrowserPlugin.h             | 109 ++++
 browser-plugin/EvBrowserPluginMain.cpp       | 362 +++++++++++
 browser-plugin/EvBrowserPluginToolbar.cpp    | 495 +++++++++++++++
 browser-plugin/EvBrowserPluginToolbar.h      |  54 ++
 browser-plugin/EvMemoryUtils.h               |  33 +
 browser-plugin/Makefile.am                   |  67 ++
 browser-plugin/evince-browser.css            |  19 +
 browser-plugin/meson.build                   |  55 ++
 browser-plugin/npapi/npapi.h                 | 914 +++++++++++++++++++++++++++
 browser-plugin/npapi/npfunctions.h           | 307 +++++++++
 browser-plugin/npapi/npruntime.h             | 393 ++++++++++++
 browser-plugin/npapi/nptypes.h               |  88 +++
 browser-plugin/plugin.symbols                |   4 +
 browser-plugin/tests/data-uri.html           |  12 +
 browser-plugin/tests/iframe.html             |  15 +
 browser-plugin/tests/initvalues.html         |  32 +
 browser-plugin/tests/local.html              |  12 +
 browser-plugin/tests/multiple.html           |  17 +
 browser-plugin/tests/remote.html             |  12 +
 browser-plugin/tests/script.html             |  59 ++
 browser-plugin/tests/test.pdf                | Bin 0 -> 9030 bytes
 configure.ac                                 |  27 +
 meson.build                                  |  12 +
 po/POTFILES.in                               |   1 +
 27 files changed, 3872 insertions(+)
---
diff --git a/Makefile.am b/Makefile.am
index f857f6b1..2bfe61bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,6 +25,10 @@ if ENABLE_PREVIEWER
 SUBDIRS += previewer
 endif
 
+if ENABLE_BROWSER_PLUGIN
+SUBDIRS += browser-plugin
+endif
+
 NULL =
 
 pkgconfigdir = $(libdir)/pkgconfig
diff --git a/browser-plugin/EvBrowserPlugin.cpp b/browser-plugin/EvBrowserPlugin.cpp
new file mode 100644
index 00000000..3b401585
--- /dev/null
+++ b/browser-plugin/EvBrowserPlugin.cpp
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "EvBrowserPlugin.h"
+
+#include "EvBrowserPluginToolbar.h"
+#include "npfunctions.h"
+#include <errno.h>
+#include <gtk/gtkx.h>
+#include <limits>
+#include <string.h>
+
+struct EvBrowserPluginClass {
+        enum Methods {
+                GoToPage,
+                ToggleContinuous,
+                ToggleDual,
+                ZoomIn,
+                ZoomOut,
+                Download,
+                Print,
+
+                NumMethodIdentifiers
+        };
+
+        enum Properties {
+                CurrentPage,
+                PageCount,
+                Zoom,
+                ZoomMode,
+                Continuous,
+                Dual,
+                Toolbar,
+
+                NumPropertyIdentifiers
+        };
+
+        EvBrowserPlugin* createObject(NPP instance)
+        {
+                if (!identifiersInitialized) {
+                        NPN_GetStringIdentifiers(methodIdentifierNames, NumMethodIdentifiers, 
methodIdentifiers);
+                        NPN_GetStringIdentifiers(propertyIdentifierNames, NumPropertyIdentifiers, 
propertyIdentifiers);
+                        identifiersInitialized = true;
+                }
+
+                return static_cast<EvBrowserPlugin *>(NPN_CreateObject(instance, &npClass));
+        }
+
+        NPClass npClass;
+
+        const NPUTF8 *methodIdentifierNames[NumMethodIdentifiers];
+        const NPUTF8 *propertyIdentifierNames[NumPropertyIdentifiers];
+        bool identifiersInitialized;
+        NPIdentifier methodIdentifiers[NumMethodIdentifiers];
+        NPIdentifier propertyIdentifiers[NumPropertyIdentifiers];
+};
+
+EvBrowserPlugin *EvBrowserPlugin::create(NPP instance)
+{
+        return s_pluginClass.createObject(instance);
+}
+
+const char *EvBrowserPlugin::nameString()
+{
+        return "Evince Browser Plugin";
+}
+
+const char *EvBrowserPlugin::descriptionString()
+{
+        return "The <a href=\"http://wiki.gnome.org/Apps/Evince/\";>Evince</a> " PACKAGE_VERSION " plugin 
handles documents inside the browser window.";
+}
+
+EvBrowserPlugin::EvBrowserPlugin(NPP instance)
+        : m_NPP(instance)
+        , m_window(nullptr)
+        , m_model(nullptr)
+        , m_view(nullptr)
+        , m_toolbar(nullptr)
+{
+        m_NPP->pdata = this;
+}
+
+EvBrowserPlugin::~EvBrowserPlugin()
+{
+        if (m_window)
+                gtk_widget_destroy(m_window);
+        g_clear_object(&m_model);
+        m_NPP->pdata = nullptr;
+}
+
+template <typename IntegerType>
+static inline void parseInteger(const char *strValue, IntegerType &intValue)
+{
+        static const IntegerType intMax = std::numeric_limits<IntegerType>::max();
+        static const bool isSigned = std::numeric_limits<IntegerType>::is_signed;
+
+        if (!strValue)
+                return;
+
+        char *endPtr = nullptr;
+        errno = 0;
+        gint64 value = isSigned ? g_ascii_strtoll(strValue, &endPtr, 0) : g_ascii_strtoull(strValue, 
&endPtr, 0);
+        if (endPtr != strValue && errno == 0 && value <= intMax)
+                intValue = static_cast<IntegerType>(value);
+}
+
+static inline void parseDouble(const char *strValue, double &doubleValue)
+{
+        if (!strValue)
+                return;
+
+        char *endPtr = nullptr;
+        errno = 0;
+        double value = g_ascii_strtod(strValue, &endPtr);
+        if (endPtr != strValue && errno == 0)
+                doubleValue = value;
+}
+
+static inline void parseBoolean(const char *strValue, bool &boolValue)
+{
+        if (!strValue)
+                return;
+
+        unique_gptr<char> value(g_ascii_strdown(strValue, -1));
+        if (g_ascii_strcasecmp(value.get(), "false") == 0 || g_ascii_strcasecmp(value.get(), "no") == 0)
+                boolValue = false;
+        else if (g_ascii_strcasecmp(value.get(), "true") == 0 || g_ascii_strcasecmp(value.get(), "yes") == 0)
+                boolValue = true;
+        else {
+                int intValue = boolValue;
+                parseInteger<int>(strValue, intValue);
+                boolValue = intValue > 0;
+        }
+}
+
+static inline void parseZoomMode(const char *strValue, EvSizingMode &sizingModeValue)
+{
+        if (!strValue)
+                return;
+
+        unique_gptr<char> value(g_ascii_strdown(strValue, -1));
+        if (g_ascii_strcasecmp(value.get(), "none") == 0)
+                sizingModeValue = EV_SIZING_FREE;
+        else if (g_ascii_strcasecmp(value.get(), "fit-page") == 0)
+                sizingModeValue = EV_SIZING_FIT_PAGE;
+        else if (g_ascii_strcasecmp(value.get(), "fit-width") == 0)
+                sizingModeValue = EV_SIZING_FIT_WIDTH;
+        else if (g_ascii_strcasecmp(value.get(), "auto") == 0)
+                sizingModeValue = EV_SIZING_AUTOMATIC;
+}
+
+NPError EvBrowserPlugin::initialize(NPMIMEType, uint16_t mode, int16_t argc, char *argn[], char *argv[], 
NPSavedData *)
+{
+        // Default values.
+        bool toolbarVisible = true;
+        unsigned currentPage = 1;
+        EvSizingMode sizingMode = EV_SIZING_AUTOMATIC;
+        bool continuous = true;
+        bool dual = false;
+        double zoom = 0;
+
+        for (int16_t i = 0; i < argc; ++i) {
+                if (g_ascii_strcasecmp(argn[i], "toolbar") == 0)
+                        parseBoolean(argv[i], toolbarVisible);
+                else if (g_ascii_strcasecmp(argn[i], "currentpage") == 0)
+                        parseInteger<unsigned>(argv[i], currentPage);
+                else if (g_ascii_strcasecmp(argn[i], "zoom") == 0)
+                        parseDouble(argv[i], zoom);
+                else if (g_ascii_strcasecmp(argn[i], "zoommode") == 0)
+                        parseZoomMode(argv[i], sizingMode);
+                else if (g_ascii_strcasecmp(argn[i], "continuous") == 0)
+                        parseBoolean(argv[i], continuous);
+                else if (g_ascii_strcasecmp(argn[i], "dual") == 0)
+                        parseBoolean(argv[i], dual);
+        }
+
+        m_model = ev_document_model_new();
+        if (currentPage > 0)
+                ev_document_model_set_page(m_model, currentPage - 1);
+        ev_document_model_set_continuous(m_model, continuous);
+        ev_document_model_set_page_layout(m_model, dual ? EV_PAGE_LAYOUT_DUAL : EV_PAGE_LAYOUT_SINGLE);
+        if (zoom) {
+                ev_document_model_set_sizing_mode(m_model, EV_SIZING_FREE);
+                ev_document_model_set_scale(m_model, zoom);
+        } else
+                ev_document_model_set_sizing_mode(m_model, sizingMode);
+
+        m_view = EV_VIEW(ev_view_new());
+        ev_view_set_model(m_view, m_model);
+
+        m_toolbar = ev_browser_plugin_toolbar_new(this);
+        if (toolbarVisible)
+                gtk_widget_show(m_toolbar);
+
+        return NPERR_NO_ERROR;
+}
+
+NPError EvBrowserPlugin::setWindow(NPWindow *window)
+{
+        if (!m_window) {
+                m_window = gtk_plug_new(reinterpret_cast<Window>(window->window));
+                gtk_widget_realize(m_window);
+
+                GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+                gtk_box_pack_start(GTK_BOX(vbox), m_toolbar, FALSE, FALSE, 0);
+
+                GtkWidget *scrolledWindow = gtk_scrolled_window_new(nullptr, nullptr);
+                gtk_container_add(GTK_CONTAINER(scrolledWindow), GTK_WIDGET(m_view));
+                gtk_widget_show(GTK_WIDGET(m_view));
+
+                gtk_box_pack_start(GTK_BOX(vbox), scrolledWindow, TRUE, TRUE, 0);
+                gtk_widget_show(scrolledWindow);
+
+                gtk_container_add(GTK_CONTAINER(m_window), vbox);
+                gtk_widget_show(vbox);
+        }
+
+        gtk_widget_set_size_request(m_window, window->width, window->height);
+        gtk_widget_show(m_window);
+
+        return NPERR_NO_ERROR;
+}
+
+NPError EvBrowserPlugin::newStream(NPMIMEType, NPStream *stream, NPBool seekable, uint16_t *stype)
+{
+        m_url.reset(g_strdup(stream->url));
+        *stype = NP_ASFILEONLY;
+        return NPERR_NO_ERROR;
+}
+
+NPError EvBrowserPlugin::destroyStream(NPStream *, NPReason)
+{
+        return NPERR_NO_ERROR;
+}
+
+void EvBrowserPlugin::streamAsFile(NPStream *, const char *fname)
+{
+        GFile *file = g_file_new_for_commandline_arg(fname);
+        unique_gptr<char> uri(g_file_get_uri(file));
+        g_object_unref(file);
+
+        // Load the document synchronously here because the temporary file created by the browser
+        // is deleted when this function returns.
+        GError *error = nullptr;
+        EvDocument *document = ev_document_factory_get_document(uri.get(), &error);
+        if (!document) {
+                g_printerr("Error loading document %s: %s\n", uri.get(), error->message);
+                g_error_free(error);
+        } else {
+                ev_document_model_set_document(m_model, document);
+                g_object_unref(document);
+
+                ev_view_set_loading(EV_VIEW(m_view), FALSE);
+        }
+}
+
+int32_t EvBrowserPlugin::writeReady(NPStream *)
+{
+        return 0;
+}
+
+int32_t EvBrowserPlugin::write(NPStream *, int32_t /*offset*/, int32_t /*len*/, void */*buffer*/)
+{
+        return 0;
+}
+
+void EvBrowserPlugin::print(NPPrint *)
+{
+
+}
+
+int16_t EvBrowserPlugin::handleEvent(XEvent *)
+{
+        return 0;
+}
+
+void EvBrowserPlugin::urlNotify(const char */*url*/, NPReason, void */*notifyData*/)
+{
+
+}
+
+unsigned EvBrowserPlugin::currentPage() const
+{
+        g_return_val_if_fail(EV_IS_DOCUMENT_MODEL(m_model), 0);
+        return ev_document_model_get_page(m_model);
+}
+
+unsigned EvBrowserPlugin::pageCount() const
+{
+        g_return_val_if_fail(EV_IS_DOCUMENT_MODEL(m_model), 0);
+        EvDocument *document = ev_document_model_get_document(m_model);
+        return document ? ev_document_get_n_pages(document) : 0;
+}
+
+double EvBrowserPlugin::zoom() const
+{
+        g_return_val_if_fail(EV_IS_DOCUMENT_MODEL(m_model), 1);
+        return ev_document_model_get_scale(m_model);
+}
+
+void EvBrowserPlugin::setZoom(double scale)
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_sizing_mode(m_model, EV_SIZING_FREE);
+        ev_document_model_set_scale(m_model, scale);
+}
+
+void EvBrowserPlugin::goToPreviousPage()
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_page(m_model, ev_document_model_get_page(m_model) - 1);
+}
+
+void EvBrowserPlugin::goToNextPage()
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_page(m_model, ev_document_model_get_page(m_model) + 1);
+}
+
+void EvBrowserPlugin::goToPage(unsigned page)
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_page(m_model, page - 1);
+}
+
+void EvBrowserPlugin::goToPage(const char *pageLabel)
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_page_by_label(m_model, pageLabel);
+}
+
+void EvBrowserPlugin::activateLink(EvLink *link)
+{
+        g_return_if_fail(EV_IS_VIEW(m_view));
+        g_return_if_fail(EV_IS_LINK(link));
+        ev_view_handle_link(m_view, link);
+        gtk_widget_grab_focus(GTK_WIDGET(m_view));
+}
+
+bool EvBrowserPlugin::isContinuous() const
+{
+        g_return_val_if_fail(EV_IS_DOCUMENT_MODEL(m_model), false);
+        return ev_document_model_get_continuous(m_model);
+}
+
+void EvBrowserPlugin::setContinuous(bool continuous)
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_continuous(m_model, continuous);
+}
+
+void EvBrowserPlugin::toggleContinuous()
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_continuous(m_model, !ev_document_model_get_continuous(m_model));
+}
+
+bool EvBrowserPlugin::isDual() const
+{
+        g_return_val_if_fail(EV_IS_DOCUMENT_MODEL(m_model), false);
+        return ev_document_model_get_page_layout(m_model) == EV_PAGE_LAYOUT_DUAL;
+}
+
+void EvBrowserPlugin::setDual(bool dual)
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_page_layout(m_model, dual ? EV_PAGE_LAYOUT_DUAL : EV_PAGE_LAYOUT_SINGLE);
+}
+
+void EvBrowserPlugin::toggleDual()
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_page_layout(m_model, isDual() ? EV_PAGE_LAYOUT_SINGLE : EV_PAGE_LAYOUT_DUAL);
+}
+
+void EvBrowserPlugin::zoomIn()
+{
+        g_return_if_fail(EV_IS_VIEW(m_view));
+        ev_document_model_set_sizing_mode(m_model, EV_SIZING_FREE);
+        ev_view_zoom_in(m_view);
+}
+
+void EvBrowserPlugin::zoomOut()
+{
+        g_return_if_fail(EV_IS_VIEW(m_view));
+        ev_document_model_set_sizing_mode(m_model, EV_SIZING_FREE);
+        ev_view_zoom_out(m_view);
+}
+
+EvSizingMode EvBrowserPlugin::sizingMode() const
+{
+        g_return_val_if_fail(EV_IS_DOCUMENT_MODEL(m_model), EV_SIZING_FREE);
+        return ev_document_model_get_sizing_mode(m_model);
+}
+
+void EvBrowserPlugin::setSizingMode(EvSizingMode sizingMode)
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+        ev_document_model_set_sizing_mode(m_model, sizingMode);
+}
+
+void EvBrowserPlugin::download() const
+{
+        g_return_if_fail(m_url);
+        // Since I don't know how to force a download in the browser, I use
+        // a special frame name here that Epiphany will check in the new window policy
+        // callback to start the download.
+        NPN_GetURL(m_NPP, m_url.get(), "_evince_download");
+}
+
+void EvBrowserPlugin::print() const
+{
+        g_return_if_fail(EV_IS_DOCUMENT_MODEL(m_model));
+
+        EvDocument *document = ev_document_model_get_document(m_model);
+        if (!document)
+                return;
+
+        EvPrintOperation *printOperation = ev_print_operation_new(document);
+        if (!printOperation)
+                return;
+
+        unique_gptr<char> outputBasename(g_path_get_basename(m_url.get()));
+        if (char *dot = g_strrstr(outputBasename.get(), "."))
+                dot[0] = '\0';
+
+        unique_gptr<char> unescapedBasename(g_uri_unescape_string(outputBasename.get(), nullptr));
+        // Set output basename for printing to file.
+        GtkPrintSettings *printSettings = gtk_print_settings_new();
+        gtk_print_settings_set(printSettings, GTK_PRINT_SETTINGS_OUTPUT_BASENAME, unescapedBasename.get());
+
+        if (const char *title = ev_document_get_title(document))
+                ev_print_operation_set_job_name(printOperation, title);
+        ev_print_operation_set_current_page(printOperation, ev_document_model_get_page(m_model));
+        ev_print_operation_set_embed_page_setup (printOperation, TRUE);
+        ev_print_operation_set_print_settings(printOperation, printSettings);
+        g_object_unref(printSettings);
+
+        g_signal_connect(printOperation, "done", G_CALLBACK(g_object_unref), nullptr);
+
+        GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(m_view));
+        ev_print_operation_run(printOperation, GTK_IS_WINDOW(toplevel) ? GTK_WINDOW(toplevel) : nullptr);
+}
+
+bool EvBrowserPlugin::canDownload() const
+{
+        // Download is only available for Epiphany for now.
+        return g_strrstr(NPN_UserAgent(m_NPP), "Epiphany");
+}
+
+bool EvBrowserPlugin::toolbarVisible() const
+{
+        g_return_val_if_fail(EV_IS_BROWSER_PLUGIN_TOOLBAR(m_toolbar), false);
+        return gtk_widget_get_visible(m_toolbar);
+}
+
+void EvBrowserPlugin::setToolbarVisible(bool isVisible)
+{
+        g_return_if_fail(EV_IS_BROWSER_PLUGIN_TOOLBAR(m_toolbar));
+        if (isVisible)
+                gtk_widget_show(m_toolbar);
+        else
+                gtk_widget_hide(m_toolbar);
+}
+
+void EvBrowserPlugin::setSearchModeEnabled(bool enabled)
+{
+        ev_view_find_set_highlight_search(m_view, enabled);
+}
+
+void EvBrowserPlugin::search(EvJobFind *job)
+{
+        ev_view_find_search_changed(m_view);
+        ev_view_find_started(m_view, job);
+}
+
+void EvBrowserPlugin::search(SearchDirection direction)
+{
+        switch (direction) {
+        case Next:
+                ev_view_find_next(m_view);
+                break;
+        case Previous:
+                ev_view_find_previous(m_view);
+                break;
+        }
+}
+
+void EvBrowserPlugin::clearSearch()
+{
+        ev_view_find_search_changed(m_view);
+        gtk_widget_queue_draw(GTK_WIDGET(m_view));
+}
+
+void EvBrowserPlugin::restartSearch()
+{
+        ev_view_find_restart(m_view, ev_document_model_get_page(m_model));
+}
+
+// Scripting interface
+NPObject *EvBrowserPlugin::allocate(NPP instance, NPClass *)
+{
+        return new EvBrowserPlugin(instance);
+}
+
+void EvBrowserPlugin::deallocate(NPObject *npObject)
+{
+        delete static_cast<EvBrowserPlugin *>(npObject);
+}
+
+void EvBrowserPlugin::invalidate(NPObject *)
+{
+}
+
+bool EvBrowserPlugin::hasMethod(NPObject *npObject, NPIdentifier name)
+{
+        for (unsigned i = 0; i < EvBrowserPluginClass::Methods::NumMethodIdentifiers; ++i) {
+                if (name == s_pluginClass.methodIdentifiers[i]) {
+                        if (i == EvBrowserPluginClass::Methods::Download)
+                                return static_cast<EvBrowserPlugin *>(npObject)->canDownload();
+                        return true;
+                }
+        }
+        return false;
+}
+
+bool EvBrowserPlugin::invoke(NPObject *npObject, NPIdentifier name, const NPVariant *args, uint32_t 
argCount, NPVariant *result)
+{
+        EvBrowserPlugin *plugin = static_cast<EvBrowserPlugin *>(npObject);
+
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::GoToPage]) {
+                if (argCount != 1)
+                        return false;
+
+                if (NPVARIANT_IS_DOUBLE(args[0]))
+                        plugin->goToPage(static_cast<unsigned>(NPVARIANT_TO_DOUBLE(args[0])));
+                else if (NPVARIANT_IS_STRING(args[0])) {
+                        unique_gptr<char> pageLabel(g_strndup(NPVARIANT_TO_STRING(args[0]).UTF8Characters, 
NPVARIANT_TO_STRING(args[0]).UTF8Length));
+                        plugin->goToPage(pageLabel.get());
+                } else
+                        return false;
+
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::ToggleContinuous]) {
+                plugin->toggleContinuous();
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::ToggleDual]) {
+                plugin->toggleDual();
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::ZoomIn]) {
+                plugin->zoomIn();
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::ZoomOut]) {
+                plugin->zoomOut();
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::Download]) {
+                plugin->download();
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        if (name == s_pluginClass.methodIdentifiers[EvBrowserPluginClass::Methods::Print]) {
+                plugin->print();
+                VOID_TO_NPVARIANT(*result);
+                return true;
+        }
+        return false;
+}
+
+bool EvBrowserPlugin::hasProperty(NPObject *npObject, NPIdentifier name)
+{
+        for (unsigned i = 0; i < EvBrowserPluginClass::Properties::NumPropertyIdentifiers; ++i) {
+                if (name == s_pluginClass.propertyIdentifiers[i])
+                        return true;
+        }
+        return false;
+}
+
+bool EvBrowserPlugin::getProperty(NPObject *npObject, NPIdentifier name, NPVariant *value)
+{
+        EvBrowserPlugin *plugin = static_cast<EvBrowserPlugin *>(npObject);
+
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::CurrentPage]) {
+                INT32_TO_NPVARIANT(plugin->currentPage() + 1, *value);
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::PageCount]) {
+                INT32_TO_NPVARIANT(plugin->pageCount(), *value);
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Zoom]) {
+                DOUBLE_TO_NPVARIANT(plugin->zoom(), *value);
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::ZoomMode]) {
+                const char *zoomMode;
+
+                switch (plugin->sizingMode()) {
+                case EV_SIZING_FREE:
+                        zoomMode = "none";
+                        break;
+                case EV_SIZING_FIT_PAGE:
+                        zoomMode = "fit-page";
+                        break;
+                case EV_SIZING_FIT_WIDTH:
+                        zoomMode = "fit-width";
+                        break;
+                case EV_SIZING_AUTOMATIC:
+                        zoomMode = "auto";
+                        break;
+                default:
+                        return false;
+                }
+
+                size_t zoomModeLength = strlen(zoomMode);
+                char *result = static_cast<char *>(NPN_MemAlloc(zoomModeLength + 1));
+                memcpy(result, zoomMode, zoomModeLength);
+                result[zoomModeLength] = '\0';
+
+                STRINGZ_TO_NPVARIANT(result, *value);
+
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Continuous]) {
+                BOOLEAN_TO_NPVARIANT(plugin->isContinuous(), *value);
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Dual]) {
+                BOOLEAN_TO_NPVARIANT(plugin->isDual(), *value);
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Toolbar]) {
+                BOOLEAN_TO_NPVARIANT(plugin->toolbarVisible(), *value);
+                return true;
+        }
+
+        return false;
+}
+
+bool EvBrowserPlugin::setProperty(NPObject *npObject, NPIdentifier name, const NPVariant *value)
+{
+        EvBrowserPlugin *plugin = static_cast<EvBrowserPlugin *>(npObject);
+
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::CurrentPage]) {
+                plugin->goToPage(static_cast<unsigned>(NPVARIANT_TO_DOUBLE(*value)));
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Zoom]) {
+                plugin->setZoom(NPVARIANT_TO_DOUBLE(*value));
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::ZoomMode]) {
+                unique_gptr<char> zoomMode(g_strndup(NPVARIANT_TO_STRING(*value).UTF8Characters, 
NPVARIANT_TO_STRING(*value).UTF8Length));
+
+                if (g_strcmp0(zoomMode.get(), "none") == 0)
+                        plugin->setSizingMode(EV_SIZING_FREE);
+                else if (g_strcmp0(zoomMode.get(), "fit-page") == 0)
+                        plugin->setSizingMode(EV_SIZING_FIT_PAGE);
+                else if (g_strcmp0(zoomMode.get(), "fit-width") == 0)
+                        plugin->setSizingMode(EV_SIZING_FIT_WIDTH);
+                else if (g_strcmp0(zoomMode.get(), "auto") == 0)
+                        plugin->setSizingMode(EV_SIZING_AUTOMATIC);
+                else
+                        return false;
+
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Continuous]) {
+                plugin->setContinuous(NPVARIANT_TO_BOOLEAN(*value));
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Dual]) {
+                plugin->setDual(NPVARIANT_TO_BOOLEAN(*value));
+                return true;
+        }
+        if (name == s_pluginClass.propertyIdentifiers[EvBrowserPluginClass::Properties::Toolbar]) {
+                plugin->setToolbarVisible(NPVARIANT_TO_BOOLEAN(*value));
+                return true;
+        }
+
+        return false;
+}
+
+EvBrowserPluginClass EvBrowserPlugin::s_pluginClass {
+        {
+                NP_CLASS_STRUCT_VERSION,
+                allocate,
+                deallocate,
+                invalidate,
+                hasMethod,
+                invoke,
+                nullptr, // NPClass::invokeDefault
+                hasProperty,
+                getProperty,
+                setProperty,
+                nullptr, // NPClass::removeProperty
+                nullptr, // NPClass::enumerate
+                nullptr // NPClass::construct
+        },
+        // methodIdentifierNames
+        {
+                "goToPage",
+                "toggleContinuous",
+                "toggleDual",
+                "zoomIn",
+                "zoomOut",
+                "download",
+                "print"
+        },
+        // propertyIdentifierNames
+        {
+                "currentPage",
+                "pageCount",
+                "zoom",
+                "zoomMode",
+                "continuous",
+                "dual",
+                "toolbar"
+        },
+        false // identifiersInitialized
+};
diff --git a/browser-plugin/EvBrowserPlugin.gresource.xml b/browser-plugin/EvBrowserPlugin.gresource.xml
new file mode 100644
index 00000000..4d3a5660
--- /dev/null
+++ b/browser-plugin/EvBrowserPlugin.gresource.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright © 2014 Igalia S.L.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3, or (at your option)
+  any later version.
+
+  This program is distributed in the hope conf it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<gresources>
+  <gresource prefix="/org/gnome/evince/browser">
+    <file alias="ui/evince-browser.css" compressed="true">evince-browser.css</file>
+    <file alias="ui/thumbnail-frame.png" compressed="true">thumbnail-frame.png</file>
+  </gresource>
+</gresources>
diff --git a/browser-plugin/EvBrowserPlugin.h b/browser-plugin/EvBrowserPlugin.h
new file mode 100644
index 00000000..6a3533d8
--- /dev/null
+++ b/browser-plugin/EvBrowserPlugin.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EvBrowserPlugin_h
+#define EvBrowserPlugin_h
+
+#include <evince-document.h>
+#include <evince-view.h>
+#include "EvMemoryUtils.h"
+#include "npapi.h"
+#include "npruntime.h"
+
+typedef union _XEvent XEvent;
+struct EvBrowserPluginClass;
+
+class EvBrowserPlugin: public NPObject {
+public:
+        static EvBrowserPlugin* create(NPP);
+
+        static const char *nameString();
+        static const char *descriptionString();
+
+        // NPP API
+        NPError initialize(NPMIMEType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData 
*);
+        NPError setWindow(NPWindow *);
+        NPError newStream(NPMIMEType, NPStream *, NPBool seekable, uint16_t *stype);
+        NPError destroyStream(NPStream *, NPReason);
+        void streamAsFile(NPStream *, const char *fname);
+        int32_t writeReady(NPStream *);
+        int32_t write(NPStream *, int32_t offset, int32_t len, void *buffer);
+        void print(NPPrint *);
+        int16_t handleEvent(XEvent *);
+        void urlNotify(const char *url, NPReason, void *notifyData);
+
+        // Viewer API
+        EvDocumentModel *model() const { return m_model; }
+        unsigned currentPage() const;
+        unsigned pageCount() const;
+        double zoom() const;
+        void setZoom(double scale);
+        void goToPreviousPage();
+        void goToNextPage();
+        void goToPage(unsigned page);
+        void goToPage(const char *pageLabel);
+        void activateLink(EvLink *);
+        bool isContinuous() const;
+        void setContinuous(bool);
+        void toggleContinuous();
+        bool isDual() const;
+        void setDual(bool);
+        void toggleDual();
+        void zoomIn();
+        void zoomOut();
+        EvSizingMode sizingMode() const;
+        void setSizingMode(EvSizingMode);
+        void download() const;
+        void print() const;
+        bool toolbarVisible() const;
+        void setToolbarVisible(bool);
+
+        bool canDownload() const;
+
+        void setSearchModeEnabled(bool);
+        void search(EvJobFind *);
+        enum SearchDirection { Next, Previous };
+        void search(SearchDirection);
+        void clearSearch();
+        void restartSearch();
+
+private:
+        EvBrowserPlugin(NPP);
+        virtual ~EvBrowserPlugin();
+
+        // Scripting interface
+        static NPObject *allocate(NPP, NPClass *);
+        static void deallocate(NPObject *);
+        static void invalidate(NPObject *);
+        static bool hasMethod(NPObject *, NPIdentifier name);
+        static bool invoke(NPObject *, NPIdentifier name, const NPVariant *args, uint32_t argCount, 
NPVariant *result);
+        static bool hasProperty(NPObject *, NPIdentifier name);
+        static bool getProperty(NPObject *, NPIdentifier name, NPVariant *);
+        static bool setProperty(NPObject *, NPIdentifier name, const NPVariant *);
+
+        NPP m_NPP;
+        GtkWidget *m_window;
+        EvDocumentModel *m_model;
+        EvView *m_view;
+        GtkWidget *m_toolbar;
+        unique_gptr<char> m_url;
+
+        static EvBrowserPluginClass s_pluginClass;
+};
+
+#endif // EvBrowserPlugin_h
diff --git a/browser-plugin/EvBrowserPluginMain.cpp b/browser-plugin/EvBrowserPluginMain.cpp
new file mode 100644
index 00000000..04f8e402
--- /dev/null
+++ b/browser-plugin/EvBrowserPluginMain.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "EvBrowserPlugin.h"
+#include "EvMemoryUtils.h"
+#include "npfunctions.h"
+#include "npruntime.h"
+#include <gdk/gdk.h>
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
+
+static NPNetscapeFuncs *browser;
+static unique_gptr<char> mimeDescription;
+
+static EvBrowserPlugin *pluginForInstance(NPP instance)
+{
+        if (!instance)
+                return nullptr;
+
+        return static_cast<EvBrowserPlugin *>(instance->pdata);
+}
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char *argn[], char 
*argv[], NPSavedData *savedData)
+{
+        if (!instance)
+                return NPERR_INVALID_INSTANCE_ERROR;
+
+        return EvBrowserPlugin::create(instance)->initialize(pluginType, mode, argc, argn, argv, savedData);
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData **saveData)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return NPERR_INVALID_INSTANCE_ERROR;
+
+        browser->releaseobject(static_cast<NPObject *>(plugin));
+        return NPERR_NO_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow *window)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return NPERR_INVALID_INSTANCE_ERROR;
+
+        return plugin->setWindow(window);
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return NPERR_INVALID_INSTANCE_ERROR;
+
+        return plugin->newStream(type, stream, seekable, stype);
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return NPERR_INVALID_INSTANCE_ERROR;
+
+        return plugin->destroyStream(stream, reason);
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return;
+
+        return plugin->streamAsFile(stream, fname);
+}
+
+int32_t NPP_WriteReady(NPP instance, NPStream *stream)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return -1;
+
+        return plugin->writeReady(stream);
+}
+
+int32_t NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len, void *buffer)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return -1;
+
+        return plugin->write(stream, offset, len, buffer);
+}
+
+void NPP_Print(NPP instance, NPPrint *platformPrint)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return;
+
+        return plugin->print(platformPrint);
+}
+
+int16_t NPP_HandleEvent(NPP instance, void *event)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return 0;
+
+        return plugin->handleEvent(static_cast<XEvent *>(event));
+}
+
+void NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData)
+{
+        EvBrowserPlugin *plugin = pluginForInstance(instance);
+        if (!plugin)
+                return;
+
+        return plugin->urlNotify(url, reason, notifyData);
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
+{
+        switch (variable) {
+        case NPPVpluginNameString:
+                *((char **)value) = const_cast<char *>(EvBrowserPlugin::nameString());
+                return NPERR_NO_ERROR;
+        case NPPVpluginDescriptionString:
+                *((char **)value) = const_cast<char *>(EvBrowserPlugin::descriptionString());
+                return NPERR_NO_ERROR;
+        case NPPVpluginNeedsXEmbed:
+                *((NPBool *)value) = TRUE;
+                return NPERR_NO_ERROR;
+        case NPPVpluginScriptableNPObject: {
+                EvBrowserPlugin *plugin = pluginForInstance(instance);
+                if (!plugin)
+                        return NPERR_INVALID_PLUGIN_ERROR;
+
+                browser->retainobject(static_cast<NPObject *>(plugin));
+                *((NPObject **)value) = plugin;
+                return NPERR_NO_ERROR;
+        }
+        default:
+                return NPERR_INVALID_PARAM;
+        }
+
+        return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP, NPNVariable, void *)
+{
+        return NPERR_NO_ERROR;
+}
+
+static void initializePluginFuncs(NPPluginFuncs *pluginFuncs)
+{
+        pluginFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+        pluginFuncs->size = sizeof(pluginFuncs);
+        pluginFuncs->newp = NPP_New;
+        pluginFuncs->destroy = NPP_Destroy;
+        pluginFuncs->setwindow = NPP_SetWindow;
+        pluginFuncs->newstream = NPP_NewStream;
+        pluginFuncs->destroystream = NPP_DestroyStream;
+        pluginFuncs->asfile = NPP_StreamAsFile;
+        pluginFuncs->writeready = NPP_WriteReady;
+        pluginFuncs->write = NPP_Write;
+        pluginFuncs->print = NPP_Print;
+        pluginFuncs->event = NPP_HandleEvent;
+        pluginFuncs->urlnotify = NPP_URLNotify;
+        pluginFuncs->getvalue = NPP_GetValue;
+        pluginFuncs->setvalue = NPP_SetValue;
+}
+
+NPError NP_Initialize(NPNetscapeFuncs *browserFuncs, NPPluginFuncs *pluginFuncs)
+{
+        if (!browserFuncs || !pluginFuncs)
+                return NPERR_INVALID_FUNCTABLE_ERROR;
+
+        if ((browserFuncs->version >> 8) > NP_VERSION_MAJOR)
+                return NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+        if (!ev_init())
+                return NPERR_GENERIC_ERROR;
+
+        gtk_init(nullptr, nullptr);
+
+#ifdef GDK_WINDOWING_WAYLAND
+        if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()))
+                return NPERR_GENERIC_ERROR;
+#endif
+
+        browser = browserFuncs;
+        initializePluginFuncs(pluginFuncs);
+
+        GBytes *resourceData = g_resources_lookup_data("/org/gnome/evince/browser/ui/evince-browser.css", 
G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
+        if (resourceData) {
+            GtkCssProvider *cssProvider = gtk_css_provider_new();
+
+            gtk_css_provider_load_from_data(cssProvider, static_cast<const gchar 
*>(g_bytes_get_data(resourceData, nullptr)), g_bytes_get_size(resourceData), nullptr);
+            g_bytes_unref(resourceData);
+
+            gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), 
GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+            g_object_unref(cssProvider);
+        }
+
+        return NPERR_NO_ERROR;
+}
+
+NPError NP_Shutdown()
+{
+        ev_shutdown();
+        return NPERR_NO_ERROR;
+}
+
+static const struct {
+        const char *mime;
+        const char *extensions;
+} mimeExtensions[] = {
+        { "application/postscript", "ps" },
+        { "application/x-ext-ps", "ps" },
+        { "application/x-bzpostscript", "ps.bz2" },
+        { "application/x-gzpostscript", "ps.gz" },
+        { "image/x-eps", "eps,epsi,epsf" },
+        { "application/x-ext-eps", "eps,epsi,epsf" },
+        { "image/x-bzeps", "eps.bz2,epsi.bz2,epsf.bz2" },
+        { "image/x-gzeps", "eps.gz,epsi.gz,epsf.gz" },
+        { "image/tiff", "tif,tiff" },
+        { "application/pdf", "pdf" },
+        { "application/x-ext-pdf", "pdf" },
+        { "application/x-bzpdf", "pdf.bz2" },
+        { "application/x-gzpdf", "pdf.gz" },
+        { "application/x-xzpdf", "pdf.xz" },
+        { "application/x-dvi", "dvi" },
+        { "application/x-ext-dvi", "dvi" },
+        { "application/x-bzdvi", "dvi.bz2" },
+        { "application/x-gzdvi", "dvi.gz" },
+        { "application/x-cbr", "cbr" },
+        { "application/x-ext-cbr", "cbr" },
+        { "application/x-cbz", "cbz" },
+        { "application/x-ext-cbz", "cbz" },
+        { "application/x-cb7", "cb7" },
+        { "application/x-ext-cb7", "cb7" },
+        { "application/x-cbt", "cbt" },
+        { "application/x-ext-cbt", "cbt" },
+        { "image/vnd.djvu", "djvu,djv" },
+        { "image/vnd.djvu+multipage", "djvu,djv" },
+        { "application/x-ext-djv", "djv" },
+        { "application/x-ext-djvu", "djvu" },
+        { "application/oxps", "xps,oxps" },
+        { "application/vnd.ms-xpsdocument", "xps,oxps" }
+};
+
+const char *NP_GetMIMEDescription()
+{
+        if (mimeDescription)
+                return mimeDescription.get();
+
+        if (!ev_init())
+                return nullptr;
+
+#ifdef GDK_WINDOWING_WAYLAND
+        if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()))
+                return nullptr;
+#endif
+
+        GString *mimeDescriptionStr = g_string_new(nullptr);
+
+        GList *typesInfo = ev_backends_manager_get_all_types_info();
+        for (GList *l = typesInfo; l; l = g_list_next(l)) {
+                EvTypeInfo *info = static_cast<EvTypeInfo *>(l->data);
+
+                for (unsigned i = 0; info->mime_types[i]; ++i) {
+                        const char *extensions = [](const char *mime) -> const char * {
+                                for (unsigned i = 0; i < G_N_ELEMENTS(mimeExtensions); ++i) {
+                                        if (g_ascii_strcasecmp(mimeExtensions[i].mime, mime) == 0)
+                                                return mimeExtensions[i].extensions;
+                                }
+
+                                return nullptr;
+                        }(info->mime_types[i]);
+
+                        if (!extensions)
+                                continue;
+
+                        g_string_append_printf(mimeDescriptionStr, "%s:%s:%s;",
+                                               info->mime_types[i],
+                                               extensions,
+                                               info->desc);
+                }
+        }
+        g_list_free(typesInfo);
+
+        mimeDescription.reset(g_string_free(mimeDescriptionStr, FALSE));
+
+        ev_shutdown();
+
+        return mimeDescription.get();
+}
+
+NPError NP_GetValue(void *, NPPVariable variable, void *value)
+{
+        return NPP_GetValue(nullptr, variable, value);
+}
+
+NPObject *NPN_CreateObject(NPP instance, NPClass *npClass)
+{
+        return browser->createobject(instance, npClass);
+}
+
+void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers)
+{
+        browser->getstringidentifiers(names, nameCount, identifiers);
+}
+
+NPError NPN_GetURL(NPP instance, const char* url, const char* target)
+{
+        return browser->geturl(instance, url, target);
+}
+
+const char *NPN_UserAgent(NPP instance)
+{
+        return browser->uagent(instance);
+}
+
+void *NPN_MemAlloc(uint32_t size)
+{
+        return browser->memalloc(size);
+}
+
+void NPN_MemFree(void* ptr)
+{
+        if (ptr)
+                browser->memfree(ptr);
+}
+
+static void __attribute__((constructor)) browserPluginConstructor()
+{
+        ev_init();
+}
+
+static void __attribute__((destructor)) browserPluginDestructor()
+{
+        ev_shutdown();
+}
diff --git a/browser-plugin/EvBrowserPluginToolbar.cpp b/browser-plugin/EvBrowserPluginToolbar.cpp
new file mode 100644
index 00000000..2c4e2be2
--- /dev/null
+++ b/browser-plugin/EvBrowserPluginToolbar.cpp
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "EvBrowserPluginToolbar.h"
+
+#include "ev-page-action-widget.h"
+#include "ev-search-box.h"
+#include <glib/gi18n-lib.h>
+
+enum {
+        PROP_0,
+        PROP_PLUGIN
+};
+
+struct _EvBrowserPluginToolbarPrivate {
+        EvBrowserPlugin *plugin;
+
+        GtkWidget *continuousToggleButton;
+        GtkWidget *dualToggleButton;
+        GtkWidget *zoomFitPageRadioButton;
+        GtkWidget *zoomFitWidthRadioButton;
+        GtkWidget *zoomAutomaticRadioButton;
+        GtkWidget *searchToggleButton;
+        GtkWidget *searchPopover;
+};
+
+G_DEFINE_TYPE(EvBrowserPluginToolbar, ev_browser_plugin_toolbar, GTK_TYPE_TOOLBAR)
+
+static void goToPreviousPage(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->goToPreviousPage();
+}
+
+static void goToNextPage(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->goToNextPage();
+}
+
+static void activateLink(EvBrowserPluginToolbar *toolbar, EvLink *link)
+{
+        toolbar->priv->plugin->activateLink(link);
+}
+
+static void toggleContinuous(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->toggleContinuous();
+}
+
+static void toggleDual(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->toggleDual();
+}
+
+static void zoomIn(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->zoomIn();
+}
+
+static void zoomOut(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->zoomOut();
+}
+
+static void zoomFitPageToggled(EvBrowserPluginToolbar *toolbar)
+{
+        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(toolbar->priv->zoomFitPageRadioButton)))
+                toolbar->priv->plugin->setSizingMode(EV_SIZING_FIT_PAGE);
+}
+
+static void zoomFitWidthToggled(EvBrowserPluginToolbar *toolbar)
+{
+        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(toolbar->priv->zoomFitWidthRadioButton)))
+                toolbar->priv->plugin->setSizingMode(EV_SIZING_FIT_WIDTH);
+}
+
+static void zoomAutomaticToggled(EvBrowserPluginToolbar *toolbar)
+{
+        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(toolbar->priv->zoomAutomaticRadioButton)))
+                toolbar->priv->plugin->setSizingMode(EV_SIZING_AUTOMATIC);
+}
+
+static void printDocument(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->print();
+}
+
+static void downloadDocument(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->download();
+}
+
+static void searchPopoverClosed(EvBrowserPluginToolbar *toolbar)
+{
+        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->priv->searchToggleButton)))
+                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->priv->searchToggleButton), FALSE);
+}
+
+static void searchStarted(EvBrowserPluginToolbar *toolbar, EvJobFind *job)
+{
+        toolbar->priv->plugin->search(job);
+}
+
+static void searchCleared(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->clearSearch();
+}
+
+static void searchNext(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->search(EvBrowserPlugin::SearchDirection::Next);
+}
+
+static void searchPrevious(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv->plugin->search(EvBrowserPlugin::SearchDirection::Previous);
+}
+
+static void toggleSearch(EvBrowserPluginToolbar *toolbar)
+{
+        if (!toolbar->priv->searchPopover) {
+                toolbar->priv->searchPopover = gtk_popover_new(toolbar->priv->searchToggleButton);
+                gtk_popover_set_position (GTK_POPOVER (toolbar->priv->searchPopover), GTK_POS_BOTTOM);
+                g_signal_connect_swapped(toolbar->priv->searchPopover, "closed", 
G_CALLBACK(searchPopoverClosed), toolbar);
+                GtkWidget *searchBox = ev_search_box_new(toolbar->priv->plugin->model());
+                g_signal_connect_swapped(searchBox, "started", G_CALLBACK(searchStarted), toolbar);
+                g_signal_connect_swapped(searchBox, "cleared", G_CALLBACK(searchCleared), toolbar);
+                g_signal_connect_swapped(searchBox, "next", G_CALLBACK(searchNext), toolbar);
+                g_signal_connect_swapped(searchBox, "previous", G_CALLBACK(searchPrevious), toolbar);
+                gtk_container_add(GTK_CONTAINER(toolbar->priv->searchPopover), searchBox);
+                gtk_widget_show(searchBox);
+        }
+
+        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->priv->searchToggleButton))) {
+                gtk_widget_show(toolbar->priv->searchPopover);
+                toolbar->priv->plugin->setSearchModeEnabled(true);
+
+                GtkSearchEntry *entry = 
ev_search_box_get_entry(EV_SEARCH_BOX(gtk_bin_get_child(GTK_BIN(toolbar->priv->searchPopover))));
+                const char *searchString = gtk_entry_get_text(GTK_ENTRY(entry));
+                if (searchString && searchString[0])
+                        toolbar->priv->plugin->restartSearch();
+        } else {
+                gtk_widget_hide(toolbar->priv->searchPopover);
+                toolbar->priv->plugin->setSearchModeEnabled(false);
+        }
+}
+
+class SignalBlocker {
+public:
+        SignalBlocker(gpointer instance, void (* closure)(EvBrowserPluginToolbar *), gpointer data)
+                : m_instance(instance)
+                , m_closure(reinterpret_cast<gpointer>(closure))
+                , m_data(data)
+        {
+                g_signal_handlers_block_by_func(m_instance, m_closure, m_data);
+        }
+
+        ~SignalBlocker()
+        {
+                g_signal_handlers_unblock_by_func(m_instance, m_closure, m_data);
+        }
+
+private:
+        gpointer m_instance;
+        gpointer m_closure;
+        gpointer m_data;
+};
+
+static void continuousChanged(EvDocumentModel *model, GParamSpec *, EvBrowserPluginToolbar *toolbar)
+{
+        SignalBlocker blocker(toolbar->priv->continuousToggleButton, toggleContinuous, toolbar);
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->priv->continuousToggleButton),
+                                     toolbar->priv->plugin->isContinuous());
+}
+
+static void dualPageChanged(EvDocumentModel *model, GParamSpec *, EvBrowserPluginToolbar *toolbar)
+{
+        SignalBlocker blocker(toolbar->priv->dualToggleButton, toggleDual, toolbar);
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->priv->dualToggleButton),
+                                     toolbar->priv->plugin->isDual());
+}
+
+static void sizingModeChanged(EvDocumentModel *model, GParamSpec *, EvBrowserPluginToolbar *toolbar)
+{
+        {
+                SignalBlocker fitPageBlocker(toolbar->priv->zoomFitPageRadioButton, zoomFitPageToggled, 
toolbar);
+                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(toolbar->priv->zoomFitPageRadioButton),
+                                               toolbar->priv->plugin->sizingMode() == EV_SIZING_FIT_PAGE);
+        }
+
+        {
+                SignalBlocker fitWidthBlocker(toolbar->priv->zoomFitPageRadioButton, zoomFitWidthToggled, 
toolbar);
+                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(toolbar->priv->zoomFitWidthRadioButton),
+                                               toolbar->priv->plugin->sizingMode() == EV_SIZING_FIT_WIDTH);
+        }
+
+        {
+                SignalBlocker automaticBlocker(toolbar->priv->zoomAutomaticRadioButton, 
zoomAutomaticToggled, toolbar);
+                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(toolbar->priv->zoomAutomaticRadioButton),
+                                               toolbar->priv->plugin->sizingMode() == EV_SIZING_AUTOMATIC);
+        }
+}
+
+static void evBrowserPluginToolbarSetProperty(GObject *object, guint propID, const GValue *value, GParamSpec 
*paramSpec)
+{
+        EvBrowserPluginToolbar *toolbar = EV_BROWSER_PLUGIN_TOOLBAR(object);
+
+        switch (propID) {
+        case PROP_PLUGIN:
+                toolbar->priv->plugin = static_cast<EvBrowserPlugin *>(g_value_get_pointer(value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
+        }
+}
+
+static GtkWidget *createButton(EvBrowserPluginToolbar *toolbar, const char *iconName, const char 
*description, GCallback callback)
+{
+        GtkWidget *button = gtk_button_new();
+
+        gtk_widget_set_valign(button, GTK_ALIGN_CENTER);
+        gtk_widget_set_tooltip_text(button, description);
+        gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_icon_name(iconName, GTK_ICON_SIZE_MENU));
+        gtk_button_set_label(GTK_BUTTON(button), nullptr);
+        gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
+        g_signal_connect_swapped(button, "clicked", callback, toolbar);
+
+        return button;
+}
+
+static GtkWidget *createToggleButton(EvBrowserPluginToolbar *toolbar, const char *iconName, const char 
*description, bool initialState, GCallback callback)
+{
+        GtkWidget *button = gtk_toggle_button_new();
+
+        gtk_widget_set_valign(button, GTK_ALIGN_CENTER);
+        gtk_widget_set_tooltip_text(button, description);
+        gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_icon_name(iconName, GTK_ICON_SIZE_MENU));
+        gtk_button_set_label(GTK_BUTTON(button), nullptr);
+        gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE);
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), initialState);
+        g_signal_connect_swapped(button, "toggled", callback, toolbar);
+
+        return button;
+}
+
+static GtkWidget *createMenuButton(EvBrowserPluginToolbar *toolbar, const gchar *iconName, GtkWidget *menu, 
GtkAlign menuAlign)
+{
+        GtkWidget *button = gtk_menu_button_new();
+
+        gtk_widget_set_valign(button, GTK_ALIGN_CENTER);
+        gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_icon_name(iconName, GTK_ICON_SIZE_MENU));
+        gtk_widget_set_halign(menu, menuAlign);
+        gtk_menu_button_set_popup(GTK_MENU_BUTTON(button), menu);
+
+        return button;
+}
+
+static GtkWidget *createButtonGroup(EvBrowserPluginToolbar *toolbar)
+{
+        GtkWidget *box = gtk_box_new(gtk_orientable_get_orientation(GTK_ORIENTABLE(toolbar)), 0);
+
+        GtkStyleContext *styleContext = gtk_widget_get_style_context(box);
+        gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_RAISED);
+        gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_LINKED);
+
+        return box;
+}
+
+static GtkWidget *createSizingModeMenu(EvBrowserPluginToolbar *toolbar)
+{
+        GtkWidget *menu = gtk_menu_new();
+
+        GtkWidget *menuItem = gtk_check_menu_item_new_with_mnemonic(_("Fit Pa_ge"));
+        toolbar->priv->zoomFitPageRadioButton = menuItem;
+        gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(menuItem), TRUE);
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuItem),
+                                       toolbar->priv->plugin->sizingMode() == EV_SIZING_FIT_PAGE);
+        g_signal_connect_swapped(menuItem, "toggled", G_CALLBACK(zoomFitPageToggled), toolbar);
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
+        gtk_widget_show(menuItem);
+
+        menuItem = gtk_check_menu_item_new_with_mnemonic(_("Fit _Width"));
+        toolbar->priv->zoomFitWidthRadioButton = menuItem;
+        gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(menuItem), TRUE);
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuItem),
+                                       toolbar->priv->plugin->sizingMode() == EV_SIZING_FIT_WIDTH);
+        g_signal_connect_swapped(menuItem, "toggled", G_CALLBACK(zoomFitWidthToggled), toolbar);
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
+        gtk_widget_show(menuItem);
+
+        menuItem = gtk_check_menu_item_new_with_mnemonic(_("_Automatic"));
+        toolbar->priv->zoomAutomaticRadioButton = menuItem;
+        gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(menuItem), TRUE);
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuItem),
+                                       toolbar->priv->plugin->sizingMode() == EV_SIZING_AUTOMATIC);
+        g_signal_connect_swapped(menuItem, "toggled", G_CALLBACK(zoomAutomaticToggled), toolbar);
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
+        gtk_widget_show(menuItem);
+
+        g_signal_connect(toolbar->priv->plugin->model(), "notify::sizing-mode",
+                         G_CALLBACK(sizingModeChanged), toolbar);
+
+        return menu;
+}
+
+static void evBrowserPluginToolbarConstructed(GObject *object)
+{
+        G_OBJECT_CLASS(ev_browser_plugin_toolbar_parent_class)->constructed(object);
+
+        EvBrowserPluginToolbar *toolbar = EV_BROWSER_PLUGIN_TOOLBAR(object);
+        bool rtl = gtk_widget_get_direction(GTK_WIDGET(toolbar)) == GTK_TEXT_DIR_RTL;
+
+        GtkWidget *hbox = createButtonGroup(toolbar);
+
+        // Navigation buttons
+        GtkWidget *button = createButton(toolbar, "go-up-symbolic", _("Go to the previous page"), 
G_CALLBACK(goToPreviousPage));
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        button = createButton(toolbar, "go-down-symbolic", _("Go to the next page"), 
G_CALLBACK(goToNextPage));
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        GtkWidget *toolItem = GTK_WIDGET(gtk_tool_item_new());
+        if (rtl)
+                gtk_widget_set_margin_left(toolItem, 12);
+        else
+                gtk_widget_set_margin_right(toolItem, 12);
+        gtk_container_add(GTK_CONTAINER(toolItem), hbox);
+        gtk_widget_show(hbox);
+
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+
+        // Page Selector
+        toolItem = GTK_WIDGET(g_object_new(EV_TYPE_PAGE_ACTION_WIDGET, nullptr));
+        ev_page_action_widget_set_model(EV_PAGE_ACTION_WIDGET(toolItem), toolbar->priv->plugin->model());
+        g_signal_connect_swapped(toolItem, "activate-link", G_CALLBACK(activateLink), toolbar);
+        if (rtl)
+                gtk_widget_set_margin_left(toolItem, 12);
+        else
+                gtk_widget_set_margin_right(toolItem, 12);
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+
+        // Search.
+        button = createToggleButton(toolbar, "edit-find-symbolic", _("Find a word or phrase in the 
document"),
+                                    false, G_CALLBACK(toggleSearch));
+        toolbar->priv->searchToggleButton = button;
+        toolItem = GTK_WIDGET(gtk_tool_item_new());
+        gtk_container_add(GTK_CONTAINER(toolItem), button);
+        gtk_widget_show(button);
+
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+
+        // Separator
+        toolItem = GTK_WIDGET(gtk_tool_item_new());
+        gtk_tool_item_set_expand(GTK_TOOL_ITEM(toolItem), TRUE);
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+
+        // View mode
+        hbox = createButtonGroup(toolbar);
+
+        button = createToggleButton(toolbar, "view-continuous-symbolic", _("Show the entire document"),
+                                    toolbar->priv->plugin->isContinuous(), G_CALLBACK(toggleContinuous));
+        toolbar->priv->continuousToggleButton = button;
+        g_signal_connect(toolbar->priv->plugin->model(), "notify::continuous",
+                         G_CALLBACK(continuousChanged), toolbar);
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        button = createToggleButton(toolbar, "view-dual-symbolic", _("Show two pages at once"),
+                                    toolbar->priv->plugin->isDual(), G_CALLBACK(toggleDual));
+        toolbar->priv->dualToggleButton = button;
+        g_signal_connect(toolbar->priv->plugin->model(), "notify::dual-page",
+                         G_CALLBACK(dualPageChanged), toolbar);
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        toolItem = GTK_WIDGET(gtk_tool_item_new());
+        if (rtl)
+                gtk_widget_set_margin_left(toolItem, 12);
+        else
+                gtk_widget_set_margin_right(toolItem, 12);
+        gtk_container_add(GTK_CONTAINER(toolItem), hbox);
+        gtk_widget_show(hbox);
+
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+
+        // Zoom
+        hbox = createButtonGroup(toolbar);
+
+        button = createButton(toolbar, "zoom-in-symbolic", _("Enlarge the document"), G_CALLBACK(zoomIn));
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        button = createButton(toolbar, "zoom-out-symbolic", _("Shrink the document"), G_CALLBACK(zoomOut));
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        button = createMenuButton(toolbar, "pan-down-symbolic", createSizingModeMenu(toolbar), 
GTK_ALIGN_END);
+        gtk_container_add(GTK_CONTAINER(hbox), button);
+        gtk_widget_show(button);
+
+        toolItem = GTK_WIDGET(gtk_tool_item_new());
+        if (rtl)
+                gtk_widget_set_margin_left(toolItem, 12);
+        else
+                gtk_widget_set_margin_right(toolItem, 12);
+        gtk_container_add(GTK_CONTAINER(toolItem), hbox);
+        gtk_widget_show(hbox);
+
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+
+        // Actions
+        // Only add download button if browser is Epiphany for now.
+        if (toolbar->priv->plugin->canDownload()) {
+                button = createButton(toolbar, "folder-download-symbolic", _("Download document"), 
G_CALLBACK(downloadDocument));
+                toolItem = GTK_WIDGET(gtk_tool_item_new());
+                gtk_container_add(GTK_CONTAINER(toolItem), button);
+                gtk_widget_show(button);
+                if (rtl)
+                        gtk_widget_set_margin_left(toolItem, 6);
+                else
+                        gtk_widget_set_margin_right(toolItem, 6);
+
+                gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+                gtk_widget_show(toolItem);
+        }
+
+        button = createButton(toolbar, "printer-symbolic", _("Print document"), G_CALLBACK(printDocument));
+        toolItem = GTK_WIDGET(gtk_tool_item_new());
+        gtk_container_add(GTK_CONTAINER(toolItem), button);
+        gtk_widget_show(button);
+
+        gtk_container_add(GTK_CONTAINER(toolbar), toolItem);
+        gtk_widget_show(toolItem);
+}
+
+static void evBrowserPluginToolbarDispose(GObject *object)
+{
+        EvBrowserPluginToolbar *toolbar = EV_BROWSER_PLUGIN_TOOLBAR(object);
+        if (toolbar->priv->searchPopover) {
+                gtk_widget_destroy(toolbar->priv->searchPopover);
+                toolbar->priv->searchPopover = nullptr;
+        }
+
+        G_OBJECT_CLASS(ev_browser_plugin_toolbar_parent_class)->dispose(object);
+}
+
+static void ev_browser_plugin_toolbar_class_init(EvBrowserPluginToolbarClass *klass)
+{
+        GObjectClass *gObjectClass = G_OBJECT_CLASS(klass);
+        gObjectClass->set_property = evBrowserPluginToolbarSetProperty;
+        gObjectClass->constructed = evBrowserPluginToolbarConstructed;
+        gObjectClass->dispose = evBrowserPluginToolbarDispose;
+
+        g_object_class_install_property(gObjectClass,
+                                         PROP_PLUGIN,
+                                         g_param_spec_pointer("plugin",
+                                                              "Plugin",
+                                                              "The plugin",
+                                                              static_cast<GParamFlags>(G_PARAM_WRITABLE | 
G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)));
+
+        g_type_class_add_private(gObjectClass, sizeof(EvBrowserPluginToolbarPrivate));
+}
+
+static void ev_browser_plugin_toolbar_init(EvBrowserPluginToolbar *toolbar)
+{
+        toolbar->priv = G_TYPE_INSTANCE_GET_PRIVATE(toolbar, EV_TYPE_BROWSER_PLUGIN_TOOLBAR, 
EvBrowserPluginToolbarPrivate);
+}
+
+GtkWidget *ev_browser_plugin_toolbar_new(EvBrowserPlugin *plugin)
+{
+        return GTK_WIDGET(g_object_new(EV_TYPE_BROWSER_PLUGIN_TOOLBAR, "plugin", plugin, nullptr));
+}
diff --git a/browser-plugin/EvBrowserPluginToolbar.h b/browser-plugin/EvBrowserPluginToolbar.h
new file mode 100644
index 00000000..52049b5b
--- /dev/null
+++ b/browser-plugin/EvBrowserPluginToolbar.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EvBrowserPluginToolbar_h
+#define EvBrowserPluginToolbar_h
+
+#include "EvBrowserPlugin.h"
+#include <gtk/gtk.h>
+#include <evince-view.h>
+
+G_BEGIN_DECLS
+
+#define EV_TYPE_BROWSER_PLUGIN_TOOLBAR              (ev_browser_plugin_toolbar_get_type())
+#define EV_BROWSER_PLUGIN_TOOLBAR(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), 
EV_TYPE_BROWSER_PLUGIN_TOOLBAR, EvBrowserPluginToolbar))
+#define EV_IS_BROWSER_PLUGIN_TOOLBAR(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), 
EV_TYPE_BROWSER_PLUGIN_TOOLBAR))
+#define EV_BROWSER_PLUGIN_TOOLBAR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), 
EV_TYPE_BROWSER_PLUGIN_TOOLBAR, EvBrowserPluginToolbarClass))
+#define EV_IS_BROWSER_PLUGIN_TOOLBAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), 
EV_TYPE_BROWSER_PLUGIN_TOOLBAR))
+#define EV_BROWSER_PLUGIN_TOOLBAR_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), 
EV_TYPE_BROWSER_PLUGIN_TOOLBAR, EvBrowserPluginToolbarClass))
+
+typedef struct _EvBrowserPluginToolbar        EvBrowserPluginToolbar;
+typedef struct _EvBrowserPluginToolbarClass   EvBrowserPluginToolbarClass;
+typedef struct _EvBrowserPluginToolbarPrivate EvBrowserPluginToolbarPrivate;
+
+struct _EvBrowserPluginToolbar {
+        GtkToolbar base_instance;
+
+        EvBrowserPluginToolbarPrivate *priv;
+};
+
+struct _EvBrowserPluginToolbarClass {
+        GtkToolbarClass base_class;
+};
+
+GType      ev_browser_plugin_toolbar_get_type (void);
+GtkWidget *ev_browser_plugin_toolbar_new      (EvBrowserPlugin *plugin);
+
+G_END_DECLS
+
+#endif // EvBrowserPluginToolbar_h
diff --git a/browser-plugin/EvMemoryUtils.h b/browser-plugin/EvMemoryUtils.h
new file mode 100644
index 00000000..38d25119
--- /dev/null
+++ b/browser-plugin/EvMemoryUtils.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Evince is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Evince 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EvMemoryUtils_h
+#define EvMemoryUtils_h
+
+#include <glib.h>
+#include <memory>
+
+template<typename T>
+struct unique_gptr_deleter {
+        void operator()(T* ptr) const { g_free(ptr); }
+};
+
+template<typename T>
+using unique_gptr = std::unique_ptr<T, unique_gptr_deleter<T>>;
+
+#endif // EvMemoryUtils_h
diff --git a/browser-plugin/Makefile.am b/browser-plugin/Makefile.am
new file mode 100644
index 00000000..6636c4f6
--- /dev/null
+++ b/browser-plugin/Makefile.am
@@ -0,0 +1,67 @@
+plugindir = $(BROWSER_PLUGIN_DIR)
+plugin_LTLIBRARIES = libevbrowserplugin.la
+
+npapi_sources = \
+       npapi/npapi.h \
+       npapi/npfunctions.h \
+       npapi/npruntime.h \
+       npapi/nptypes.h
+
+libevbrowserplugin_la_SOURCES = \
+       $(npapi_sources) \
+       EvBrowserPluginMain.cpp \
+       EvBrowserPlugin.h \
+       EvBrowserPlugin.cpp \
+       EvBrowserPluginToolbar.h \
+       EvBrowserPluginToolbar.cpp \
+       EvMemoryUtils.h
+
+nodist_libevbrowserplugin_la_SOURCES = \
+       EvBrowserPluginResources.c
+
+libevbrowserplugin_la_CPPFLAGS = \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/browser-plugin/npapi \
+       -I$(top_srcdir)/libdocument \
+       -I$(top_srcdir)/libview \
+       -I$(top_srcdir)/libmisc \
+       -DGNOMELOCALEDIR=\"$(datadir)/locale\" \
+       -DEVINCE_COMPILATION \
+       -DXP_UNIX \
+       -DMOZ_X11 \
+       $(BROWSER_PLUGIN_CFLAGS) \
+       $(AM_CPPFLAGS)
+
+libevbrowserplugin_la_CXXFLAGS = \
+       -std=c++11 \
+       -fno-exceptions \
+       -fno-strict-aliasing \
+       -fno-rtti \
+       $(AM_CXXFLAGS)
+
+libevbrowserplugin_la_LDFLAGS = \
+       -avoid-version \
+       -export-symbols $(top_srcdir)/browser-plugin/plugin.symbols \
+       -module \
+       -no-undefined \
+       -Wl,-z,nodelete \
+       $(AM_LDFLAGS)
+
+libevbrowserplugin_la_LIBADD = \
+       $(top_builddir)/libdocument/libevdocument3.la \
+       $(top_builddir)/libview/libevview3.la \
+       $(top_builddir)/libmisc/libevmisc.la \
+       $(BROWSER_PLUGIN_LIBS)
+
+EvBrowserPluginResources.c: EvBrowserPlugin.gresource.xml Makefile $(shell $(GLIB_COMPILE_RESOURCES) 
--generate-dependencies --sourcedir=$(srcdir) --sourcedir=$(top_srcdir)/data 
$(srcdir)/EvBrowserPlugin.gresource.xml)
+       $(AM_V_GEN) XMLLINT=$(XMLLINT) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) 
--sourcedir=$(top_srcdir)/data --generate-source $<
+
+EXTRA_DIST = \
+       EvBrowserPlugin.gresource.xml \
+       evince-browser.css \
+       plugin.symbols
+
+CLEANFILES = \
+       EvBrowserPluginResources.c
+
+-include $(top_srcdir)/git.mk
diff --git a/browser-plugin/evince-browser.css b/browser-plugin/evince-browser.css
new file mode 100644
index 00000000..2273f51c
--- /dev/null
+++ b/browser-plugin/evince-browser.css
@@ -0,0 +1,19 @@
+.content-view.document-page {
+    border-style: solid;
+    border-width: 3px 3px 6px 4px;
+    border-image: url("resource:///org/gnome/evince/browser/ui/thumbnail-frame.png") 3 3 6 4;
+    background-color: @theme_bg_color;
+}
+
+EvView {
+    background-color: @theme_bg_color;
+}
+
+EvView:selected {
+    background-color: @theme_selected_bg_color;
+}
+
+EvView.document-page {
+    background-color: white;
+    padding: 0;
+}
diff --git a/browser-plugin/meson.build b/browser-plugin/meson.build
new file mode 100644
index 00000000..af1dc699
--- /dev/null
+++ b/browser-plugin/meson.build
@@ -0,0 +1,55 @@
+sources = files(
+  'EvBrowserPlugin.cpp',
+  'EvBrowserPluginMain.cpp',
+  'EvBrowserPluginToolbar.cpp',
+)
+
+resource_data = files(
+  '../data/thumbnail-frame.png',
+  'evince-browser.css',
+)
+
+resource = 'EvBrowserPlugin'
+
+sources += gnome.compile_resources(
+  resource + 'Resources',
+  resource + '.gresource.xml',
+  source_dir: data_dir,
+  dependencies: resource_data,
+  export: true,
+)
+
+incs = [
+  top_inc,
+  include_directories('npapi'),
+]
+
+cflags = [
+  '-DGNOMELOCALEDIR="@0@"'.format(ev_localedir),
+  '-DEVINCE_COMPILATION',
+  '-DMOZ_X11',
+  '-DXP_UNIX',
+]
+
+cppflags = cflags + cc.get_supported_arguments([
+  '-std=c++11',
+  '-fno-exceptions',
+  '-fno-strict-aliasing',
+  '-fno-rtti',
+])
+
+symbol_map = join_paths(meson.current_source_dir(), 'plugin-symbol.map')
+ldflag = cpp.get_supported_link_arguments([
+  '-Wl,--version-script,' + symbol_map,
+  '-Wl,-z,nodelete',
+])
+
+shared_module(
+  'evbrowserplugin',
+  sources: sources,
+  include_directories: incs,
+  dependencies: libevmisc_dep,
+  cpp_args: cppflags,
+  install: true,
+  install_dir: browser_plugin_dir,
+)
diff --git a/browser-plugin/npapi/npapi.h b/browser-plugin/npapi/npapi.h
new file mode 100644
index 00000000..3d08b2ca
--- /dev/null
+++ b/browser-plugin/npapi/npapi.h
@@ -0,0 +1,914 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef npapi_h_
+#define npapi_h_
+
+#if defined(__OS2__)
+#pragma pack(1)
+#endif
+
+#include "nptypes.h"
+
+#if defined(__OS2__) || defined(OS2)
+#ifndef XP_OS2
+#define XP_OS2 1
+#endif
+#endif
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+#include <windef.h>
+#ifndef XP_WIN
+#define XP_WIN 1
+#endif
+#endif
+
+#if defined(__SYMBIAN32__)
+#ifndef XP_SYMBIAN
+#define XP_SYMBIAN 1
+#undef XP_WIN
+#endif
+#endif
+
+#if defined(__APPLE_CC__) && !defined(XP_UNIX)
+#ifndef XP_MACOSX
+#define XP_MACOSX 1
+#endif
+#endif
+
+#if defined(XP_MACOSX) && defined(__LP64__)
+#define NP_NO_QUICKDRAW
+#define NP_NO_CARBON
+#endif
+
+#if defined(XP_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#include <OpenGL/OpenGL.h>
+#ifndef NP_NO_CARBON
+#include <Carbon/Carbon.h>
+#endif
+#endif
+
+#if defined(XP_UNIX)
+#include <stdio.h>
+#if defined(MOZ_X11)
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#endif
+#endif
+
+#if defined(XP_SYMBIAN)
+#include <QEvent>
+#include <QRegion>
+#endif
+
+/*----------------------------------------------------------------------*/
+/*                        Plugin Version Constants                      */
+/*----------------------------------------------------------------------*/
+
+#define NP_VERSION_MAJOR 0
+#define NP_VERSION_MINOR 27
+
+
+/* The OS/2 version of Netscape uses RC_DATA to define the
+   mime types, file extensions, etc that are required.
+   Use a vertical bar to separate types, end types with \0.
+   FileVersion and ProductVersion are 32bit ints, all other
+   entries are strings that MUST be terminated with a \0.
+
+AN EXAMPLE:
+
+RCDATA NP_INFO_ProductVersion { 1,0,0,1,}
+
+RCDATA NP_INFO_MIMEType    { "video/x-video|",
+                             "video/x-flick\0" }
+RCDATA NP_INFO_FileExtents { "avi|",
+                             "flc\0" }
+RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",
+                             "MMOS2 Flc/Fli player(*.flc)\0" }
+
+RCDATA NP_INFO_FileVersion       { 1,0,0,1 }
+RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" }
+RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0"
+RCDATA NP_INFO_InternalName      { "NPAVI32\0" )
+RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0"
+RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" }
+RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" }
+*/
+/* RC_DATA types for version info - required */
+#define NP_INFO_ProductVersion      1
+#define NP_INFO_MIMEType            2
+#define NP_INFO_FileOpenName        3
+#define NP_INFO_FileExtents         4
+/* RC_DATA types for version info - used if found */
+#define NP_INFO_FileDescription     5
+#define NP_INFO_ProductName         6
+/* RC_DATA types for version info - optional */
+#define NP_INFO_CompanyName         7
+#define NP_INFO_FileVersion         8
+#define NP_INFO_InternalName        9
+#define NP_INFO_LegalCopyright      10
+#define NP_INFO_OriginalFilename    11
+
+#ifndef RC_INVOKED
+
+/*----------------------------------------------------------------------*/
+/*                       Definition of Basic Types                      */
+/*----------------------------------------------------------------------*/
+
+typedef unsigned char NPBool;
+typedef int16_t       NPError;
+typedef int16_t       NPReason;
+typedef char*         NPMIMEType;
+
+/*----------------------------------------------------------------------*/
+/*                       Structures and definitions                     */
+/*----------------------------------------------------------------------*/
+
+#if !defined(__LP64__)
+#if defined(XP_MACOSX)
+#pragma options align=mac68k
+#endif
+#endif /* __LP64__ */
+
+/*
+ *  NPP is a plug-in's opaque instance handle
+ */
+typedef struct _NPP
+{
+  void* pdata;      /* plug-in private data */
+  void* ndata;      /* netscape private data */
+} NPP_t;
+
+typedef NPP_t*  NPP;
+
+typedef struct _NPStream
+{
+  void*    pdata; /* plug-in private data */
+  void*    ndata; /* netscape private data */
+  const    char* url;
+  uint32_t end;
+  uint32_t lastmodified;
+  void*    notifyData;
+  const    char* headers; /* Response headers from host.
+                           * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS.
+                           * Used for HTTP only; NULL for non-HTTP.
+                           * Available from NPP_NewStream onwards.
+                           * Plugin should copy this data before storing it.
+                           * Includes HTTP status line and all headers,
+                           * preferably verbatim as received from server,
+                           * headers formatted as in HTTP ("Header: Value"),
+                           * and newlines (\n, NOT \r\n) separating lines.
+                           * Terminated by \n\0 (NOT \n\n\0). */
+} NPStream;
+
+typedef struct _NPByteRange
+{
+  int32_t  offset; /* negative offset means from the end */
+  uint32_t length;
+  struct _NPByteRange* next;
+} NPByteRange;
+
+typedef struct _NPSavedData
+{
+  int32_t len;
+  void*   buf;
+} NPSavedData;
+
+typedef struct _NPRect
+{
+  uint16_t top;
+  uint16_t left;
+  uint16_t bottom;
+  uint16_t right;
+} NPRect;
+
+typedef struct _NPSize
+{
+  int32_t width;
+  int32_t height;
+} NPSize;
+
+typedef enum {
+  NPFocusNext = 0,
+  NPFocusPrevious = 1
+} NPFocusDirection;
+
+/* These formats describe the format in the memory byte-order. This means if
+ * a 32-bit value of a pixel is viewed on a little-endian system the layout will
+ * be 0xAARRGGBB. The Alpha channel will be stored in the most significant
+ * bits. */
+typedef enum {
+  /* 32-bit per pixel 8-bit per channel - premultiplied alpha */
+  NPImageFormatBGRA32     = 0x1,
+  /* 32-bit per pixel 8-bit per channel - 1 unused channel */
+  NPImageFormatBGRX32     = 0x2 
+} NPImageFormat;
+
+typedef struct _NPAsyncSurface
+{
+  uint32_t version;
+  NPSize size;
+  NPImageFormat format;
+  union {
+    struct {
+      uint32_t stride;
+      void *data;
+    } bitmap;
+#if defined(XP_WIN)
+    HANDLE sharedHandle;
+#endif
+  };
+} NPAsyncSurface;
+
+/* Return values for NPP_HandleEvent */
+#define kNPEventNotHandled 0
+#define kNPEventHandled 1
+/* Exact meaning must be spec'd in event model. */
+#define kNPEventStartIME 2
+
+#if defined(XP_UNIX)
+/*
+ * Unix specific structures and definitions
+ */
+
+/*
+ * Callback Structures.
+ *
+ * These are used to pass additional platform specific information.
+ */
+enum {
+  NP_SETWINDOW = 1,
+  NP_PRINT
+};
+
+typedef struct
+{
+  int32_t type;
+} NPAnyCallbackStruct;
+
+typedef struct
+{
+  int32_t      type;
+#if defined(MOZ_X11)
+  Display*     display;
+  Visual*      visual;
+  Colormap     colormap;
+  unsigned int depth;
+#endif
+} NPSetWindowCallbackStruct;
+
+typedef struct
+{
+  int32_t type;
+  FILE* fp;
+} NPPrintCallbackStruct;
+
+#endif /* XP_UNIX */
+
+typedef enum {
+#if defined(XP_MACOSX)
+#ifndef NP_NO_QUICKDRAW
+  NPDrawingModelQuickDraw = 0,
+#endif
+  NPDrawingModelCoreGraphics = 1,
+  NPDrawingModelOpenGL = 2,
+  NPDrawingModelCoreAnimation = 3,
+  NPDrawingModelInvalidatingCoreAnimation = 4,
+#endif
+#if defined(XP_WIN)
+  NPDrawingModelSyncWin = 5,
+#endif
+#if defined(MOZ_X11)
+  NPDrawingModelSyncX = 6,
+#endif
+  NPDrawingModelAsyncBitmapSurface = 7
+#if defined(XP_WIN)
+  , NPDrawingModelAsyncWindowsDXGISurface = 8
+#endif
+} NPDrawingModel;
+
+#ifdef XP_MACOSX
+typedef enum {
+#ifndef NP_NO_CARBON
+  NPEventModelCarbon = 0,
+#endif
+  NPEventModelCocoa = 1
+} NPEventModel;
+#endif
+
+/*
+ *   The following masks are applied on certain platforms to NPNV and
+ *   NPPV selectors that pass around pointers to COM interfaces. Newer
+ *   compilers on some platforms may generate vtables that are not
+ *   compatible with older compilers. To prevent older plugins from
+ *   not understanding a new browser's ABI, these masks change the
+ *   values of those selectors on those platforms. To remain backwards
+ *   compatible with different versions of the browser, plugins can
+ *   use these masks to dynamically determine and use the correct C++
+ *   ABI that the browser is expecting. This does not apply to Windows
+ *   as Microsoft's COM ABI will likely not change.
+ */
+
+#define NP_ABI_GCC3_MASK  0x10000000
+/*
+ *   gcc 3.x generated vtables on UNIX and OSX are incompatible with
+ *   previous compilers.
+ */
+#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
+#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
+#else
+#define _NP_ABI_MIXIN_FOR_GCC3 0
+#endif
+
+#if defined(XP_MACOSX)
+#define NP_ABI_MACHO_MASK 0x01000000
+#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK
+#else
+#define _NP_ABI_MIXIN_FOR_MACHO 0
+#endif
+
+#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)
+
+/*
+ * List of variable names for which NPP_GetValue shall be implemented
+ */
+typedef enum {
+  NPPVpluginNameString = 1,
+  NPPVpluginDescriptionString,
+  NPPVpluginWindowBool,
+  NPPVpluginTransparentBool,
+  NPPVjavaClass,
+  NPPVpluginWindowSize,
+  NPPVpluginTimerInterval,
+  NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),
+  NPPVpluginScriptableIID = 11,
+  NPPVjavascriptPushCallerBool = 12,
+  NPPVpluginKeepLibraryInMemory = 13,
+  NPPVpluginNeedsXEmbed         = 14,
+
+  /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14.
+   */
+  NPPVpluginScriptableNPObject  = 15,
+
+  /* Get the plugin value (as \0-terminated UTF-8 string data) for
+   * form submission if the plugin is part of a form. Use
+   * NPN_MemAlloc() to allocate memory for the string data. Introduced
+   * in NPAPI minor version 15.
+   */
+  NPPVformValue = 16,
+
+  NPPVpluginUrlRequestsDisplayedBool = 17,
+
+  /* Checks if the plugin is interested in receiving the http body of
+   * all http requests (including failed ones, http status != 200).
+   */
+  NPPVpluginWantsAllNetworkStreams = 18,
+
+  /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */
+  NPPVpluginNativeAccessibleAtkPlugId = 19,
+
+  /* Checks to see if the plug-in would like the browser to load the "src" attribute. */
+  NPPVpluginCancelSrcStream = 20,
+
+  NPPVsupportsAdvancedKeyHandling = 21,
+
+  NPPVpluginUsesDOMForCursorBool = 22,
+
+  /* Used for negotiating drawing models */
+  NPPVpluginDrawingModel = 1000
+#if defined(XP_MACOSX)
+  /* Used for negotiating event models */
+  , NPPVpluginEventModel = 1001
+  /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation 
layer. */
+  , NPPVpluginCoreAnimationLayer = 1003
+#endif
+
+#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6))
+  , NPPVpluginWindowlessLocalBool = 2002
+#endif
+} NPPVariable;
+
+/*
+ * List of variable names for which NPN_GetValue should be implemented.
+ */
+typedef enum {
+  NPNVxDisplay = 1,
+  NPNVxtAppContext,
+  NPNVnetscapeWindow,
+  NPNVjavascriptEnabledBool,
+  NPNVasdEnabledBool,
+  NPNVisOfflineBool,
+
+  NPNVserviceManager = (10 | NP_ABI_MASK),
+  NPNVDOMElement     = (11 | NP_ABI_MASK),
+  NPNVDOMWindow      = (12 | NP_ABI_MASK),
+  NPNVToolkit        = (13 | NP_ABI_MASK),
+  NPNVSupportsXEmbedBool = 14,
+
+  /* Get the NPObject wrapper for the browser window. */
+  NPNVWindowNPObject = 15,
+
+  /* Get the NPObject wrapper for the plugins DOM element. */
+  NPNVPluginElementNPObject = 16,
+
+  NPNVSupportsWindowless = 17,
+
+  NPNVprivateModeBool = 18,
+
+  NPNVsupportsAdvancedKeyHandling = 21,
+
+  NPNVdocumentOrigin = 22,
+
+  NPNVpluginDrawingModel = 1000 /* Get the current drawing model (NPDrawingModel) */
+#if defined(XP_MACOSX)
+  , NPNVcontentsScaleFactor = 1001
+#ifndef NP_NO_QUICKDRAW
+  , NPNVsupportsQuickDrawBool = 2000
+#endif
+  , NPNVsupportsCoreGraphicsBool = 2001
+  , NPNVsupportsOpenGLBool = 2002
+  , NPNVsupportsCoreAnimationBool = 2003
+  , NPNVsupportsInvalidatingCoreAnimationBool = 2004
+#endif
+  , NPNVsupportsAsyncBitmapSurfaceBool = 2007
+#if defined(XP_WIN)
+  , NPNVsupportsAsyncWindowsDXGISurfaceBool = 2008
+#endif
+#if defined(XP_MACOSX)
+#ifndef NP_NO_CARBON
+  , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */
+#endif
+  , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */
+  , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated
+                                                    Cocoa text input specification. */
+  , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports
+                                                               CA model compositing */
+#endif
+#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6))
+  , NPNVSupportsWindowlessLocal = 2002
+#endif
+} NPNVariable;
+
+typedef enum {
+  NPNURLVCookie = 501,
+  NPNURLVProxy
+} NPNURLVariable;
+
+/*
+ * The type of Toolkit the widgets use
+ */
+typedef enum {
+  NPNVGtk12 = 1,
+  NPNVGtk2
+} NPNToolkitType;
+
+/*
+ * The type of a NPWindow - it specifies the type of the data structure
+ * returned in the window field.
+ */
+typedef enum {
+  NPWindowTypeWindow = 1,
+  NPWindowTypeDrawable
+} NPWindowType;
+
+typedef struct _NPWindow
+{
+  void* window;  /* Platform specific window handle */
+                 /* OS/2: x - Position of bottom left corner */
+                 /* OS/2: y - relative to visible netscape window */
+  int32_t  x;      /* Position of top left corner relative */
+  int32_t  y;      /* to a netscape page. */
+  uint32_t width;  /* Maximum window size */
+  uint32_t height;
+  NPRect   clipRect; /* Clipping rectangle in port coordinates */
+#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX)
+  void * ws_info; /* Platform-dependent additional data */
+#endif /* XP_UNIX */
+  NPWindowType type; /* Is this a window or a drawable? */
+} NPWindow;
+
+typedef struct _NPImageExpose
+{
+  char*    data;       /* image pointer */
+  int32_t  stride;     /* Stride of data image pointer */
+  int32_t  depth;      /* Depth of image pointer */
+  int32_t  x;          /* Expose x */
+  int32_t  y;          /* Expose y */
+  uint32_t width;      /* Expose width */
+  uint32_t height;     /* Expose height */
+  NPSize   dataSize;   /* Data buffer size */
+  float    translateX; /* translate X matrix value */
+  float    translateY; /* translate Y matrix value */
+  float    scaleX;     /* scale X matrix value */
+  float    scaleY;     /* scale Y matrix value */
+} NPImageExpose;
+
+typedef struct _NPFullPrint
+{
+  NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */
+  NPBool printOne;     /* TRUE if plugin should print one copy to default
+                          printer */
+  void* platformPrint; /* Platform-specific printing info */
+} NPFullPrint;
+
+typedef struct _NPEmbedPrint
+{
+  NPWindow window;
+  void* platformPrint; /* Platform-specific printing info */
+} NPEmbedPrint;
+
+typedef struct _NPPrint
+{
+  uint16_t mode;               /* NP_FULL or NP_EMBED */
+  union
+  {
+    NPFullPrint fullPrint;   /* if mode is NP_FULL */
+    NPEmbedPrint embedPrint; /* if mode is NP_EMBED */
+  } print;
+} NPPrint;
+
+#if defined(XP_MACOSX)
+#ifndef NP_NO_CARBON
+typedef EventRecord NPEvent;
+#endif
+#elif defined(XP_SYMBIAN)
+typedef QEvent NPEvent;
+#elif defined(XP_WIN)
+typedef struct _NPEvent
+{
+  uint16_t event;
+  uintptr_t wParam;
+  uintptr_t lParam;
+} NPEvent;
+#elif defined(XP_OS2)
+typedef struct _NPEvent
+{
+  uint32_t event;
+  uint32_t wParam;
+  uint32_t lParam;
+} NPEvent;
+#elif defined(XP_UNIX) && defined(MOZ_X11)
+typedef XEvent NPEvent;
+#else
+typedef void*  NPEvent;
+#endif
+
+#if defined(XP_MACOSX)
+typedef void* NPRegion;
+#ifndef NP_NO_QUICKDRAW
+typedef RgnHandle NPQDRegion;
+#endif
+typedef CGPathRef NPCGRegion;
+#elif defined(XP_WIN)
+typedef HRGN NPRegion;
+#elif defined(XP_UNIX) && defined(MOZ_X11)
+typedef Region NPRegion;
+#elif defined(XP_SYMBIAN)
+typedef QRegion* NPRegion;
+#else
+typedef void *NPRegion;
+#endif
+
+typedef struct _NPNSString NPNSString;
+typedef struct _NPNSWindow NPNSWindow;
+typedef struct _NPNSMenu   NPNSMenu;
+
+#if defined(XP_MACOSX)
+typedef NPNSMenu NPMenu;
+#else
+typedef void *NPMenu;
+#endif
+
+typedef enum {
+  NPCoordinateSpacePlugin = 1,
+  NPCoordinateSpaceWindow,
+  NPCoordinateSpaceFlippedWindow,
+  NPCoordinateSpaceScreen,
+  NPCoordinateSpaceFlippedScreen
+} NPCoordinateSpace;
+
+#if defined(XP_MACOSX)
+
+#ifndef NP_NO_QUICKDRAW
+typedef struct NP_Port
+{
+  CGrafPtr port;
+  int32_t portx; /* position inside the topmost window */
+  int32_t porty;
+} NP_Port;
+#endif /* NP_NO_QUICKDRAW */
+
+/*
+ * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics
+ * as its drawing model.
+ */
+
+typedef struct NP_CGContext
+{
+  CGContextRef context;
+  void *window; /* A WindowRef under the Carbon event model. */
+} NP_CGContext;
+
+/*
+ * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its
+ * drawing model.
+ */
+
+typedef struct NP_GLContext
+{
+  CGLContextObj context;
+#ifdef NP_NO_CARBON
+  NPNSWindow *window;
+#else
+  void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */
+#endif
+} NP_GLContext;
+
+typedef enum {
+  NPCocoaEventDrawRect = 1,
+  NPCocoaEventMouseDown,
+  NPCocoaEventMouseUp,
+  NPCocoaEventMouseMoved,
+  NPCocoaEventMouseEntered,
+  NPCocoaEventMouseExited,
+  NPCocoaEventMouseDragged,
+  NPCocoaEventKeyDown,
+  NPCocoaEventKeyUp,
+  NPCocoaEventFlagsChanged,
+  NPCocoaEventFocusChanged,
+  NPCocoaEventWindowFocusChanged,
+  NPCocoaEventScrollWheel,
+  NPCocoaEventTextInput
+} NPCocoaEventType;
+
+typedef struct _NPCocoaEvent {
+  NPCocoaEventType type;
+  uint32_t version;
+  union {
+    struct {
+      uint32_t modifierFlags;
+      double   pluginX;
+      double   pluginY;
+      int32_t  buttonNumber;
+      int32_t  clickCount;
+      double   deltaX;
+      double   deltaY;
+      double   deltaZ;
+    } mouse;
+    struct {
+      uint32_t    modifierFlags;
+      NPNSString *characters;
+      NPNSString *charactersIgnoringModifiers;
+      NPBool      isARepeat;
+      uint16_t    keyCode;
+    } key;
+    struct {
+      CGContextRef context;
+      double x;
+      double y;
+      double width;
+      double height;
+    } draw;
+    struct {
+      NPBool hasFocus;
+    } focus;
+    struct {
+      NPNSString *text;
+    } text;
+  } data;
+} NPCocoaEvent;
+
+#ifndef NP_NO_CARBON
+/* Non-standard event types that can be passed to HandleEvent */
+enum NPEventType {
+  NPEventType_GetFocusEvent = (osEvt + 16),
+  NPEventType_LoseFocusEvent,
+  NPEventType_AdjustCursorEvent,
+  NPEventType_MenuCommandEvent,
+  NPEventType_ClippingChangedEvent,
+  NPEventType_ScrollingBeginsEvent = 1000,
+  NPEventType_ScrollingEndsEvent
+};
+#endif /* NP_NO_CARBON */
+
+#endif /* XP_MACOSX */
+
+/*
+ * Values for mode passed to NPP_New:
+ */
+#define NP_EMBED 1
+#define NP_FULL  2
+
+/*
+ * Values for stream type passed to NPP_NewStream:
+ */
+#define NP_NORMAL     1
+#define NP_SEEK       2
+#define NP_ASFILE     3
+#define NP_ASFILEONLY 4
+
+#define NP_MAXREADY (((unsigned)(~0)<<1)>>1)
+
+/*
+ * Flags for NPP_ClearSiteData.
+ */
+#define NP_CLEAR_ALL   0
+#define NP_CLEAR_CACHE (1 << 0)
+
+#if !defined(__LP64__)
+#if defined(XP_MACOSX)
+#pragma options align=reset
+#endif
+#endif /* __LP64__ */
+
+/*----------------------------------------------------------------------*/
+/*       Error and Reason Code definitions                              */
+/*----------------------------------------------------------------------*/
+
+/*
+ * Values of type NPError:
+ */
+#define NPERR_BASE                         0
+#define NPERR_NO_ERROR                    (NPERR_BASE + 0)
+#define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)
+#define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)
+#define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)
+#define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)
+#define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)
+#define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)
+#define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)
+#define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)
+#define NPERR_INVALID_PARAM               (NPERR_BASE + 9)
+#define NPERR_INVALID_URL                 (NPERR_BASE + 10)
+#define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)
+#define NPERR_NO_DATA                     (NPERR_BASE + 12)
+#define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)
+#define NPERR_TIME_RANGE_NOT_SUPPORTED    (NPERR_BASE + 14)
+#define NPERR_MALFORMED_SITE              (NPERR_BASE + 15)
+
+/*
+ * Values of type NPReason:
+ */
+#define NPRES_BASE          0
+#define NPRES_DONE         (NPRES_BASE + 0)
+#define NPRES_NETWORK_ERR  (NPRES_BASE + 1)
+#define NPRES_USER_BREAK   (NPRES_BASE + 2)
+
+/*
+ * Don't use these obsolete error codes any more.
+ */
+#define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR
+#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR
+#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK
+
+/*
+ * Version feature information
+ */
+#define NPVERS_HAS_STREAMOUTPUT             8
+#define NPVERS_HAS_NOTIFICATION             9
+#define NPVERS_HAS_LIVECONNECT              9
+#define NPVERS_68K_HAS_LIVECONNECT          11
+#define NPVERS_HAS_WINDOWLESS               11
+#define NPVERS_HAS_XPCONNECT_SCRIPTING      13
+#define NPVERS_HAS_NPRUNTIME_SCRIPTING      14
+#define NPVERS_HAS_FORM_VALUES              15
+#define NPVERS_HAS_POPUPS_ENABLED_STATE     16
+#define NPVERS_HAS_RESPONSE_HEADERS         17
+#define NPVERS_HAS_NPOBJECT_ENUM            18
+#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
+#define NPVERS_HAS_ALL_NETWORK_STREAMS      20
+#define NPVERS_HAS_URL_AND_AUTH_INFO        21
+#define NPVERS_HAS_PRIVATE_MODE             22
+#define NPVERS_MACOSX_HAS_COCOA_EVENTS      23
+#define NPVERS_HAS_ADVANCED_KEY_HANDLING    25
+#define NPVERS_HAS_URL_REDIRECT_HANDLING    26
+#define NPVERS_HAS_CLEAR_SITE_DATA          27
+
+/*----------------------------------------------------------------------*/
+/*                        Function Prototypes                           */
+/*----------------------------------------------------------------------*/
+
+#if defined(__OS2__)
+#define NP_LOADDS _System
+#else
+#define NP_LOADDS
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NPP_* functions are provided by the plugin and called by the navigator. */
+
+#if defined(XP_UNIX)
+const char* NPP_GetMIMEDescription(void);
+#endif
+
+NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,
+                          uint16_t mode, int16_t argc, char* argn[],
+                          char* argv[], NPSavedData* saved);
+NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);
+NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);
+NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,
+                                NPStream* stream, NPBool seekable,
+                                uint16_t* stype);
+NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,
+                                    NPReason reason);
+int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);
+int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset,
+                            int32_t len, void* buffer);
+void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,
+                                   const char* fname);
+void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);
+int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event);
+void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
+                                NPReason reason, void* notifyData);
+NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
+NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
+NPBool  NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction);
+void    NP_LOADDS NPP_LostFocus(NPP instance);
+void    NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData);
+NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge);
+char**  NP_LOADDS NPP_GetSitesWithData(void);
+void    NP_LOADDS NPP_DidComposite(NPP instance);
+
+/* NPN_* functions are provided by the navigator and called by the plugin. */
+void        NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
+                                  int* netscape_major, int* netscape_minor);
+NPError     NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,
+                                       const char* target, void* notifyData);
+NPError     NP_LOADDS NPN_GetURL(NPP instance, const char* url,
+                                 const char* target);
+NPError     NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,
+                                        const char* target, uint32_t len,
+                                        const char* buf, NPBool file,
+                                        void* notifyData);
+NPError     NP_LOADDS NPN_PostURL(NPP instance, const char* url,
+                                  const char* target, uint32_t len,
+                                  const char* buf, NPBool file);
+NPError     NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);
+NPError     NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,
+                                    const char* target, NPStream** stream);
+int32_t     NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len,
+                                void* buffer);
+NPError     NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream,
+                                        NPReason reason);
+void        NP_LOADDS NPN_Status(NPP instance, const char* message);
+const char* NP_LOADDS NPN_UserAgent(NPP instance);
+void*       NP_LOADDS NPN_MemAlloc(uint32_t size);
+void        NP_LOADDS NPN_MemFree(void* ptr);
+uint32_t    NP_LOADDS NPN_MemFlush(uint32_t size);
+void        NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);
+NPError     NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable,
+                                   void *value);
+NPError     NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable,
+                                   void *value);
+void        NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
+void        NP_LOADDS NPN_InvalidateRegion(NPP instance,
+                                           NPRegion invalidRegion);
+void        NP_LOADDS NPN_ForceRedraw(NPP instance);
+void        NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
+void        NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
+void        NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
+                                                void (*func) (void *),
+                                                void *userData);
+NPError     NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable,
+                                         const char *url, char **value,
+                                         uint32_t *len);
+NPError     NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable,
+                                         const char *url, const char *value,
+                                         uint32_t len);
+NPError     NP_LOADDS NPN_GetAuthenticationInfo(NPP instance,
+                                                const char *protocol,
+                                                const char *host, int32_t port,
+                                                const char *scheme,
+                                                const char *realm,
+                                                char **username, uint32_t *ulen,
+                                                char **password,
+                                                uint32_t *plen);
+uint32_t    NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void 
(*timerFunc)(NPP npp, uint32_t timerID));
+void        NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID);
+NPError     NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu);
+NPBool      NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace 
sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
+NPBool      NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled);
+NPBool      NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction);
+void        NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow);
+NPError     NP_LOADDS NPN_InitAsyncSurface(NPP instance, NPSize *size,
+                                           NPImageFormat format, void *initData,
+                                           NPAsyncSurface *surface);
+NPError     NP_LOADDS NPN_FinalizeAsyncSurface(NPP instance, NPAsyncSurface *surface);
+void        NP_LOADDS NPN_SetCurrentAsyncSurface(NPP instance, NPAsyncSurface *surface, NPRect *changed);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* RC_INVOKED */
+#if defined(__OS2__)
+#pragma pack()
+#endif
+
+#endif /* npapi_h_ */
diff --git a/browser-plugin/npapi/npfunctions.h b/browser-plugin/npapi/npfunctions.h
new file mode 100644
index 00000000..5207d3e4
--- /dev/null
+++ b/browser-plugin/npapi/npfunctions.h
@@ -0,0 +1,307 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef npfunctions_h_
+#define npfunctions_h_
+
+#ifdef __OS2__
+#pragma pack(1)
+#define NP_LOADDS _System
+#else
+#define NP_LOADDS
+#endif
+
+#include "npapi.h"
+#include "npruntime.h"
+
+#ifdef MOZ_WIDGET_ANDROID
+#include <jni.h>
+#endif
+
+typedef NPError      (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, 
int16_t argc, char* argn[], char* argv[], NPSavedData* saved);
+typedef NPError      (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save);
+typedef NPError      (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window);
+typedef NPError      (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, 
NPBool seekable, uint16_t* stype);
+typedef NPError      (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
+typedef int32_t      (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream);
+typedef int32_t      (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t 
len, void* buffer);
+typedef void         (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* 
fname);
+typedef void         (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint);
+typedef int16_t      (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event);
+typedef void         (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, 
void* notifyData);
+/* Any NPObjects returned to the browser via NPP_GetValue should be retained
+   by the plugin on the way out. The browser is responsible for releasing. */
+typedef NPError      (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value);
+typedef NPError      (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value);
+typedef NPBool       (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction);
+typedef void         (* NP_LOADDS NPP_LostFocusPtr)(NPP instance);
+typedef void         (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, 
void* notifyData);
+typedef NPError      (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge);
+typedef char**       (* NP_LOADDS NPP_GetSitesWithDataPtr)(void);
+typedef void         (* NP_LOADDS NPP_DidCompositePtr)(NPP instance);
+
+typedef NPError      (*NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value);
+typedef NPError      (*NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value);
+typedef NPError      (*NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* 
notifyData);
+typedef NPError      (*NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t 
len, const char* buf, NPBool file, void* notifyData);
+typedef NPError      (*NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window);
+typedef NPError      (*NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, 
const char* buf, NPBool file);
+typedef NPError      (*NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList);
+typedef NPError      (*NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** 
stream);
+typedef int32_t      (*NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer);
+typedef NPError      (*NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason);
+typedef void         (*NPN_StatusProcPtr)(NPP instance, const char* message);
+/* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't
+   depend on it sticking around and don't free it. */
+typedef const char*  (*NPN_UserAgentProcPtr)(NPP instance);
+typedef void*        (*NPN_MemAllocProcPtr)(uint32_t size);
+typedef void         (*NPN_MemFreeProcPtr)(void* ptr);
+typedef uint32_t     (*NPN_MemFlushProcPtr)(uint32_t size);
+typedef void         (*NPN_ReloadPluginsProcPtr)(NPBool reloadPages);
+typedef void*        (*NPN_GetJavaEnvProcPtr)(void);
+typedef void*        (*NPN_GetJavaPeerProcPtr)(NPP instance);
+typedef void         (*NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect);
+typedef void         (*NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region);
+typedef void         (*NPN_ForceRedrawProcPtr)(NPP instance);
+typedef NPIdentifier (*NPN_GetStringIdentifierProcPtr)(const NPUTF8* name);
+typedef void         (*NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, 
NPIdentifier* identifiers);
+typedef NPIdentifier (*NPN_GetIntIdentifierProcPtr)(int32_t intid);
+typedef bool         (*NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier);
+typedef NPUTF8*      (*NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier);
+typedef int32_t      (*NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier);
+typedef NPObject*    (*NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass);
+typedef NPObject*    (*NPN_RetainObjectProcPtr)(NPObject *obj);
+typedef void         (*NPN_ReleaseObjectProcPtr)(NPObject *obj);
+typedef bool         (*NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant 
*args, uint32_t argCount, NPVariant *result);
+typedef bool         (*NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t 
argCount, NPVariant *result);
+typedef bool         (*NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result);
+typedef bool         (*NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant 
*result);
+typedef bool         (*NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const 
NPVariant *value);
+typedef bool         (*NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef bool         (*NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef bool         (*NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+typedef void         (*NPN_ReleaseVariantValueProcPtr)(NPVariant *variant);
+typedef void         (*NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message);
+typedef void         (*NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled);
+typedef void         (*NPN_PopPopupsEnabledStateProcPtr)(NPP npp);
+typedef bool         (*NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t 
*count);
+typedef void         (*NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData);
+typedef bool         (*NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t 
argCount, NPVariant *result);
+typedef NPError      (*NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char 
**value, uint32_t *len);
+typedef NPError      (*NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char 
*value, uint32_t len);
+typedef NPError      (*NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, 
int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, 
uint32_t *plen);
+typedef uint32_t     (*NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void 
(*timerFunc)(NPP npp, uint32_t timerID));
+typedef void         (*NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID);
+typedef NPError      (*NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu);
+typedef NPBool       (*NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace 
sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
+typedef NPBool       (*NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled);
+typedef NPBool       (*NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction);
+typedef void         (*NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow);
+typedef NPError      (*NPN_InitAsyncSurfacePtr)(NPP instance, NPSize *size, NPImageFormat format, void 
*initData, NPAsyncSurface *surface);
+typedef NPError      (*NPN_FinalizeAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface);
+typedef void         (*NPN_SetCurrentAsyncSurfacePtr)(NPP instance, NPAsyncSurface *surface, NPRect 
*changed);
+
+typedef struct _NPPluginFuncs {
+  uint16_t size;
+  uint16_t version;
+  NPP_NewProcPtr newp;
+  NPP_DestroyProcPtr destroy;
+  NPP_SetWindowProcPtr setwindow;
+  NPP_NewStreamProcPtr newstream;
+  NPP_DestroyStreamProcPtr destroystream;
+  NPP_StreamAsFileProcPtr asfile;
+  NPP_WriteReadyProcPtr writeready;
+  NPP_WriteProcPtr write;
+  NPP_PrintProcPtr print;
+  NPP_HandleEventProcPtr event;
+  NPP_URLNotifyProcPtr urlnotify;
+  void* javaClass;
+  NPP_GetValueProcPtr getvalue;
+  NPP_SetValueProcPtr setvalue;
+  NPP_GotFocusPtr gotfocus;
+  NPP_LostFocusPtr lostfocus;
+  NPP_URLRedirectNotifyPtr urlredirectnotify;
+  NPP_ClearSiteDataPtr clearsitedata;
+  NPP_GetSitesWithDataPtr getsiteswithdata;
+  NPP_DidCompositePtr didComposite;
+} NPPluginFuncs;
+
+typedef struct _NPNetscapeFuncs {
+  uint16_t size;
+  uint16_t version;
+  NPN_GetURLProcPtr geturl;
+  NPN_PostURLProcPtr posturl;
+  NPN_RequestReadProcPtr requestread;
+  NPN_NewStreamProcPtr newstream;
+  NPN_WriteProcPtr write;
+  NPN_DestroyStreamProcPtr destroystream;
+  NPN_StatusProcPtr status;
+  NPN_UserAgentProcPtr uagent;
+  NPN_MemAllocProcPtr memalloc;
+  NPN_MemFreeProcPtr memfree;
+  NPN_MemFlushProcPtr memflush;
+  NPN_ReloadPluginsProcPtr reloadplugins;
+  NPN_GetJavaEnvProcPtr getJavaEnv;
+  NPN_GetJavaPeerProcPtr getJavaPeer;
+  NPN_GetURLNotifyProcPtr geturlnotify;
+  NPN_PostURLNotifyProcPtr posturlnotify;
+  NPN_GetValueProcPtr getvalue;
+  NPN_SetValueProcPtr setvalue;
+  NPN_InvalidateRectProcPtr invalidaterect;
+  NPN_InvalidateRegionProcPtr invalidateregion;
+  NPN_ForceRedrawProcPtr forceredraw;
+  NPN_GetStringIdentifierProcPtr getstringidentifier;
+  NPN_GetStringIdentifiersProcPtr getstringidentifiers;
+  NPN_GetIntIdentifierProcPtr getintidentifier;
+  NPN_IdentifierIsStringProcPtr identifierisstring;
+  NPN_UTF8FromIdentifierProcPtr utf8fromidentifier;
+  NPN_IntFromIdentifierProcPtr intfromidentifier;
+  NPN_CreateObjectProcPtr createobject;
+  NPN_RetainObjectProcPtr retainobject;
+  NPN_ReleaseObjectProcPtr releaseobject;
+  NPN_InvokeProcPtr invoke;
+  NPN_InvokeDefaultProcPtr invokeDefault;
+  NPN_EvaluateProcPtr evaluate;
+  NPN_GetPropertyProcPtr getproperty;
+  NPN_SetPropertyProcPtr setproperty;
+  NPN_RemovePropertyProcPtr removeproperty;
+  NPN_HasPropertyProcPtr hasproperty;
+  NPN_HasMethodProcPtr hasmethod;
+  NPN_ReleaseVariantValueProcPtr releasevariantvalue;
+  NPN_SetExceptionProcPtr setexception;
+  NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate;
+  NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate;
+  NPN_EnumerateProcPtr enumerate;
+  NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall;
+  NPN_ConstructProcPtr construct;
+  NPN_GetValueForURLPtr getvalueforurl;
+  NPN_SetValueForURLPtr setvalueforurl;
+  NPN_GetAuthenticationInfoPtr getauthenticationinfo;
+  NPN_ScheduleTimerPtr scheduletimer;
+  NPN_UnscheduleTimerPtr unscheduletimer;
+  NPN_PopUpContextMenuPtr popupcontextmenu;
+  NPN_ConvertPointPtr convertpoint;
+  NPN_HandleEventPtr handleevent;
+  NPN_UnfocusInstancePtr unfocusinstance;
+  NPN_URLRedirectResponsePtr urlredirectresponse;
+  NPN_InitAsyncSurfacePtr initasyncsurface;
+  NPN_FinalizeAsyncSurfacePtr finalizeasyncsurface;
+  NPN_SetCurrentAsyncSurfacePtr setcurrentasyncsurface;
+} NPNetscapeFuncs;
+
+#ifdef XP_MACOSX
+/*
+ * Mac OS X version(s) of NP_GetMIMEDescription(const char *)
+ * These can be called to retreive MIME information from the plugin dynamically
+ *
+ * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
+ *       to get mime info from the plugin only on OSX and may not be supported
+ *       in furture version -- use NP_GetMIMEDescription instead
+ */
+enum
+{
+ kBPSupportedMIMETypesStructVers_1    = 1
+};
+typedef struct _BPSupportedMIMETypes
+{
+ SInt32    structVersion;      /* struct version */
+ Handle    typeStrings;        /* STR# formated handle, allocated by plug-in */
+ Handle    infoStrings;        /* STR# formated handle, allocated by plug-in */
+} BPSupportedMIMETypes;
+OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags);
+#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription"
+typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void);
+typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32);
+#endif
+
+#if defined(_WIN32)
+#define OSCALL WINAPI
+#else
+#if defined(__OS2__)
+#define OSCALL _System
+#else
+#define OSCALL
+#endif
+#endif
+
+#if defined(XP_UNIX)
+/* GCC 3.3 and later support the visibility attribute. */
+#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
+#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default")))
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#define NP_VISIBILITY_DEFAULT __global
+#else
+#define NP_VISIBILITY_DEFAULT
+#endif
+#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type
+#endif
+
+#if defined(_WIN32) || defined (__OS2__)
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* plugin meta member functions */
+#if defined(__OS2__)
+typedef struct _NPPluginData {   /* Alternate OS2 Plugin interface */
+  char *pMimeTypes;
+  char *pFileExtents;
+  char *pFileOpenTemplate;
+  char *pProductName;
+  char *pProductDescription;
+  unsigned long dwProductVersionMS;
+  unsigned long dwProductVersionLS;
+} NPPluginData;
+typedef NPError     (OSCALL *NP_GetPluginDataFunc)(NPPluginData*);
+NPError OSCALL      NP_GetPluginData(NPPluginData * pPluginData);
+#endif
+typedef NPError     (OSCALL *NP_GetEntryPointsFunc)(NPPluginFuncs*);
+NPError OSCALL      NP_GetEntryPoints(NPPluginFuncs* pFuncs);
+typedef NPError     (OSCALL *NP_InitializeFunc)(NPNetscapeFuncs*);
+NPError OSCALL      NP_Initialize(NPNetscapeFuncs* bFuncs);
+typedef NPError     (OSCALL *NP_ShutdownFunc)(void);
+NPError OSCALL      NP_Shutdown(void);
+typedef const char* (*NP_GetMIMEDescriptionFunc)(void);
+const char*         NP_GetMIMEDescription(void);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#if defined(__OS2__)
+#pragma pack()
+#endif
+
+#ifdef XP_UNIX
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef char*          (*NP_GetPluginVersionFunc)(void);
+NP_EXPORT(char*)       NP_GetPluginVersion(void);
+typedef const char*    (*NP_GetMIMEDescriptionFunc)(void);
+NP_EXPORT(const char*) NP_GetMIMEDescription(void);
+#ifdef XP_MACOSX
+typedef NPError        (*NP_InitializeFunc)(NPNetscapeFuncs*);
+NP_EXPORT(NPError)     NP_Initialize(NPNetscapeFuncs* bFuncs);
+typedef NPError        (*NP_GetEntryPointsFunc)(NPPluginFuncs*);
+NP_EXPORT(NPError)     NP_GetEntryPoints(NPPluginFuncs* pFuncs);
+#else
+#ifdef MOZ_WIDGET_ANDROID
+typedef NPError    (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*, JNIEnv* pEnv);
+NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, JNIEnv* pEnv);
+#else
+typedef NPError    (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*);
+NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs);
+#endif
+#endif
+typedef NPError        (*NP_ShutdownFunc)(void);
+NP_EXPORT(NPError)     NP_Shutdown(void);
+typedef NPError        (*NP_GetValueFunc)(void *, NPPVariable, void *);
+NP_EXPORT(NPError)     NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif /* npfunctions_h_ */
diff --git a/browser-plugin/npapi/npruntime.h b/browser-plugin/npapi/npruntime.h
new file mode 100644
index 00000000..6e891650
--- /dev/null
+++ b/browser-plugin/npapi/npruntime.h
@@ -0,0 +1,393 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla
+ * Foundation ("Mozilla") nor the names of their contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR
+ * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _NP_RUNTIME_H_
+#define _NP_RUNTIME_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "nptypes.h"
+
+/*
+    This API is used to facilitate binding code written in C to script
+    objects.  The API in this header does not assume the presence of a
+    user agent.  That is, it can be used to bind C code to scripting
+    environments outside of the context of a user agent.
+
+    However, the normal use of the this API is in the context of a
+    scripting environment running in a browser or other user agent.
+    In particular it is used to support the extended Netscape
+    script-ability API for plugins (NP-SAP).  NP-SAP is an extension
+    of the Netscape plugin API.  As such we have adopted the use of
+    the "NP" prefix for this API.
+
+    The following NP{N|P}Variables were added to the Netscape plugin
+    API (in npapi.h):
+
+    NPNVWindowNPObject
+    NPNVPluginElementNPObject
+    NPPVpluginScriptableNPObject
+
+    These variables are exposed through NPN_GetValue() and
+    NPP_GetValue() (respectively) and are used to establish the
+    initial binding between the user agent and native code.  The DOM
+    objects in the user agent can be examined and manipulated using
+    the NPN_ functions that operate on NPObjects described in this
+    header.
+
+    To the extent possible the assumptions about the scripting
+    language used by the scripting environment have been minimized.
+*/
+
+#define NP_BEGIN_MACRO  do {
+#define NP_END_MACRO    } while (0)
+
+/*
+    Objects (non-primitive data) passed between 'C' and script is
+    always wrapped in an NPObject.  The 'interface' of an NPObject is
+    described by an NPClass.
+*/
+typedef struct NPObject NPObject;
+typedef struct NPClass NPClass;
+
+typedef char NPUTF8;
+typedef struct _NPString {
+    const NPUTF8 *UTF8Characters;
+    uint32_t UTF8Length;
+} NPString;
+
+typedef enum {
+    NPVariantType_Void,
+    NPVariantType_Null,
+    NPVariantType_Bool,
+    NPVariantType_Int32,
+    NPVariantType_Double,
+    NPVariantType_String,
+    NPVariantType_Object
+} NPVariantType;
+
+typedef struct _NPVariant {
+    NPVariantType type;
+    union {
+        bool boolValue;
+        int32_t intValue;
+        double doubleValue;
+        NPString stringValue;
+        NPObject *objectValue;
+    } value;
+} NPVariant;
+
+/*
+    NPN_ReleaseVariantValue is called on all 'out' parameters
+    references.  Specifically it is to be called on variants that own
+    their value, as is the case with all non-const NPVariant*
+    arguments after a successful call to any methods (except this one)
+    in this API.
+
+    After calling NPN_ReleaseVariantValue, the type of the variant
+    will be NPVariantType_Void.
+*/
+void NPN_ReleaseVariantValue(NPVariant *variant);
+
+#define NPVARIANT_IS_VOID(_v)    ((_v).type == NPVariantType_Void)
+#define NPVARIANT_IS_NULL(_v)    ((_v).type == NPVariantType_Null)
+#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool)
+#define NPVARIANT_IS_INT32(_v)   ((_v).type == NPVariantType_Int32)
+#define NPVARIANT_IS_DOUBLE(_v)  ((_v).type == NPVariantType_Double)
+#define NPVARIANT_IS_STRING(_v)  ((_v).type == NPVariantType_String)
+#define NPVARIANT_IS_OBJECT(_v)  ((_v).type == NPVariantType_Object)
+
+#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue)
+#define NPVARIANT_TO_INT32(_v)   ((_v).value.intValue)
+#define NPVARIANT_TO_DOUBLE(_v)  ((_v).value.doubleValue)
+#define NPVARIANT_TO_STRING(_v)  ((_v).value.stringValue)
+#define NPVARIANT_TO_OBJECT(_v)  ((_v).value.objectValue)
+
+#define VOID_TO_NPVARIANT(_v)                                                 \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Void;                                           \
+    (_v).value.objectValue = NULL;                                            \
+NP_END_MACRO
+
+#define NULL_TO_NPVARIANT(_v)                                                 \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Null;                                           \
+    (_v).value.objectValue = NULL;                                            \
+NP_END_MACRO
+
+#define BOOLEAN_TO_NPVARIANT(_val, _v)                                        \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Bool;                                           \
+    (_v).value.boolValue = !!(_val);                                          \
+NP_END_MACRO
+
+#define INT32_TO_NPVARIANT(_val, _v)                                          \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Int32;                                          \
+    (_v).value.intValue = _val;                                               \
+NP_END_MACRO
+
+#define DOUBLE_TO_NPVARIANT(_val, _v)                                         \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Double;                                         \
+    (_v).value.doubleValue = _val;                                            \
+NP_END_MACRO
+
+#define STRINGZ_TO_NPVARIANT(_val, _v)                                        \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_String;                                         \
+    NPString str = { _val, (uint32_t)(strlen(_val)) };                        \
+    (_v).value.stringValue = str;                                             \
+NP_END_MACRO
+
+#define STRINGN_TO_NPVARIANT(_val, _len, _v)                                  \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_String;                                         \
+    NPString str = { _val, (uint32_t)(_len) };                                \
+    (_v).value.stringValue = str;                                             \
+NP_END_MACRO
+
+#define OBJECT_TO_NPVARIANT(_val, _v)                                         \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Object;                                         \
+    (_v).value.objectValue = _val;                                            \
+NP_END_MACRO
+
+
+/*
+  Type mappings (JavaScript types have been used for illustration
+    purposes):
+
+  JavaScript       to             C (NPVariant with type:)
+  undefined                       NPVariantType_Void
+  null                            NPVariantType_Null
+  Boolean                         NPVariantType_Bool
+  Number                          NPVariantType_Double or NPVariantType_Int32
+  String                          NPVariantType_String
+  Object                          NPVariantType_Object
+
+  C (NPVariant with type:)   to   JavaScript
+  NPVariantType_Void              undefined
+  NPVariantType_Null              null
+  NPVariantType_Bool              Boolean
+  NPVariantType_Int32             Number
+  NPVariantType_Double            Number
+  NPVariantType_String            String
+  NPVariantType_Object            Object
+*/
+
+typedef void *NPIdentifier;
+
+/*
+    NPObjects have methods and properties.  Methods and properties are
+    identified with NPIdentifiers.  These identifiers may be reflected
+    in script.  NPIdentifiers can be either strings or integers, IOW,
+    methods and properties can be identified by either strings or
+    integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be
+    compared using ==.  In case of any errors, the requested
+    NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled
+    by the browser. Plugins do not need to worry about memory management
+    with regards to NPIdentifiers.
+*/
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);
+void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,
+                              NPIdentifier *identifiers);
+NPIdentifier NPN_GetIntIdentifier(int32_t intid);
+bool NPN_IdentifierIsString(NPIdentifier identifier);
+
+/*
+    The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed.
+*/
+NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier);
+
+/*
+    Get the integer represented by identifier. If identifier is not an
+    integer identifier, the behaviour is undefined.
+*/
+int32_t NPN_IntFromIdentifier(NPIdentifier identifier);
+
+/*
+    NPObject behavior is implemented using the following set of
+    callback functions.
+
+    The NPVariant *result argument of these functions (where
+    applicable) should be released using NPN_ReleaseVariantValue().
+*/
+typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass);
+typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj);
+typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj);
+typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name);
+typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                    const NPVariant *args, uint32_t argCount,
+                                    NPVariant *result);
+typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj,
+                                           const NPVariant *args,
+                                           uint32_t argCount,
+                                           NPVariant *result);
+typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name);
+typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                         NPVariant *result);
+typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                         const NPVariant *value);
+typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
+                                            NPIdentifier name);
+typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value,
+                                         uint32_t *count);
+typedef bool (*NPConstructFunctionPtr)(NPObject *npobj,
+                                       const NPVariant *args,
+                                       uint32_t argCount,
+                                       NPVariant *result);
+
+/*
+    NPObjects returned by create, retain, invoke, and getProperty pass
+    a reference count to the caller.  That is, the callee adds a
+    reference count which passes to the caller.  It is the caller's
+    responsibility to release the returned object.
+
+    NPInvokeFunctionPtr function may return 0 to indicate a void
+    result.
+
+    NPInvalidateFunctionPtr is called by the scripting environment
+    when the native code is shutdown.  Any attempt to message a
+    NPObject instance after the invalidate callback has been
+    called will result in undefined behavior, even if the native code
+    is still retaining those NPObject instances.  (The runtime
+    will typically return immediately, with 0 or NULL, from an attempt
+    to dispatch to a NPObject, but this behavior should not be
+    depended upon.)
+
+    The NPEnumerationFunctionPtr function may pass an array of
+    NPIdentifiers back to the caller. The callee allocs the memory of
+    the array using NPN_MemAlloc(), and it's the caller's responsibility
+    to release it using NPN_MemFree().
+*/
+struct NPClass
+{
+    uint32_t structVersion;
+    NPAllocateFunctionPtr allocate;
+    NPDeallocateFunctionPtr deallocate;
+    NPInvalidateFunctionPtr invalidate;
+    NPHasMethodFunctionPtr hasMethod;
+    NPInvokeFunctionPtr invoke;
+    NPInvokeDefaultFunctionPtr invokeDefault;
+    NPHasPropertyFunctionPtr hasProperty;
+    NPGetPropertyFunctionPtr getProperty;
+    NPSetPropertyFunctionPtr setProperty;
+    NPRemovePropertyFunctionPtr removeProperty;
+    NPEnumerationFunctionPtr enumerate;
+    NPConstructFunctionPtr construct;
+};
+
+#define NP_CLASS_STRUCT_VERSION      3
+
+#define NP_CLASS_STRUCT_VERSION_ENUM 2
+#define NP_CLASS_STRUCT_VERSION_CTOR 3
+
+#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass)   \
+        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM)
+
+#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass)   \
+        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR)
+
+struct NPObject {
+    NPClass *_class;
+    uint32_t referenceCount;
+    /*
+     * Additional space may be allocated here by types of NPObjects
+     */
+};
+
+/*
+    If the class has an allocate function, NPN_CreateObject invokes
+    that function, otherwise a NPObject is allocated and
+    returned. This method will initialize the referenceCount member of
+    the NPObject to 1.
+*/
+NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);
+
+/*
+    Increment the NPObject's reference count.
+*/
+NPObject *NPN_RetainObject(NPObject *npobj);
+
+/*
+    Decremented the NPObject's reference count.  If the reference
+    count goes to zero, the class's destroy function is invoke if
+    specified, otherwise the object is freed directly.
+*/
+void NPN_ReleaseObject(NPObject *npobj);
+
+/*
+    Functions to access script objects represented by NPObject.
+
+    Calls to script objects are synchronous.  If a function returns a
+    value, it will be supplied via the result NPVariant
+    argument. Successful calls will return true, false will be
+    returned in case of an error.
+
+    Calls made from plugin code to script must be made from the thread
+    on which the plugin was initialized.
+*/
+
+bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
+                const NPVariant *args, uint32_t argCount, NPVariant *result);
+bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
+                       uint32_t argCount, NPVariant *result);
+bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script,
+                  NPVariant *result);
+bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+                     NPVariant *result);
+bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+                     const NPVariant *value);
+bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
+bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
+                   uint32_t *count);
+bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args,
+                   uint32_t argCount, NPVariant *result);
+
+/*
+    NPN_SetException may be called to trigger a script exception upon
+    return from entry points into NPObjects.  Typical usage:
+
+    NPN_SetException (npobj, message);
+*/
+void NPN_SetException(NPObject *npobj, const NPUTF8 *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/browser-plugin/npapi/nptypes.h b/browser-plugin/npapi/nptypes.h
new file mode 100644
index 00000000..6fbc7d11
--- /dev/null
+++ b/browser-plugin/npapi/nptypes.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nptypes_h_
+#define nptypes_h_
+
+/*
+ * Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and
+ * true/false macros are available.
+ */
+
+#if defined(WIN32) || defined(OS2)
+  /*
+   * Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool
+   * is predefined tho, both in C and C++.
+   */
+  typedef short int16_t;
+  typedef unsigned short uint16_t;
+  typedef int int32_t;
+  typedef unsigned int uint32_t;
+  typedef long long int64_t;
+  typedef unsigned long long uint64_t;
+#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
+  /*
+   * AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
+   * but not bool for C.
+   */
+  #include <inttypes.h>
+
+  #ifndef __cplusplus
+    typedef int bool;
+    #define true   1
+    #define false  0
+  #endif
+#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
+  /*
+   * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and
+   * u_int32_t.
+   */
+  #include <sys/types.h>
+
+  /*
+   * BSD/OS ships no header that defines uint32_t, nor bool (for C)
+   */
+  #if defined(bsdi)
+  typedef u_int32_t uint32_t;
+  typedef u_int64_t uint64_t;
+
+  #if !defined(__cplusplus)
+    typedef int bool;
+    #define true   1
+    #define false  0
+  #endif
+  #else
+  /*
+   * FreeBSD and OpenBSD define uint32_t and bool.
+   */
+    #include <inttypes.h>
+    #include <stdbool.h>
+  #endif
+#elif defined(BEOS)
+  #include <inttypes.h>
+#else
+  /*
+   * For those that ship a standard C99 stdint.h header file, include
+   * it. Can't do the same for stdbool.h tho, since some systems ship
+   * with a stdbool.h file that doesn't compile!
+   */
+  #include <stdint.h>
+
+  #ifndef __cplusplus
+    #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95)
+      #include <stdbool.h>
+    #else
+      /*
+       * GCC 2.91 can't deal with a typedef for bool, but a #define
+       * works.
+       */
+      #define bool int
+      #define true   1
+      #define false  0
+    #endif
+  #endif
+#endif
+
+#endif /* nptypes_h_ */
diff --git a/browser-plugin/plugin.symbols b/browser-plugin/plugin.symbols
new file mode 100644
index 00000000..c13252cf
--- /dev/null
+++ b/browser-plugin/plugin.symbols
@@ -0,0 +1,4 @@
+NP_GetMIMEDescription
+NP_GetValue
+NP_Initialize
+NP_Shutdown
diff --git a/browser-plugin/tests/data-uri.html b/browser-plugin/tests/data-uri.html
new file mode 100644
index 00000000..8f3c1d8b
--- /dev/null
+++ b/browser-plugin/tests/data-uri.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: Data URI</title>
+</head>
+
+<body>
+  <h1>Data URI</h1>
+  <object 
data="data:application/pdf;charset=utf8;base64,JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nCWKsQoCMRBE+/2KqQWTzZqNJxwpxFOwCy5YiJ16ncflCn/foAzMG3jDLuBDMxjclu7UCboYXIf6pOsK779rqSPtjSSpU2yTtIc94I8BEmGvW88hS8+S1603HH9UTvluZxqMChXM8MPpohgXeKsRhwmFvg1xHIkKZW5kc3RyZWFtCmVuZG9iagoKMyAwIG9iagoxMjAKZW5kb2JqCgo0IDAgb2JqCjw8L1R5cGUvWE9iamVjdAovU3VidHlwZS9Gb3JtCi9CQm94WyAtMTc3IDQyMCA3NzIgNDIwLjEgXQovR3JvdXA8PC9TL1RyYW5zcGFyZW5jeS9DUy9EZXZpY2VSR0IvSyB0cnVlPj4KL0xlbmd0aCA4Ci9GaWx0ZXIvRmxhdGVEZWNvZGUKPj4Kc3RyZWFtCnicAwAAAAABCmVuZHN0cmVhbQplbmRvYmoKCjUgMCBvYmoKPDwvQ0EgMC41CiAgIC9jYSAwLjUKPj4KZW5kb2JqCgo3IDAgb2JqCjw8L0xlbmd0aCA4IDAgUi9GaWx0ZXIvRmxhdGVEZWNvZGU+PgpzdHJlYW0KeJwlij0LAjEQRPv9FVMLl+yuyX3AkULuFOyCCxZip16nXCz8+wZlYN7AG3aCD61gcF1xiE7RB3E9yp3OGzz/rqYstDPSNrqIrtX6sBv8XqAB9riMLElH1tTU3nL4MXKXrnak2ShTxgo/H07CWN7wVgZML2T6Aik/HLsKZW5kc3RyZWFtCmVuZG9iagoKOCAwIG9iagoxMjIKZW5kb2JqCgo5IDAgb2JqCjw8L1R5cGUvWE9iamVjdAovU3VidHlwZS9Gb3Jt
 Ci9CQm94
 
WyAtMTc3IDQyMCA3NzIgNDIwLjEgXQovR3JvdXA8PC9TL1RyYW5zcGFyZW5jeS9DUy9EZXZpY2VSR0IvSyB0cnVlPj4KL0xlbmd0aCA4Ci9GaWx0ZXIvRmxhdGVEZWNvZGUKPj4Kc3RyZWFtCnicAwAAAAABCmVuZHN0cmVhbQplbmRvYmoKCjEwIDAgb2JqCjw8L0NBIDAuNQogICAvY2EgMC41Cj4+CmVuZG9iagoKMTIgMCBvYmoKPDwvTGVuZ3RoIDEzIDAgUi9GaWx0ZXIvRmxhdGVEZWNvZGU+PgpzdHJlYW0KeJwlirEKAjEQRPv9iqkFk901e55wpBBPwS64YCF26nXKxcLfNygD8wbecBB8aAaD27KNBUWfJPSodzov8Py7ljrR1kk7C4Z1p+3hN8S9QBP8cRlYsg6sedl6xelH4z5f/UijU6GCGXE8nMQwvRG9SsLuhUJfRkwc7QplbmRzdHJlYW0KZW5kb2JqCgoxMyAwIG9iagoxMjEKZW5kb2JqCgoxNCAwIG9iago8PC9UeXBlL1hPYmplY3QKL1N1YnR5cGUvRm9ybQovQkJveFsgLTE3NyA0MjAgNzcyIDQyMC4xIF0KL0dyb3VwPDwvUy9UcmFuc3BhcmVuY3kvQ1MvRGV2aWNlUkdCL0sgdHJ1ZT4+Ci9MZW5ndGggOAovRmlsdGVyL0ZsYXRlRGVjb2RlCj4+CnN0cmVhbQp4nAMAAAAAAQplbmRzdHJlYW0KZW5kb2JqCgoxNSAwIG9iago8PC9DQSAwLjUKICAgL2NhIDAuNQo+PgplbmRvYmoKCjE3IDAgb2JqCjw8L0xlbmd0aCAxOCAwIFIvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aDEgODAyND4+CnN0cmVhbQp4nOVYfVRb53l/3nv1yZc++EYYXXEBAwIJBJgPY3EBSQiDjfjyBKpAAglQYhCWZFyn9Uyb2nHluPbyndUn8
 XKyNltzT
 
i52lpEsrclOunWnS9OebjvLGqc+Z91fDY2bLT07bQx73itBbC9pz1l3zv7YlXTv8/087+993vde3UTseBiyYBVYEGYXg8vF2ZkqAPh7AKKfXUlw2z0Ch/RNAKZgbnl+sbrpJ78AYP8TQCmfP3py7q03fH0Ameii+t5COBh6+sBNG0Du91CwbwEFh7ZOKgHykIWKhcXE588wPy5AvgJ57mh0NmjJVmG+PAfyeYvBzy//jeKMDEkv1S8FF8OHw889hvznMf7gcjSeCEHFNkDpm1S/HAsvfzT5JPqX/gzrS6CM4IceWUgqKM+wMrlCqYL/r4f8AuSDW34ANLAsne862BehmF6337/7vDW4/ev/zSrS+D8F34CX4QK8A/60wgUeiMBxlNx5vAE/Qik9PDAJfw7Jzwj7IqyjPmUXgIvw9GfYeeBJuAZ/e1cWDyzCF7CWv4B3SCP8HbZKFD4kKvgSfBejfoiyQ58WisnB05xEzt0h/Ql8nTkPBxnsQ6wCNYyV0cKbcJlMYeQEjvPC7og7/1vQh+AUnkdhAVaQlg75gY//BdTb/46jOgUH4cvQDUfv8HidPMtm4PyNwbOI6RuSzLqjVLrZ+5hXGOb2o8j8EczjL0hw7MwFthscch15GUBwTnjHx0ZHhj1Dhw8NDhzsd/e5nI7enm6hy36gc39He1vrvpbGBqulvq56b1VlBV9uMhbl6bSanOzMDLVKqZDLWIZAnZN3BTixKiDKqni3u57yfBAFwTsEAZFDketuG5ELSGbc3ZYCWs7dYymkLIVdS6LlOqGzvo5z8pz4loPn1snksBfpCw5+ghM3JfqQRMuqJCYbGZMJPThn0YKDE0mAc4qulYWkM+DAeGuZGb18bzijvg7WMjKRzERKrOaX10i1nUgEU+3sWGNAlU3TimylMxgSPcNep8NgMk3U1/WLObxDUkGvFFJU9IpKKSQXoaXDeW6tbiP58LoWZgLmrBAfCn7OK7JB9E
 2yzmTyIV
 
FnFmt4h1jzwM+KcORhsY53OEUzjTowsptn4JOURJRXanku+RHgcPjN9++WBNMSRaX2I6CkC+FNJl0850oGksH17dUZntPyybWsrOSyExEGjxe91rdfO28QXQ9PiNrAAulID9Y1MiDmDvu8IlPp4haCKMFvF29qM5h0Ezs2ns9SAwKBcCCmJhMd+Pl1AWaQEVeHvSmegxnDVRCs5gmRCVDNxo4mf5xqVnc0u+4BHmdzYNSbFGWV/SHeiRifD4qrM9hP99Gp4LVizq8MJj6p13Ht1gnJlsOq+kMRTpRXISzodacDdgp1SWolJudXqcumARNU6fRcO49haBwn7wykvysLRRiAq68T3ebU1I95RcGBhBBMz5FzrcGKHsEATlHEIU2faOWXxTy+Z3c+aVnOyKhXckm7iXm9IgRm016i1emgmTlnMuBIlUBj8cPeV6Fp++ZaM2e41gTNMOGgxgW92FdVzqQ3NCcaA4YQrrQ5zmswicIETvAE7w1P0EZDhGpuYjqTlFFkese8A6P8wPCkty1dSEpBw8kqnfeE4b2GVBhsOVFVqeK8jIGdQEMtCjgXEnxPJ55FZaUKf1oEXJLSVu3p5LzEADvWWIZYwznDjrQd5e8KKqft1OveiaagLMbpdRtME6bUUV/HoJpLJ0YPFQXVvaNiK3EnQBmDYSQRxbKI9jzn5cP8BL/AiYLHS8dG4ZFQToMhYZ6eq7G7uDvAQpjAhOodhoIpusyGO8EV+yR+l3Xfo+7fUXNJFT8wmqTB+XRAwMr7RaAtLLTpDNLqp+uZdwVxEeOKltZzck0Q6FpeoMs2yfeHkvyot1Oyxh3klOEBmksPA2RgrKe+DjeznjWenBteE8i50Unvq1p8pDo35r3KEKY30DOxVoE676sc3iskKUOlVEgZjjI00ggyKsne8KoAsCppZZJA4mfXCUgy1Y6MwOw6k5Jpd2QMymQpmSDJ6IGzVLSAGOP+7eRCdH6+OLGQDEz
 QHocCRAS
 
/RCS8HdHh7WuEUWSJGXy4R8zke6i8i8q7UnIFlSuxM0gBqa97IKl18h8V1Uu3bsBnTyYkH8cnYCVY1ghYO68qZapN25pC/m7nVZZBEtZYKpZT8VWlQv1x51VC5U06k67SpDM5GG6rgjy1tSAf//W3HLK3pLj7AWQmfObKAhM8L5x6XveyjpEbyZmSx0sYefGZYkaVwZQwTE5GUZbGDZOlvIa38lH+NH+Rl1v5Ln4ImWf56/xPeaWGn0bmbSS3eUUbFTHU+DRqZRreiMan0fQlXqFS5kx6ckmuKpCdrZMH8qYL2JzcaZ0eujZtXZubunbrJrH6N21T/mMx+tO+t9nYYJ7yT/nxIM0Wxkx0TTY7Q3SF+aaWVt3eFpOtjMnPy2F4dpIfWp2aWZg6fYjbOvyPt7//7Ivk1xe+HWuwRl9LsqInMVBx+0z92ANb39rqMbS0GGTPlLQcuP/S6MhTCZeEh3v7ffYY+wbUwj54UjDdX0UMheZCJqfAXsDouUyNe4++Xs9k6Um2jhAZYde3bwp71Do3YYmqNGNfn6JttY1MtxGhjSDR2Je3d317QzBm5Lj37h3KI3lVVeVmT2kp7GsaztAUKDzq/HIPaHHk+GnatNGx69utOPwmq1m7iYOPad/dtNkaG6b8Zjp8eiJ0tHTse3NYvtzCtDTbZV2kBYHhyxUawrfYSa4yh83Pa7LtayU/EpY89ce3tnI1Te7pDoe/rahsX//4dMOFHFNbbcNMZXlb9/l/enD/kbbSi45ZG/tGUcfswO0zxfVTmmq+qHZgvtPus+8tUBHZo7VOW2lJ/vG3cvK3ymRMrsVjF41F2JHeLRf7jsyAe3sfTJALQuFJJznSONfINHKqLLe70du40HiuUdZIkVCjhClSZbpt69v/LOSotO6KahTtpaJsCuYRlcZdQP2MbapsN1eNFsq+cptFwctg3F1ZLhTvcVfSU3lleWXRQzkkx9UilOxxt7QMuM1A/gqI
 DP/JMWrw
 
jfmI4CPNPsL5iI/m1k8E3Ks+kvCRgI+87HvTx0hiw6Ex9xUfkflIl8z3Fd/zPvZ51P2D72c+GdVf63a7pWvLgdTVbJWuQm6Zyb2bgOF8Del4Fk2Ju93ev6ehiBQpeJtVVst63HvasHeMbqubvZJJ3JnuzF6Pp1bb68ktleZe3443br9f+5ZNu6krbKfzv2kz+6ePHTtmxoOuA5x6ysXw0L6H7LFNbJFNv+Rpxl7RF7Zr6TpJHWA2+wk2C8lT8OVVe5VlpMlkK5DWSKpjmFYL29JaRakm7KfC1kK0YZureBPtnDJGWmC2famuymGoiJ3761dqRku7WPc+UvDUoy0nNh6+/4mp2uJ6e4XeWlv6zDPNwa9NlnY0Valv8OfLTTWuvq3H8vninML2mYOTDx6p2bq26Mu3Du5rPdRYUNAwyDz43DfUigd1ZV9JdJ8K7uftIw2m/a3NJQpDbWv51YPvDJ0crlEo1WzUfKkq/vFr7YLe2txSXLG/tojvOsK0nzrd5e8sK+v0d3VNdxnp2vXg2nWx3wUjrt6EUP/VPPJULsnMPZ/LFBiqDIy6qLiopujpIpmqym3MzDTWQR2xr9ZdqbtVx9bRie096KZXobDW4q4k7nMFpAA8lZUKzlOsVQzrCtIzld6dcFam/Nof2KwUdWlr8pMd4Frzd1bmPgruHkIohCbEksjyu2L+sp4ee0lh92Fv/fE/CdX94PrAgzPtW0+2DbcUk0d0Zjd5R99/dv6AXJWhaNMYCrKFP3zt5K8+rJ56ZmWEXLYe+cLg4BeOSH+kCP5TBfaM3A0ZYBdqtVmeLMaTtZwlZt3KksGSoJUTkAtyj/yKXJTLVXLlaoYC5HG2SNpqS94iVtxfS3CbaWyolONeWqmTt1Q2MXGiv20luVu/JA81e6Rt0hVseU/Kh/9k2YvyQSiH08J4ZRmRFz+O94gsfam+Uz+ol31VQ2plJC+PUUdLystLKqBCqGCEikDFlYqbF
 bJmk8PEm
 
Brw9skw6kLTRT0BvVbP6PVZ8YcKSaGCMa2QVGl+bG6/X6eXVgL2egpn3B0bGwBxpreCGtJil7dgwyK0uOnp7KRJanCZ0sRe/Pj74T97KNxrWjlbtn+fVc/3DD565N0bZk/isbUQc/XRqce/tLL6mP/L59Sa3IznCaMv/stvjjz8pVNnn/ThGGewj0QcYyeI1862kma6LcVxfzJz6mz3w3qSQa9y3PD3dwx0MB2Gsy2kJcpNG6IG5jR3kWPqDBxnqGPV+dEVOIt9ace5sTOCPWC/Yr9pl3HqBrWgZtUdhnhpqU0LZq2ZMZsr4zalNi5fzljNYDQZJCNDXgxdFAQtNh1edbTxKBwIxnt+uklYpR1j069r96duD3TJSwu8ai/bVFjG0k6k69dKWlrtZGclS1ixKawYuuZF4eTasdnXBjJ76vUdvX1l/hPOkrpD8/svXjx21NDh7y070NaACPKuwbHGH/+k3B0dfOVFsui7ONtclEtKXs/I06gto3HH4fmuPaxqRK1Y/XJ3UODSyKq1mcrnXuhaHGvPzP+m9N6L6H7+NZ/5F9Oazo/AmHrn8vbD/5b3yWuDLRc+kYwDfSHDpEXopzRtOeEPdo3IPW8nlMz74JDFYT97AdwyAC9ePdQd6Zexa2eQrIOXyWHmETYLPw72FVlIiqJGLZt6QYI3YivtcFmmoh1l1L2UHNnNFdjNS9AykKYZfCJbTtMsGOBEmpahzSNpWg458FyaVoAGxDSthAfgeppWQR5pT9NqyCGH0nQm1uDbfWNoITvxsyFK/jRN54CdycPsRKZGboMZSdMEOFafphnIYW1pmoV9rJCmZWizkqblUMo+kaYVUMZeTdNK+A/2h2laBdWyN9O0Gkpl76fpTGiTq9J0FnxOvhM/G96TX07TOfBFxQO90eWTscj8QoKrnq3hbA0NrdxIOMS5g4k6rn9p1sJ1Hz3KSQZxLhaOh2Mr4ZCFG+zvcY50j/UPHeYicS
 7IJWLBUH
 
gxGLufi87d7T8YmQnHgolIdIkbDccicyPh+eNHg7Hu+Gx4KRSOcfXcvRb38kfCsThlGi0NrZbmT7T3Gv+OQrD6+Ug8EY6hMLLEjVtGLZwnmAgvJbjgUogb23UcmpuLzIYl4Ww4lgiicTSxgKXedzwWiYciszRb3LI7gt5obDmaLikRXglzh4KJRDgeXVpIJJY7rNYTJ05YgmnjWbS1zEYXrb9Nlzi5HA6F45H5JRy5ZSGxeHQQC1qKY+HHpYxYzZ2ouaJLODlHUzZ1XDwc5mj4OMafC4ewtOVY9L7wbMISjc1bT0Tuj1hT8SJL89ZPwtAo6Ty/nzf0QhTX4EmIQQTmYQESwEE1zEINXm3QgJ9WpEYgDCG8uiGIFnVI9cMSWlmQom8uj+L1kwhxiQvjNYzXFcmXWg6iVw84MVo3jCE9BIdRGpHsg/hLoHUQbcOwiNcY3I+yKMz91vyD6D8j5aGaCNovoXZUkkTQl3rOw3GskEbsxlyzKFmSssTQsl6q67fH+F36IxIV39U0Yl0UNws+13+a7++K/PshksJ+XoqSkGKnLCNS7HG0GJWsPJInxSIhZVuSrMY+JeMQZpxDf4rcJ5azUuwE8qnIUaQX0qjeh4jHpApCkt/O2OKY+b/PAe3BGHZh9B6UaHUrUs5Dkjwh9RTVLUjcMnTgXceK9w36saDN3ZFn03EtErWIlv9TvwSukGUJx7A0z/Nom5pzixRzEftrMI3QktT3FKHjd4wxhc1n9ZpLuqZWztG74tCZpVfqu1N9PF3/nJQnhdoynqOIe1hC2yJJ56UxRnAOI0jdWR+dsfm07N5qdmq5ezz/l7lTzxiwbcKMn3KsqQPfIUq8Y3dJ5+tEJkyQm7fJ27cJd5uc/g3x/IasfnjpQ+aXt2qML926fosZ+mD6g5c+YBs+IJoPiAo2tZuezcDm8uaVTUWG5n2SBT8nun+92Wb8adON8fea3h2HG6TTc2P1hniDpf9yJm+
 oMl03CDv
 
+Lltg1G5wGw0byxurGz/cuLlxa0O1+p1L32G+/brVqHnd+DpjvDZ07fQ1NvAC0bxgfIHxfD3wdebSZaK5bLxsvcz+8dMW49N9ZcYnn9hrvPnErScYGr7liWyda/pxcvqRi48wy2dXz146y66euXSGeWnl+goT99QYo0tm41JfrbG4qWhc2cSOK9htI/V0zFRWuwLTgnEajXyTDcbJvhpjbpN+XI7FytBQwxrZLnaIjbIX2eusUjXiKTMO4++m55aH0QwZh6xD0nuZ4IAJAx1cPrh6kO131RjdfW1GTZ+xz9r3dt9P+z7oU0z3kWfx63rJdd3FCq4aq0twlZlcpW7DeEFT/ri2STPOEBgnTTBu1WxrGI1mWnNaw2qgC5jVAiIn6+TS2tio2TywrtweGRBVHp9IzomVo/QsDE+KinMijE/6vGuEfG3izIUL0LNnQLSNesXAnokBMYSEQIlVJLR71gqgZyIeT0j/34nZjORxPIP5OIqm4ikhmHfUYI6TeBzicWKmOolECcTNVEwl1Ieg51Qc6IlqzZIVpeLxoqn/AjZhPhMKZW5kc3RyZWFtCmVuZG9iagoKMTggMCBvYmoKNDk3NAplbmRvYmoKCjE5IDAgb2JqCjw8L1R5cGUvRm9udERlc2NyaXB0b3IvRm9udE5hbWUvQkFBQUFBK0xpYmVyYXRpb25TZXJpZgovRmxhZ3MgNAovRm9udEJCb3hbLTE3NiAtMzAzIDEwMDUgOTgxXS9JdGFsaWNBbmdsZSAwCi9Bc2NlbnQgODkxCi9EZXNjZW50IC0yMTYKL0NhcEhlaWdodCA5ODEKL1N0ZW1WIDgwCi9Gb250RmlsZTIgMTcgMCBSCj4+CmVuZG9iagoKMjAgMCBvYmoKPDwvTGVuZ3RoIDI1OC9GaWx0ZXIvRmxhdGVEZWNvZGU+PgpzdHJlYW0KeJxdkEFuwyAQRfecgmW6iMB2nWRhWaoSRfIibVW3B8Aw
 dpFqQBgv
 
fPvCkLZSF6A3mv8Z/rBzd+mMDuzVW9lDoKM2ysNiVy+BDjBpQ4qSKi3DvcJbzsIRFr39tgSYOzPapiHsLfaW4De6e1J2gAfCXrwCr81Edx/nPtb96twXzGAC5aRtqYIxvnMT7lnMwNC171Rs67Dto+VP8L45oCXWRf6KtAoWJyR4YSYgDectba7XloBR/3qn7BhG+Sl8VBZRyXnN28gl8qFIXGU+Jn7MXCeukUvUH5Ar1B8zl4lPmSucf5+UfpJW9ZOQytX7mA73ibFSIG3gd+XOuuTC8w0ou32ECmVuZHN0cmVhbQplbmRvYmoKCjIxIDAgb2JqCjw8L1R5cGUvRm9udC9TdWJ0eXBlL1RydWVUeXBlL0Jhc2VGb250L0JBQUFBQStMaWJlcmF0aW9uU2VyaWYKL0ZpcnN0Q2hhciAwCi9MYXN0Q2hhciA4Ci9XaWR0aHNbMzY1IDU1NiA0NDMgNTAwIDQ0MyAyNTAgNTAwIDUwMCA1MDAgXQovRm9udERlc2NyaXB0b3IgMTkgMCBSCi9Ub1VuaWNvZGUgMjAgMCBSCj4+CmVuZG9iagoKMjIgMCBvYmoKPDwvRjEgMjEgMCBSCj4+CmVuZG9iagoKMjMgMCBvYmoKPDwvRm9udCAyMiAwIFIKL1hPYmplY3Q8PC9UcjE0IDE0IDAgUi9UcjQgNCAwIFIvVHI5IDkgMCBSPj4KL0V4dEdTdGF0ZTw8L0VHUzEwIDEwIDAgUi9FR1MxNSAxNSAwIFIvRUdTNSA1IDAgUj4+Ci9Qcm9jU2V0Wy9QREYvVGV4dC9JbWFnZUMvSW1hZ2VJL0ltYWdlQl0KPj4KZW5kb2JqCgoxIDAgb2JqCjw8L1R5cGUvUGFnZS9QYXJlbnQgMTYgMCBSL1Jlc291cmNlcyAyMyAwIFIvTWVkaWFCb3hbMCAwIDU5NSA4NDJdL0dyb3VwPDwvUy9UcmFuc3BhcmVuY3kvQ1MvRGV2a
 WNlUkdCL
 
0kgdHJ1ZT4+L0NvbnRlbnRzIDIgMCBSPj4KZW5kb2JqCgo2IDAgb2JqCjw8L1R5cGUvUGFnZS9QYXJlbnQgMTYgMCBSL1Jlc291cmNlcyAyMyAwIFIvTWVkaWFCb3hbMCAwIDU5NSA4NDJdL0dyb3VwPDwvUy9UcmFuc3BhcmVuY3kvQ1MvRGV2aWNlUkdCL0kgdHJ1ZT4+L0NvbnRlbnRzIDcgMCBSPj4KZW5kb2JqCgoxMSAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDE2IDAgUi9SZXNvdXJjZXMgMjMgMCBSL01lZGlhQm94WzAgMCA1OTUgODQyXS9Hcm91cDw8L1MvVHJhbnNwYXJlbmN5L0NTL0RldmljZVJHQi9JIHRydWU+Pi9Db250ZW50cyAxMiAwIFI+PgplbmRvYmoKCjE2IDAgb2JqCjw8L1R5cGUvUGFnZXMKL1Jlc291cmNlcyAyMyAwIFIKL01lZGlhQm94WyAwIDAgNTk1IDg0MiBdCi9LaWRzWyAxIDAgUiA2IDAgUiAxMSAwIFIgXQovQ291bnQgMz4+CmVuZG9iagoKMjQgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL1BhZ2VzIDE2IDAgUgovT3BlbkFjdGlvblsxIDAgUiAvWFlaIG51bGwgbnVsbCAwXQovVmlld2VyUHJlZmVyZW5jZXM8PC9EaXNwbGF5RG9jVGl0bGUgdHJ1ZQo+PgovTGFuZyhlcy1FUykKPj4KZW5kb2JqCgoyNSAwIG9iago8PC9UaXRsZTxGRUZGMDA0NTAwNzYwMDY5MDA2RTAwNjMwMDY1MDAyMDAwNDIwMDcyMDA2RjAwNzcwMDczMDA2NTAwNzIwMDIwMDA1MDAwNkMwMDc1MDA2NzAwNjkwMDZFMDAyMDAwNTQwMDY1MDA3MzAwNzQ+Ci9DcmVhdG9yPEZFRkYwMDU3MDA3MjAwNjkwMDc0MDA2NT
 AwNzI+Ci
 
9Qcm9kdWNlcjxGRUZGMDA0QzAwNjkwMDYyMDA3MjAwNjUwMDRGMDA2NjAwNjYwMDY5MDA2MzAwNjUwMDIwMDAzNDAwMkUwMDMyPgovQ3JlYXRpb25EYXRlKEQ6MjAxNDA3MDgxMjI4MzcrMDInMDAnKT4+CmVuZG9iagoKeHJlZgowIDI2CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwNzMyNSAwMDAwMCBuIAowMDAwMDAwMDE5IDAwMDAwIG4gCjAwMDAwMDAyMTAgMDAwMDAgbiAKMDAwMDAwMDIzMCAwMDAwMCBuIAowMDAwMDAwNDA5IDAwMDAwIG4gCjAwMDAwMDc0NjkgMDAwMDAgbiAKMDAwMDAwMDQ0OSAwMDAwMCBuIAowMDAwMDAwNjQyIDAwMDAwIG4gCjAwMDAwMDA2NjIgMDAwMDAgbiAKMDAwMDAwMDg0MSAwMDAwMCBuIAowMDAwMDA3NjEzIDAwMDAwIG4gCjAwMDAwMDA4ODIgMDAwMDAgbiAKMDAwMDAwMTA3NiAwMDAwMCBuIAowMDAwMDAxMDk3IDAwMDAwIG4gCjAwMDAwMDEyNzcgMDAwMDAgbiAKMDAwMDAwNzc1OSAwMDAwMCBuIAowMDAwMDAxMzE4IDAwMDAwIG4gCjAwMDAwMDYzNzggMDAwMDAgbiAKMDAwMDAwNjQwMCAwMDAwMCBuIAowMDAwMDA2NTk3IDAwMDAwIG4gCjAwMDAwMDY5MjUgMDAwMDAgbiAKMDAwMDAwNzExOSAwMDAwMCBuIAowMDAwMDA3MTUyIDAwMDAwIG4gCjAwMDAwMDc4NzIgMDAwMDAgbiAKMDAwMDAwODAxNSAwMDAwMCBuIAp0cmFpbGVyCjw8L1NpemUgMjYvUm9vdCAyNCAwIFIKL0luZm8gMjUgMCBSCi9JRCBbIDw0QjA5Q0NFOUEwRTM3NjU0MDI2N0RFRTg4OTA1ODM2Mz4KPDR
 CMDlDQ0U
 
5QTBFMzc2NTQwMjY3REVFODg5MDU4MzYzPiBdCi9Eb2NDaGVja3N1bSAvMjMwNzE0Mzc3ODg4NjkzOTJFNDQ3RUQ1NzJGM0FDOEMKPj4Kc3RhcnR4cmVmCjgzMDcKJSVFT0YK"
 type="application/pdf" width="600" height="600">
+    The pdf could not be rendered.
+  </object>
+</body>
+</html>
diff --git a/browser-plugin/tests/iframe.html b/browser-plugin/tests/iframe.html
new file mode 100644
index 00000000..ce893b04
--- /dev/null
+++ b/browser-plugin/tests/iframe.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: Iframe</title>
+</head>
+
+<body>
+  <h1>PDF document inside an Iframe</h1>
+  <button onclick="document.getElementById('container').setAttribute('style', 'display: 
none');">Hide</button>
+  <button onclick="document.getElementById('container').setAttribute('style', 'display: 
block');">Show</button>
+  <div id="container">
+    <iframe id="frame" src="test.pdf" width="450" height="450"/>
+  </div>
+</body>
+</html>
+
diff --git a/browser-plugin/tests/initvalues.html b/browser-plugin/tests/initvalues.html
new file mode 100644
index 00000000..c99cfd43
--- /dev/null
+++ b/browser-plugin/tests/initvalues.html
@@ -0,0 +1,32 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: InitialValues</title>
+</head>
+
+<body>
+  <h1>Default</h1>
+  <object data="test.pdf" type="application/pdf" widtH="600" height="300">
+    The pdf could not be rendered.
+  </object>
+  <h1>toolbar='false'</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="300" toolbar="false">
+    The pdf could not be rendered.
+  </object>
+  <h1>currentPage="2"</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="300" currentPage="2">
+    The pdf could not be rendered.
+  </object>
+  <h1>zoomMode="fit-page"</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="300" zoomMode="fit-page">
+    The pdf could not be rendered.
+  </object>
+  <h1>continuous="false" dual="true"</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="300" continuous="false" dual="true">
+    The pdf could not be rendered.
+  </object>
+  <h1>zoom="2.0"</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="300" zoom="2.0">
+    The pdf could not be rendered.
+  </object>
+</body>
+</html>
diff --git a/browser-plugin/tests/local.html b/browser-plugin/tests/local.html
new file mode 100644
index 00000000..0c25cb30
--- /dev/null
+++ b/browser-plugin/tests/local.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: Local PDF document</title>
+</head>
+
+<body>
+  <h1>Local PDF document</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="600">
+    The pdf could not be rendered.
+  </object>
+</body>
+</html>
diff --git a/browser-plugin/tests/multiple.html b/browser-plugin/tests/multiple.html
new file mode 100644
index 00000000..592dacef
--- /dev/null
+++ b/browser-plugin/tests/multiple.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: Multiple PDF documents</title>
+</head>
+
+<body>
+  <h1>Local PDF document</h1>
+  <object data="test.pdf" type="application/pdf" width="600" height="600">
+    The pdf could not be rendered.
+  </object>
+  <h1>Remote PDF document</h1>
+  <object data="http://plugindoc.mozdev.org/testpages/test.pdf";
+          type="application/pdf" width="600" height="600">
+    The pdf could not be rendered.
+  </object>
+</body>
+</html>
diff --git a/browser-plugin/tests/remote.html b/browser-plugin/tests/remote.html
new file mode 100644
index 00000000..b8b00abd
--- /dev/null
+++ b/browser-plugin/tests/remote.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: Remote document</title>
+</head>
+
+<body>
+  <h1>Remote PDF document</h1>
+  <object data="http://plugindoc.mozdev.org/testpages/test.pdf"; type="application/pdf" width="640" 
height="480">
+    The pdf could not be rendered.
+  </object>
+</body>
+</html>
diff --git a/browser-plugin/tests/script.html b/browser-plugin/tests/script.html
new file mode 100644
index 00000000..a78c31f6
--- /dev/null
+++ b/browser-plugin/tests/script.html
@@ -0,0 +1,59 @@
+<html>
+<head>
+  <title>Evince Browser Plugin Test: Scripting</title>
+  <script>
+    function updateProperties() {
+        document.getElementById('currentPage').textContent = document._pdf.currentPage;
+        document.getElementById('pageCount').textContent = document._pdf.pageCount;
+        document.getElementById('zoom').textContent = document._pdf.zoom;
+        document.getElementById('continuous').textContent = document._pdf.continuous;
+        document.getElementById('dual').textContent = document._pdf.dual;
+        document.getElementById('zoomMode').textContent = document._pdf.zoomMode;
+        document.getElementById('toolbar').textContent = document._pdf.toolbar;
+    }
+
+    function init() {
+        document._pdf = document.getElementById('pdf');
+        setInterval(updateProperties, 500);
+    }
+    document.addEventListener("DOMContentLoaded", init, false);
+  </script>
+</head>
+
+<body>
+  <h1>PDF document controlled by JavaScript</h1>
+  <object id="pdf" data="test.pdf" type="application/pdf" width="600" height="300">
+    The pdf could not be rendered.
+  </object>
+  <br>
+  <button onclick="document._pdf.currentPage--;">currentPage--</button>
+  <button onclick="document._pdf.currentPage++;">currentPage++</button>
+  <button onclick="document._pdf.zoomIn();">Zoom In</button>
+  <button onclick="document._pdf.zoomOut();">Zoom In</button>
+  <button onclick="document._pdf.zoom+=0.1;">zoom+=0.1</button>
+  <button onclick="document._pdf.zoom-=0.1;">zoom-=0.1</button>
+  <button onclick="document._pdf.zoom=1;">zoom=1</button>
+  <button onclick="document._pdf.toggleContinuous();">Toggle Continuous</button>
+  <button onclick="document._pdf.continuous=true;">continuous=true</button>
+  <button onclick="document._pdf.continuous=false;">continuous=false</button>
+  <button onclick="document._pdf.toggleDual();">Toggle Dual</button>
+  <button onclick="document._pdf.dual=true;">dual=true</button>
+  <button onclick="document._pdf.dual=false;">dual=false</button>
+  <button onclick="document._pdf.zoomMode='fit-page';">zoomMode='fit-page'</button>
+  <button onclick="document._pdf.zoomMode='fit-width';">zoomMode='fit-width'</button>
+  <button onclick="document._pdf.zoomMode='auto';">zoomMode='auto'</button>
+  <button onclick="document._pdf.print();">Print</button>
+  <button onclick="document._pdf.download();">Download</button>
+  <button onclick="document._pdf.toolbar=true;">toolbar=true</button>
+  <button onclick="document._pdf.toolbar=false;">toolbar=false</button>
+  <table>
+    <tr><th>currentPage:</th><td id="currentPage"></td></tr>
+    <tr><th>pageCount:</th><td id="pageCount"></td></tr>
+    <tr><th>zoom:</th><td id="zoom"></td></tr>
+    <tr><th>continuous:</th><td id="continuous"></td></tr>
+    <tr><th>dual:</th><td id="dual"></td></tr>
+    <tr><th>zoomMode:</th><td id="zoomMode"></td></tr>
+    <tr><th>toolbar:</th><td id="toolbar"></td></tr>
+  </table>
+</body>
+</html>
diff --git a/browser-plugin/tests/test.pdf b/browser-plugin/tests/test.pdf
new file mode 100644
index 00000000..3efaa34d
Binary files /dev/null and b/browser-plugin/tests/test.pdf differ
diff --git a/configure.ac b/configure.ac
index 2823294e..9036a995 100644
--- a/configure.ac
+++ b/configure.ac
@@ -500,6 +500,31 @@ PREVIEWER_LIBS="$PREVIEWER_LIBS $GTKUNIXPRINT_LIBS -lz"
 AC_SUBST(PREVIEWER_CFLAGS)
 AC_SUBST(PREVIEWER_LIBS)
 
+
+# **************
+# Browser Plugin
+# **************
+
+AC_ARG_ENABLE([browser-plugin],
+  [AS_HELP_STRING([--disable-browser-plugin],
+                  [Disable the Browser Plugin])],
+  [],
+  [enable_browser_plugin=no])
+
+if test x$enable_browser_plugin = "xyes" ; then
+  PKG_CHECK_MODULES([BROWSER_PLUGIN],[gtk+-3.0 >= $GTK_REQUIRED gthread-2.0 gio-2.0 >= $GLIB_REQUIRED])
+
+  if test -z "${BROWSER_PLUGIN_DIR}"; then
+    BROWSER_PLUGIN_DIR="\${libdir}/mozilla/plugins"
+  fi
+  AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
+fi
+
+AM_CONDITIONAL([ENABLE_BROWSER_PLUGIN],[test "$enable_browser_plugin" = "yes"])
+BROWSER_PLUGIN_CFLAGS="$BROWSER_PLUGIN_CFLAGS $DEBUG_FLAGS"
+AC_SUBST(BROWSER_PLUGIN_CFLAGS)
+AC_SUBST(BROWSER_PLUGIN_LIBS)
+
 # ***
 # GIR
 # ***
@@ -919,6 +944,7 @@ backend/tiff/Makefile
 backend/xps/evince-xpsdocument.metainfo.xml.in
 backend/xps/xpsdocument.evince-backend.desktop.in
 backend/xps/Makefile
+browser-plugin/Makefile
 cut-n-paste/Makefile
 cut-n-paste/gimpcellrenderertoggle/Makefile
 cut-n-paste/synctex/Makefile
@@ -991,6 +1017,7 @@ Viewer ...................:  $enable_viewer
 Previewer ................:  $enable_previewer
 Thumbnailer ..............:  $enable_thumbnailer
 Nautilus Extensions.......:  $enable_nautilus
+Browser Plugin............:  $enable_browser_plugin
 
 
 BACKENDS
diff --git a/meson.build b/meson.build
index 558c9ab9..700cb372 100644
--- a/meson.build
+++ b/meson.build
@@ -457,6 +457,17 @@ if enable_previewer
   subdir('previewer')
 endif
 
+# *** Browser Plugin ***
+enable_browser_plugin = get_option('browser_plugin')
+if enable_browser_plugin
+  browser_plugin_dir = get_option('browser_plugin_dir')
+  if not browser_plugin_dir.startswith('/')
+    browser_plugin_dir = join_paths(ev_libdir, browser_plugin_dir)
+  endif
+
+  subdir('browser-plugin')
+endif
+
 subdir('data')
 
 headers = files(
@@ -505,6 +516,7 @@ output += 'Viewer ...................:  ' + enable_viewer.to_string() + '\n'
 output += 'Previewer ................:  ' + enable_previewer.to_string() + '\n'
 output += 'Thumbnailer ..............:  ' + enable_thumbnailer.to_string() + '\n'
 output += 'Nautilus Extensions ......:  ' + enable_nautilus.to_string() + '\n'
+output += 'Browser Plugin ...........:  ' + enable_browser_plugin.to_string() + '\n\n\n'
 output += 'BACKENDS\n\n'
 output += 'Comics ...................:  ' + enable_comics.to_string() + '\n'
 output += 'DJVU .....................:  ' + enable_djvu.to_string() + '\n'
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e75b0619..ebfc72b5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -20,6 +20,7 @@ backend/tiff/tiff-document.c
 backend/tiff/tiffdocument.evince-backend.desktop.in.in
 backend/xps/evince-xpsdocument.metainfo.xml.in.in
 backend/xps/xpsdocument.evince-backend.desktop.in.in
+browser-plugin/EvBrowserPluginToolbar.cpp
 data/org.gnome.Evince.desktop.in.in
 data/org.gnome.Evince.gschema.xml
 data/org.gnome.Evince-previewer.desktop.in.in


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