diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp
index 38acff3ef9..f849a5dbd2 100644
--- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp
+++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.cpp
@@ -1,475 +1,622 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include "berryHelpPluginActivator.h"
 
 #include "berryHelpContentView.h"
 #include "berryHelpIndexView.h"
 #include "berryHelpSearchView.h"
 #include "berryHelpEditor.h"
 #include "berryHelpEditorInput.h"
 #include "berryHelpEditorInputFactory.h"
 #include "berryHelpPerspective.h"
+#include "berryHelpWebView.h"
 
 #include "berryQHelpEngineConfiguration.h"
 #include "berryQHelpEngineWrapper.h"
 
 #include <berryPlatformUI.h>
 
 #include <service/event/ctkEventConstants.h>
 
 #include <QDir>
 #include <QDateTime>
+#include <QTimer>
+#include <QWebEngineProfile>
+#include <QWebEngineUrlRequestJob>
+#include <QWebEngineUrlSchemeHandler>
+
+namespace
+{
+  class HelpDeviceReply final : public QIODevice
+  {
+  public:
+    HelpDeviceReply(const QUrl& request, const QByteArray& fileData);
+    ~HelpDeviceReply() override;
+
+    qint64 bytesAvailable() const override;
+    void close() override;
+
+  private:
+    qint64 readData(char* data, qint64 maxlen) override;
+    qint64 writeData(const char* data, qint64 maxlen) override;
+
+    QByteArray m_Data;
+    const qint64 m_OrigLen;
+  };
+
+  HelpDeviceReply::HelpDeviceReply(const QUrl&, const QByteArray& fileData)
+    : m_Data(fileData),
+    m_OrigLen(fileData.length())
+  {
+    this->setOpenMode(QIODevice::ReadOnly);
+
+    QTimer::singleShot(0, this, &QIODevice::readyRead);
+    QTimer::singleShot(0, this, &QIODevice::readChannelFinished);
+  }
+
+  HelpDeviceReply::~HelpDeviceReply()
+  {
+  }
+
+  qint64 HelpDeviceReply::bytesAvailable() const
+  {
+    return m_Data.length() + QIODevice::bytesAvailable();
+  }
+
+  void HelpDeviceReply::close()
+  {
+    QIODevice::close();
+    this->deleteLater();
+  }
+
+  qint64 HelpDeviceReply::readData(char* data, qint64 maxlen)
+  {
+    qint64 len = qMin(qint64(m_Data.length()), maxlen);
+
+    if (len)
+    {
+      memcpy(data, m_Data.constData(), len);
+      m_Data.remove(0, len);
+    }
+
+    return len;
+  }
+
+  qint64 HelpDeviceReply::writeData(const char*, qint64)
+  {
+    return 0;
+  }
+
+
+  class HelpUrlSchemeHandler final : public QWebEngineUrlSchemeHandler
+  {
+  public:
+    explicit HelpUrlSchemeHandler(QObject* parent = nullptr);
+    ~HelpUrlSchemeHandler() override;
+
+    void requestStarted(QWebEngineUrlRequestJob* job) override;
+  };
+
+  HelpUrlSchemeHandler::HelpUrlSchemeHandler(QObject* parent)
+    : QWebEngineUrlSchemeHandler(parent)
+  {
+  }
+
+  HelpUrlSchemeHandler::~HelpUrlSchemeHandler()
+  {
+  }
+
+  enum class ResolveUrlResult
+  {
+    Error,
+    Redirect,
+    Data
+  };
+
+  ResolveUrlResult ResolveUrl(const QUrl& url, QUrl& redirectedUrl, QByteArray& data)
+  {
+    auto& helpEngine = berry::HelpPluginActivator::getInstance()->getQHelpEngine();
+
+    const auto targetUrl = helpEngine.findFile(url);
+
+    if (!targetUrl.isValid())
+      return ResolveUrlResult::Error;
+
+    if (targetUrl != url)
+    {
+      redirectedUrl = targetUrl;
+      return ResolveUrlResult::Redirect;
+    }
+
+    data = helpEngine.fileData(targetUrl);
+    return ResolveUrlResult::Data;
+  }
+
+
+  void HelpUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob* job)
+  {
+    QUrl url = job->requestUrl();
+    QUrl redirectedUrl;
+    QByteArray data;
+
+    switch (ResolveUrl(url, redirectedUrl, data))
+    {
+    case ResolveUrlResult::Data:
+      job->reply(
+        berry::HelpWebView::mimeFromUrl(url).toLatin1(),
+        new HelpDeviceReply(url, data));
+      break;
+
+    case ResolveUrlResult::Redirect:
+      job->redirect(redirectedUrl);
+      break;
+
+    case ResolveUrlResult::Error:
+      job->reply(
+        QByteArrayLiteral("text/html"),
+        new HelpDeviceReply(url, berry::HelpWebView::m_PageNotFoundMessage.arg(url.toString()).toUtf8()));
+      break;
+    }
+  }
+}
 
 namespace berry {
 
 class HelpPerspectiveListener : public IPerspectiveListener
 {
 public:
 
   Events::Types GetPerspectiveEventTypes() const override;
 
   using IPerspectiveListener::PerspectiveChanged;
 
   void PerspectiveOpened(const SmartPointer<IWorkbenchPage>& page, const IPerspectiveDescriptor::Pointer& perspective) override;
   void PerspectiveChanged(const SmartPointer<IWorkbenchPage>& page, const IPerspectiveDescriptor::Pointer& perspective, const QString &changeId) override;
 };
 
 class HelpWindowListener : public IWindowListener
 {
 public:
 
   HelpWindowListener();
   ~HelpWindowListener() override;
 
   void WindowClosed(const IWorkbenchWindow::Pointer& window) override;
   void WindowOpened(const IWorkbenchWindow::Pointer& window) override;
 
 private:
 
   // We use the same perspective listener for every window
   QScopedPointer<IPerspectiveListener> perspListener;
 };
 
 
 HelpPluginActivator* HelpPluginActivator::instance = nullptr;
 
 HelpPluginActivator::HelpPluginActivator()
-  : pluginListener(nullptr)
+  : helpSchemeHandler(const_cast<QWebEngineUrlSchemeHandler*>(QWebEngineProfile::defaultProfile()->urlSchemeHandler("qthelp"))),
+    pluginListener(nullptr)
 {
   this->instance = this;
+
+  if (helpSchemeHandler == nullptr)
+  {
+    helpSchemeHandler = new HelpUrlSchemeHandler(this);
+    QWebEngineProfile::defaultProfile()->installUrlSchemeHandler("qthelp", helpSchemeHandler);
+  }
 }
 
 HelpPluginActivator::~HelpPluginActivator()
 {
   instance = nullptr;
 }
 
 void
 HelpPluginActivator::start(ctkPluginContext* context)
 {
   BERRY_REGISTER_EXTENSION_CLASS(berry::HelpContentView, context)
   BERRY_REGISTER_EXTENSION_CLASS(berry::HelpIndexView, context)
   BERRY_REGISTER_EXTENSION_CLASS(berry::HelpSearchView, context)
   BERRY_REGISTER_EXTENSION_CLASS(berry::HelpEditor, context)
   BERRY_REGISTER_EXTENSION_CLASS(berry::HelpEditorInputFactory, context)
   BERRY_REGISTER_EXTENSION_CLASS(berry::HelpPerspective, context)
 
   QFileInfo qhcInfo = context->getDataFile("qthelpcollection.qhc");
   helpEngine.reset(new QHelpEngineWrapper(qhcInfo.absoluteFilePath()));
   helpEngine->setReadOnly(false);
   if (!helpEngine->setupData())
   {
     BERRY_ERROR << "QHelpEngine set-up failed: " << helpEngine->error().toStdString();
     return;
   }
 
   helpEngineConfiguration.reset(new QHelpEngineConfiguration(context, *helpEngine.data()));
 
   delete pluginListener;
   pluginListener = new QCHPluginListener(context, helpEngine.data());
   context->connectPluginListener(pluginListener, SLOT(pluginChanged(ctkPluginEvent)));
 
   // register all QCH files from all the currently installed plugins
   pluginListener->processPlugins();
 
   helpEngine->initialDocSetupDone();
 
   // Register a wnd listener which registers a perspective listener for each
   // new window. The perspective listener opens the help home page in the window
   // if no other help page is opened yet.
   wndListener.reset(new HelpWindowListener());
   PlatformUI::GetWorkbench()->AddWindowListener(wndListener.data());
 
   // Register an event handler for CONTEXTHELP_REQUESTED events
   helpContextHandler.reset(new HelpContextHandler);
   ctkDictionary helpHandlerProps;
   helpHandlerProps.insert(ctkEventConstants::EVENT_TOPIC, "org/blueberry/ui/help/CONTEXTHELP_REQUESTED");
   context->registerService<ctkEventHandler>(helpContextHandler.data(), helpHandlerProps);
 }
 
 void
 HelpPluginActivator::stop(ctkPluginContext* /*context*/)
 {
   delete pluginListener;
   pluginListener = nullptr;
 
   if (PlatformUI::IsWorkbenchRunning())
   {
     PlatformUI::GetWorkbench()->RemoveWindowListener(wndListener.data());
   }
   wndListener.reset();
 
   helpEngineConfiguration.reset();
   helpEngine.reset();
 }
 
 HelpPluginActivator *HelpPluginActivator::getInstance()
 {
   return instance;
 }
 
 QHelpEngineWrapper& HelpPluginActivator::getQHelpEngine()
 {
   return *helpEngine;
 }
 
 void HelpPluginActivator::linkActivated(IWorkbenchPage::Pointer page, const QUrl &link)
 {
   IEditorInput::Pointer input(new HelpEditorInput(link));
 
   // see if an editor with the same input is already open
   IEditorPart::Pointer reuseEditor = page->FindEditor(input);
   if (reuseEditor)
   {
     // just activate it
     page->Activate(reuseEditor);
   }
   else
   {
     // reuse the currently active editor, if it is a HelpEditor
     reuseEditor = page->GetActiveEditor();
     if (reuseEditor.IsNotNull() && page->GetReference(reuseEditor)->GetId() == HelpEditor::EDITOR_ID)
     {
       page->ReuseEditor(reuseEditor.Cast<IReusableEditor>(), input);
       page->Activate(reuseEditor);
     }
     else
     {
       // get the last used HelpEditor instance
       QList<IEditorReference::Pointer> editors =
           page->FindEditors(IEditorInput::Pointer(nullptr), HelpEditor::EDITOR_ID, IWorkbenchPage::MATCH_ID);
       if (editors.empty())
       {
         // no HelpEditor is currently open, create a new one
         page->OpenEditor(input, HelpEditor::EDITOR_ID);
       }
       else
       {
         // reuse an existing editor
         reuseEditor = editors.front()->GetEditor(false);
         page->ReuseEditor(reuseEditor.Cast<IReusableEditor>(), input);
         page->Activate(reuseEditor);
       }
     }
   }
 }
 
 QCHPluginListener::QCHPluginListener(ctkPluginContext* context, QHelpEngine* helpEngine)
   : delayRegistration(true), context(context), helpEngine(helpEngine)
 {}
 
 void QCHPluginListener::processPlugins()
 {
   QMutexLocker lock(&mutex);
   processPlugins_unlocked();
 }
 
 void QCHPluginListener::pluginChanged(const ctkPluginEvent& event)
 {
   QMutexLocker lock(&mutex);
   if (delayRegistration)
   {
     this->processPlugins_unlocked();
     return;
   }
 
   /* Only should listen for RESOLVED and UNRESOLVED events.
    *
    * When a plugin is updated the Framework will publish an UNRESOLVED and
    * then a RESOLVED event which should cause the plugin to be removed
    * and then added back into the registry.
    *
    * When a plugin is uninstalled the Framework should publish an UNRESOLVED
    * event and then an UNINSTALLED event so the plugin will have been removed
    * by the UNRESOLVED event before the UNINSTALLED event is published.
    */
   QSharedPointer<ctkPlugin> plugin = event.getPlugin();
   switch (event.getType())
   {
   case ctkPluginEvent::RESOLVED :
     addPlugin(plugin);
     break;
   case ctkPluginEvent::UNRESOLVED :
     removePlugin(plugin);
     break;
   default:
     break;
   }
 }
 
 void QCHPluginListener::processPlugins_unlocked()
 {
   if (!delayRegistration) return;
 
   foreach (QSharedPointer<ctkPlugin> plugin, context->getPlugins())
   {
     if (isPluginResolved(plugin))
       addPlugin(plugin);
     else
       removePlugin(plugin);
   }
 
   delayRegistration = false;
 }
 
 bool QCHPluginListener::isPluginResolved(QSharedPointer<ctkPlugin> plugin)
 {
   return (plugin->getState() & (ctkPlugin::RESOLVED | ctkPlugin::ACTIVE | ctkPlugin::STARTING | ctkPlugin::STOPPING)) != 0;
 }
 
 void QCHPluginListener::removePlugin(QSharedPointer<ctkPlugin> plugin)
 {
   // bail out if system plugin
   if (plugin->getPluginId() == 0) return;
 
   QFileInfo qchDirInfo = context->getDataFile("qch_files/" + QString::number(plugin->getPluginId()));
   if (qchDirInfo.exists())
   {
     QDir qchDir(qchDirInfo.absoluteFilePath());
     QStringList qchEntries = qchDir.entryList(QStringList("*.qch"));
     QStringList qchFiles;
     foreach(QString qchEntry, qchEntries)
     {
       qchFiles << qchDir.absoluteFilePath(qchEntry);
     }
     // unregister the cached qch files
     foreach(QString qchFile, qchFiles)
     {
       QString namespaceName = QHelpEngineCore::namespaceName(qchFile);
       if (namespaceName.isEmpty())
       {
         BERRY_ERROR << "Could not get the namespace for qch file " << qchFile.toStdString();
         continue;
       }
       else
       {
         if (!helpEngine->unregisterDocumentation(namespaceName))
         {
           BERRY_ERROR << "Unregistering qch namespace " << namespaceName.toStdString() << " failed: " << helpEngine->error().toStdString();
         }
       }
     }
     // clean the directory
     foreach(QString qchEntry, qchEntries)
     {
       qchDir.remove(qchEntry);
     }
   }
 }
 
 void QCHPluginListener::addPlugin(QSharedPointer<ctkPlugin> plugin)
 {
   // bail out if system plugin
   if (plugin->getPluginId() == 0) return;
 
   QFileInfo qchDirInfo = context->getDataFile("qch_files/" + QString::number(plugin->getPluginId()));
   QUrl location(plugin->getLocation());
   QFileInfo pluginFileInfo(location.toLocalFile());
 
   if (!qchDirInfo.exists() || qchDirInfo.lastModified() < pluginFileInfo.lastModified())
   {
     removePlugin(plugin);
 
     if (!qchDirInfo.exists())
     {
       QDir().mkpath(qchDirInfo.absoluteFilePath());
     }
 
     QStringList localQCHFiles;
     QStringList resourceList = plugin->findResources("/", "*.qch", true);
     foreach(QString resource, resourceList)
     {
       QByteArray content = plugin->getResource(resource);
       QFile localFile(qchDirInfo.absoluteFilePath() + "/" + resource.section('/', -1));
       localFile.open(QIODevice::WriteOnly);
       localFile.write(content);
       localFile.close();
       if (localFile.error() != QFile::NoError)
       {
         BERRY_WARN << "Error writing " << localFile.fileName().toStdString()
                    << ": " << localFile.errorString().toStdString();
       }
       else
       {
         localQCHFiles << localFile.fileName();
       }
     }
 
     foreach(QString qchFile, localQCHFiles)
     {
       if (!helpEngine->registerDocumentation(qchFile))
       {
         BERRY_ERROR << "Registering qch file " << qchFile.toStdString() << " failed: " << helpEngine->error().toStdString();
       }
     }
   }
 
 }
 
 IPerspectiveListener::Events::Types HelpPerspectiveListener::GetPerspectiveEventTypes() const
 {
   return Events::OPENED | Events::CHANGED;
 }
 
 void HelpPerspectiveListener::PerspectiveOpened(const SmartPointer<IWorkbenchPage>& page, const IPerspectiveDescriptor::Pointer& perspective)
 {
   // if no help editor is opened, open one showing the home page
   if (perspective->GetId() == HelpPerspective::ID &&
       page->FindEditors(IEditorInput::Pointer(nullptr), HelpEditor::EDITOR_ID, IWorkbenchPage::MATCH_ID).empty())
   {
     IEditorInput::Pointer input(new HelpEditorInput());
     page->OpenEditor(input, HelpEditor::EDITOR_ID);
   }
 }
 
 void HelpPerspectiveListener::PerspectiveChanged(const SmartPointer<IWorkbenchPage>& page, const IPerspectiveDescriptor::Pointer& perspective, const QString &changeId)
 {
   if (perspective->GetId() == HelpPerspective::ID && changeId == IWorkbenchPage::CHANGE_RESET)
   {
     PerspectiveOpened(page, perspective);
   }
 }
 
 HelpWindowListener::HelpWindowListener()
   : perspListener(new HelpPerspectiveListener())
 {
   // Register perspective listener for already opened windows
   typedef QList<IWorkbenchWindow::Pointer> WndVec;
   WndVec windows = PlatformUI::GetWorkbench()->GetWorkbenchWindows();
   for (WndVec::iterator i = windows.begin(); i != windows.end(); ++i)
   {
     (*i)->AddPerspectiveListener(perspListener.data());
   }
 }
 
 HelpWindowListener::~HelpWindowListener()
 {
   if (!PlatformUI::IsWorkbenchRunning()) return;
 
   typedef QList<IWorkbenchWindow::Pointer> WndVec;
   WndVec windows = PlatformUI::GetWorkbench()->GetWorkbenchWindows();
   for (WndVec::iterator i = windows.begin(); i != windows.end(); ++i)
   {
     (*i)->RemovePerspectiveListener(perspListener.data());
   }
 }
 
 void HelpWindowListener::WindowClosed(const IWorkbenchWindow::Pointer& window)
 {
   window->RemovePerspectiveListener(perspListener.data());
 }
 
 void HelpWindowListener::WindowOpened(const IWorkbenchWindow::Pointer& window)
 {
   window->AddPerspectiveListener(perspListener.data());
 }
 
 void HelpContextHandler::handleEvent(const ctkEvent &event)
 {
   struct _runner : public Poco::Runnable
   {
     _runner(const ctkEvent& ev) : ev(ev) {}
 
     void run() override
     {
       QUrl helpUrl;
       if (ev.containsProperty("url"))
       {
         helpUrl = QUrl(ev.getProperty("url").toString());
       }
       else
       {
         helpUrl = contextUrl();
       }
 
       HelpPluginActivator::linkActivated(PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(),
                                          helpUrl);
       delete this;
     }
 
     QUrl contextUrl() const
     {
       berry::IWorkbench* currentWorkbench = berry::PlatformUI::GetWorkbench();
       if (currentWorkbench)
       {
         berry::IWorkbenchWindow::Pointer currentWorkbenchWindow = currentWorkbench->GetActiveWorkbenchWindow();
         if (currentWorkbenchWindow)
         {
           berry::IWorkbenchPage::Pointer currentPage = currentWorkbenchWindow->GetActivePage();
           if (currentPage)
           {
             berry::IWorkbenchPart::Pointer currentPart = currentPage->GetActivePart();
             if (currentPart)
             {
               QString pluginID = currentPart->GetSite()->GetPluginId();
               QString viewID = currentPart->GetSite()->GetId();
               QString loc = "qthelp://" + pluginID + "/bundle/%1.html";
 
               QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine();
               // Get view help page if available
               QUrl contextUrl(loc.arg(viewID.replace(".", "_")));
               QUrl url = helpEngine.findFile(contextUrl);
               if (url.isValid()) return url;
               else
               {
                 BERRY_INFO << "Context help url invalid: " << contextUrl.toString().toStdString();
               }
               // If no view help exists get plugin help if available
               QUrl pluginContextUrl(loc.arg(pluginID.replace(".", "_")));
               url = helpEngine.findFile(pluginContextUrl);
               if (url.isValid()) return url;
               // Try to get the index.html file of the plug-in contributing the
               // currently active part.
               QUrl pluginIndexUrl(loc.arg("index"));
               url = helpEngine.findFile(pluginIndexUrl);
               if (url != pluginIndexUrl)
               {
                 // Use the default page instead of another index.html
                 // (merged via the virtual folder property).
                 url = QUrl();
               }
               return url;
             }
           }
         }
       }
       return QUrl();
     }
 
     ctkEvent ev;
   };
   // sync with GUI thread
   Display::GetDefault()->AsyncExec(new _runner(event));
 }
 
 }
diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h
index 5464fde6f7..da1ee7a7e9 100644
--- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h
+++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpPluginActivator.h
@@ -1,114 +1,116 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef BERRYLOGPLUGIN_H_
 #define BERRYLOGPLUGIN_H_
 
 #include <ctkPluginActivator.h>
 
 #include <service/event/ctkEvent.h>
 #include <service/event/ctkEventHandler.h>
 
 #include <QScopedPointer>
 #include <QMutex>
 
 #include <berryIWorkbenchPage.h>
 #include <berryIWindowListener.h>
 
 class QHelpEngine;
+class QWebEngineUrlSchemeHandler;
 
 namespace berry {
 
 class QHelpEngineConfiguration;
 class QHelpEngineWrapper;
 class QCHPluginListener;
 
 class HelpContextHandler : public QObject, public ctkEventHandler
 {
   Q_OBJECT
   Q_INTERFACES(ctkEventHandler)
 
 public:
 
   void handleEvent(const ctkEvent& event) override;
 };
 
 class HelpPluginActivator : public QObject, public ctkPluginActivator
 {
   Q_OBJECT
   Q_PLUGIN_METADATA(IID "org_blueberry_ui_qt_help")
   Q_INTERFACES(ctkPluginActivator)
 
 public:
 
   HelpPluginActivator();
   ~HelpPluginActivator() override;
 
   void start(ctkPluginContext* context) override;
   void stop(ctkPluginContext* context) override;
 
   static HelpPluginActivator* getInstance();
 
   static void linkActivated(IWorkbenchPage::Pointer page, const QUrl &link);
 
   QHelpEngineWrapper& getQHelpEngine();
 
 private:
 
   Q_DISABLE_COPY(HelpPluginActivator)
 
   static HelpPluginActivator* instance;
 
   QScopedPointer<QHelpEngineWrapper, QScopedPointerDeleteLater > helpEngine;
   QScopedPointer<QHelpEngineConfiguration> helpEngineConfiguration;
   QScopedPointer<HelpContextHandler> helpContextHandler;
+  QWebEngineUrlSchemeHandler* helpSchemeHandler;
 
   QCHPluginListener* pluginListener;
   QScopedPointer<IWindowListener> wndListener;
 };
 
 /**
  * A listener for CTK plugin events. When plugins come and go we look to see
  * if there are any qch files and update the QHelpEngine accordingly.
  */
 class QCHPluginListener : public QObject {
 
   Q_OBJECT
 
 public:
 
   QCHPluginListener(ctkPluginContext* context, QHelpEngine* helpEngine);
 
   void processPlugins();
 
 public Q_SLOTS:
 
   void pluginChanged(const ctkPluginEvent& event);
 
 private:
 
   void processPlugins_unlocked();
 
   bool isPluginResolved(QSharedPointer<ctkPlugin> plugin);
 
   void removePlugin(QSharedPointer<ctkPlugin> plugin);
   void addPlugin(QSharedPointer<ctkPlugin> plugin);
 
   QMutex mutex;
   bool delayRegistration;
   ctkPluginContext* context;
   QHelpEngine* helpEngine;
 };
 
 }
 
 #endif /*BERRYLOGPLUGIN_H_*/
diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp
index 1e81da25a5..9c9e2eea2f 100644
--- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp
+++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.cpp
@@ -1,450 +1,311 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #include "berryHelpWebView.h"
 
 #include "berryHelpPluginActivator.h"
 #include "berryHelpEditor.h"
 #include "berryHelpEditorInput.h"
 #include "berryQHelpEngineWrapper.h"
 
 #include <berryIWorkbenchPage.h>
 
 #include <QCoreApplication>
-#include <QTimer>
 #include <QStringBuilder>
 #include <QTemporaryFile>
 #include <QDesktopServices>
 #include <QWheelEvent>
 
 #include <QWebEngineSettings>
-#include <QWebEngineUrlSchemeHandler>
-#include <QWebEngineUrlRequestJob>
-#include <QWebEngineProfile>
 
 namespace berry {
 
 struct ExtensionMap {
   const char *extension;
   const char *mimeType;
 } extensionMap[] = {
     { ".bmp", "image/bmp" },
     { ".css", "text/css" },
     { ".gif", "image/gif" },
     { ".html", "text/html" },
     { ".htm", "text/html" },
     { ".ico", "image/x-icon" },
     { ".jpeg", "image/jpeg" },
     { ".jpg", "image/jpeg" },
     { ".js", "application/x-javascript" },
     { ".mng", "video/x-mng" },
     { ".pbm", "image/x-portable-bitmap" },
     { ".pgm", "image/x-portable-graymap" },
     { ".pdf", "application/pdf" },
     { ".png", "image/png" },
     { ".ppm", "image/x-portable-pixmap" },
     { ".rss", "application/rss+xml" },
     { ".svg", "image/svg+xml" },
     { ".svgz", "image/svg+xml" },
     { ".text", "text/plain" },
     { ".tif", "image/tiff" },
     { ".tiff", "image/tiff" },
     { ".txt", "text/plain" },
     { ".xbm", "image/x-xbitmap" },
     { ".xml", "text/xml" },
     { ".xpm", "image/x-xpm" },
     { ".xsl", "text/xsl" },
     { ".xhtml", "application/xhtml+xml" },
     { ".wml", "text/vnd.wap.wml" },
     { ".wmlc", "application/vnd.wap.wmlc" },
     { "about:blank", nullptr },
     { nullptr, nullptr }
 };
 
-class HelpDeviceReply final : public QIODevice
-{
-public:
-  HelpDeviceReply(const QUrl& request, const QByteArray& fileData);
-  ~HelpDeviceReply() override;
-
-  qint64 bytesAvailable() const override;
-  void close() override;
-
-private:
-  qint64 readData(char* data, qint64 maxlen) override;
-  qint64 writeData(const char* data, qint64 maxlen) override;
-
-  QByteArray m_Data;
-  const qint64 m_OrigLen;
-};
-
-HelpDeviceReply::HelpDeviceReply(const QUrl&, const QByteArray& fileData)
-  : m_Data(fileData),
-    m_OrigLen(fileData.length())
-{
-  this->setOpenMode(QIODevice::ReadOnly);
-
-  QTimer::singleShot(0, this, &QIODevice::readyRead);
-  QTimer::singleShot(0, this, &QIODevice::readChannelFinished);
-}
-
-HelpDeviceReply::~HelpDeviceReply()
-{
-}
-
-qint64 HelpDeviceReply::bytesAvailable() const
-{
-  return m_Data.length() + QIODevice::bytesAvailable();
-}
-
-void HelpDeviceReply::close()
-{
-  QIODevice::close();
-  this->deleteLater();
-}
-
-qint64 HelpDeviceReply::readData(char* data, qint64 maxlen)
-{
-  qint64 len = qMin(qint64(m_Data.length()), maxlen);
-
-  if (len)
-  {
-    memcpy(data, m_Data.constData(), len);
-    m_Data.remove(0, len);
-  }
-
-  return len;
-}
-
-qint64 HelpDeviceReply::writeData(const char*, qint64)
-{
-  return 0;
-}
-
-
-class HelpUrlSchemeHandler final : public QWebEngineUrlSchemeHandler
-{
-public:
-  explicit HelpUrlSchemeHandler(QObject* parent = nullptr);
-  ~HelpUrlSchemeHandler() override;
-
-  void requestStarted(QWebEngineUrlRequestJob* job) override;
-};
-
-HelpUrlSchemeHandler::HelpUrlSchemeHandler(QObject* parent)
-  : QWebEngineUrlSchemeHandler(parent)
-{
-}
-
-HelpUrlSchemeHandler::~HelpUrlSchemeHandler()
-{
-}
-
-enum class ResolveUrlResult
-{
-  Error,
-  Redirect,
-  Data
-};
-
-ResolveUrlResult ResolveUrl(const QUrl& url, QUrl& redirectedUrl, QByteArray& data)
-{
-  auto& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine();
-
-  const auto targetUrl = helpEngine.findFile(url);
-
-  if (!targetUrl.isValid())
-    return ResolveUrlResult::Error;
-
-  if (targetUrl != url)
-  {
-    redirectedUrl = targetUrl;
-    return ResolveUrlResult::Redirect;
-  }
-
-  data = helpEngine.fileData(targetUrl);
-  return ResolveUrlResult::Data;
-}
-
-
-void HelpUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob* job)
-{
-  QUrl url = job->requestUrl();
-  QUrl redirectedUrl;
-  QByteArray data;
-
-  switch (ResolveUrl(url, redirectedUrl, data))
-  {
-  case ResolveUrlResult::Data:
-    job->reply(
-      HelpWebView::mimeFromUrl(url).toLatin1(),
-      new HelpDeviceReply(url, data));
-    break;
-
-  case ResolveUrlResult::Redirect:
-    job->redirect(redirectedUrl);
-    break;
-
-  case ResolveUrlResult::Error:
-    job->reply(
-      QByteArrayLiteral("text/html"),
-      new HelpDeviceReply(url, HelpWebView::m_PageNotFoundMessage.arg(url.toString()).toUtf8()));
-    break;
-  }
-}
-
 const QString HelpWebView::m_PageNotFoundMessage =
     QCoreApplication::translate("org.blueberry.ui.qt.help", "<title>Context Help</title><div "
                                 "align=\"center\"><br><br><h1>No help page found for identifier</h1><br><h3>'%1'"
                                 "</h3></div>");
 
 const QString HelpWebView::m_MissingContextMessage =
     QCoreApplication::translate("org.blueberry.ui.qt.help", "<title>Context Help</title><div "
                                 "align=\"center\"><br><br><h1>Unknown context..</h1><h1>&nbsp;</h1><h1>Please click inside a view and hit F1 again!</h1></div>");
 
 class HelpPage final : public QWebEnginePage
 {
 public:
   explicit HelpPage(QObject* parent = nullptr);
   ~HelpPage() override;
 
 private:
   bool acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame) override;
 };
 
 HelpPage::HelpPage(QObject* parent)
   : QWebEnginePage(parent)
 {
 }
 
 HelpPage::~HelpPage()
 {
 }
 
 bool HelpPage::acceptNavigationRequest(const QUrl& url, NavigationType, bool)
 {
   if (url.scheme().contains("http"))
   {
     QDesktopServices::openUrl(url);
     return false;
   }
 
   return true;
 }
 
 HelpWebView::HelpWebView(IEditorSite::Pointer, QWidget *parent, qreal zoom)
   : QWebEngineView(parent),
     m_LoadFinished(false),
-    m_HelpEngine(HelpPluginActivator::getInstance()->getQHelpEngine()),
-    m_HelpSchemeHandler(new HelpUrlSchemeHandler(this))
+    m_HelpEngine(HelpPluginActivator::getInstance()->getQHelpEngine())
 {
-  QWebEngineProfile::defaultProfile()->installUrlSchemeHandler("qthelp", m_HelpSchemeHandler);
-
   auto helpPage = new HelpPage(this);
   this->setPage(helpPage);
 
   this->setAcceptDrops(false);
 
   auto action = pageAction(QWebEnginePage::OpenLinkInNewWindow);
   action->setText("Open Link in New Tab");
 
   if (parent == nullptr)
     action->setVisible(false);
 
   this->pageAction(QWebEnginePage::DownloadLinkToDisk)->setVisible(false);
   this->pageAction(QWebEnginePage::DownloadImageToDisk)->setVisible(false);
 
   connect(pageAction(QWebEnginePage::Copy), SIGNAL(changed()), this, SLOT(actionChanged()));
   connect(pageAction(QWebEnginePage::Back), SIGNAL(changed()), this, SLOT(actionChanged()));
   connect(pageAction(QWebEnginePage::Forward), SIGNAL(changed()), this, SLOT(actionChanged()));
   connect(page(), SIGNAL(linkHovered(QString)), this, SIGNAL(highlighted(QString)));
   connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl)));
   connect(this, SIGNAL(loadStarted()), this, SLOT(setLoadStarted()));
   connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool)));
 
   this->setFont(this->viewerFont());
   this->setZoomFactor(zoom == 0.0 ? 1.0 : zoom);
 }
 
 HelpWebView::~HelpWebView()
 {
 }
 
 QFont HelpWebView::viewerFont() const
 {
   QWebEngineSettings* webSettings = settings();
   return QFont(webSettings->fontFamily(QWebEngineSettings::StandardFont),
                webSettings->fontSize(QWebEngineSettings::DefaultFontSize));
 }
 
 void HelpWebView::setViewerFont(const QFont &font)
 {
   QWebEngineSettings *webSettings = settings();
   webSettings->setFontFamily(QWebEngineSettings::StandardFont, font.family());
   webSettings->setFontSize(QWebEngineSettings::DefaultFontSize, font.pointSize());
 }
 
 void HelpWebView::scaleUp()
 {
   setZoomFactor(zoomFactor() + 0.1);
 }
 
 void HelpWebView::scaleDown()
 {
   setZoomFactor(qMax(0.0, zoomFactor() - 0.1));
 }
 
 void HelpWebView::resetScale()
 {
   setZoomFactor(1.0);
 }
 
 bool HelpWebView::handleForwardBackwardMouseButtons(QMouseEvent *e)
 {
   if (e->button() == Qt::XButton1)
   {
     triggerPageAction(QWebEnginePage::Back);
     return true;
   }
 
   if (e->button() == Qt::XButton2)
   {
     triggerPageAction(QWebEnginePage::Forward);
     return true;
   }
 
   return false;
 }
 
 void HelpWebView::setSource(const QUrl &url)
 {
   if (url.toString().trimmed().isEmpty()) {
     setHtml(m_MissingContextMessage);
   }
   else if (m_HelpEngine.findFile(url).isValid())
   {
     load(url);
   }
   else
   {
     setHtml(m_PageNotFoundMessage.arg(url.toString()));
   }
 }
 
 void HelpWebView::wheelEvent(QWheelEvent *e)
 {
   if (e->modifiers()& Qt::ControlModifier)
   {
     e->accept();
     e->angleDelta().y() > 0 ? scaleUp() : scaleDown();
   }
   else
   {
     QWebEngineView::wheelEvent(e);
   }
 }
 
 void HelpWebView::actionChanged()
 {
   QAction *a = qobject_cast<QAction *>(sender());
   if (a == pageAction(QWebEnginePage::Copy))
     emit copyAvailable(a->isEnabled());
   else if (a == pageAction(QWebEnginePage::Back))
     emit backwardAvailable(a->isEnabled());
   else if (a == pageAction(QWebEnginePage::Forward))
     emit forwardAvailable(a->isEnabled());
 }
 
 void HelpWebView::setLoadStarted()
 {
   m_LoadFinished = false;
 }
 
 void HelpWebView::setLoadFinished(bool ok)
 {
   m_LoadFinished = ok;
   emit sourceChanged(url());
 }
 
 QString HelpWebView::mimeFromUrl(const QUrl &url)
 {
   const QString &path = url.path();
   const int index = path.lastIndexOf(QLatin1Char('.'));
   const QByteArray &ext = path.mid(index).toUtf8().toLower();
 
   const ExtensionMap *e = extensionMap;
   while (e->extension)
   {
     if (ext == e->extension)
       return QLatin1String(e->mimeType);
     ++e;
   }
   return QLatin1String("");
 }
 
 bool HelpWebView::canOpenPage(const QString &url)
 {
   return !mimeFromUrl(url).isEmpty();
 }
 
 bool HelpWebView::isLocalUrl(const QUrl &url)
 {
   const QString &scheme = url.scheme();
   return scheme.isEmpty()
       || scheme == QLatin1String("file")
       || scheme == QLatin1String("qrc")
       || scheme == QLatin1String("data")
       || scheme == QLatin1String("qthelp")
       || scheme == QLatin1String("about");
 }
 
 bool HelpWebView::launchWithExternalApp(const QUrl &url)
 {
   if (isLocalUrl(url))
   {
     const QHelpEngine& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine();
     const QUrl &resolvedUrl = helpEngine.findFile(url);
     if (!resolvedUrl.isValid())
       return false;
 
     const QString& path = resolvedUrl.path();
     if (!canOpenPage(path))
     {
       QTemporaryFile tmpTmpFile;
       if (!tmpTmpFile.open())
         return false;
 
       const QString &extension = QFileInfo(path).completeSuffix();
       QFile actualTmpFile(tmpTmpFile.fileName() % QLatin1String(".")
                           % extension);
       if (!actualTmpFile.open(QIODevice::ReadWrite | QIODevice::Truncate))
         return false;
 
       actualTmpFile.write(helpEngine.fileData(resolvedUrl));
       actualTmpFile.close();
       return QDesktopServices::openUrl(QUrl(actualTmpFile.fileName()));
     }
   }
   else if (url.scheme() == QLatin1String("http"))
   {
     return QDesktopServices::openUrl(url);
   }
   return false;
 }
 
 void HelpWebView::home()
 {
   setSource(m_HelpEngine.homePage());
 }
 
 }
diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h
index b7d8029759..f6f21548bb 100644
--- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h
+++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpWebView.h
@@ -1,104 +1,101 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 
 #ifndef BERRYHELPWEBVIEW_H
 #define BERRYHELPWEBVIEW_H
 
 #include <QFont>
 #include <QAction>
 
 #include <QWebEnginePage>
 #include <QWebEngineView>
 
 #include <berryIEditorSite.h>
 
-class QWebEngineUrlSchemeHandler;
-
 namespace berry {
 
 class QHelpEngineWrapper;
 
 class HelpWebView : public QWebEngineView
 {
   Q_OBJECT
 
 public:
   explicit HelpWebView(IEditorSite::Pointer editorSite, QWidget *parent, qreal zoom = 0.0);
   ~HelpWebView() override;
 
   QFont viewerFont() const;
   void setViewerFont(const QFont &font);
 
   qreal scale() const { return this->zoomFactor(); }
 
   bool handleForwardBackwardMouseButtons(QMouseEvent *e);
 
   void setSource(const QUrl &url);
 
   inline QString documentTitle() const
   { return title(); }
 
   inline bool hasSelection() const
   { return !selectedText().isEmpty(); } // ### this is suboptimal
 
   inline void copy()
   { return triggerPageAction(QWebEnginePage::Copy); }
 
   inline bool isForwardAvailable() const
   { return pageAction(QWebEnginePage::Forward)->isEnabled(); }
   inline bool isBackwardAvailable() const
   { return pageAction(QWebEnginePage::Back)->isEnabled(); }
   inline bool hasLoadFinished() const
   { return m_LoadFinished; }
 
   static QString mimeFromUrl(const QUrl &url);
   static bool canOpenPage(const QString &url);
   static bool isLocalUrl(const QUrl &url);
   static bool launchWithExternalApp(const QUrl &url);
   static const QString m_MissingContextMessage;
   static const QString m_PageNotFoundMessage;
 
 public Q_SLOTS:
 
   void backward() { back(); }
   void home();
 
   void scaleUp();
   void scaleDown();
   void resetScale();
 
 Q_SIGNALS:
   void copyAvailable(bool enabled);
   void forwardAvailable(bool enabled);
   void backwardAvailable(bool enabled);
   void highlighted(const QString &);
   void sourceChanged(const QUrl &);
 
 protected:
   void wheelEvent(QWheelEvent *) override;
 
 private Q_SLOTS:
   void actionChanged();
   void setLoadStarted();
   void setLoadFinished(bool ok);
 
 private:
 
   bool m_LoadFinished;
   QHelpEngineWrapper& m_HelpEngine;
-  QWebEngineUrlSchemeHandler* m_HelpSchemeHandler;
 };
 
 }
 
 #endif // BERRYHELPWEBVIEW_H