summaryrefslogtreecommitdiffstats
path: root/src/webenginewidgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/webenginewidgets')
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp84
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h7
-rw-r--r--src/webenginewidgets/api/qwebengineview.cpp102
-rw-r--r--src/webenginewidgets/api/qwebengineview_p.h11
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp59
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h12
6 files changed, 174 insertions, 101 deletions
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 3a2a07520..a6267c223 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -273,8 +273,6 @@ RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostVie
// The new delegate will not be deleted by the parent view though, because we unset the parent
// when the parent is destroyed. The delegate will be destroyed by Chromium when the popup is
// dismissed.
- // If the delegate is not for a popup, but for a newly created QWebEngineView, the parent is 0
- // just like before.
return new RenderWidgetHostViewQtDelegateWidget(client, this->view);
}
@@ -718,12 +716,87 @@ const QObject *QWebEnginePagePrivate::holdingQObject() const
return q;
}
+void QWebEnginePagePrivate::widgetChanged(RenderWidgetHostViewQtDelegate *newWidgetBase)
+{
+ Q_Q(QWebEnginePage);
+ bindPageAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateWidget *>(newWidgetBase));
+}
+
void QWebEnginePagePrivate::ensureInitialized() const
{
if (!adapter->isInitialized())
adapter->loadDefault();
}
+void QWebEnginePagePrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView *view)
+{
+ auto oldView = page ? page->d_func()->view : nullptr;
+ auto oldPage = view ? view->d_func()->page : nullptr;
+
+ // Change pointers first.
+
+ if (page && oldView != view) {
+ if (oldView)
+ oldView->d_func()->page = nullptr;
+ page->d_func()->view = view;
+ }
+
+ if (view && oldPage != page) {
+ if (oldPage)
+ oldPage->d_func()->view = nullptr;
+ view->d_func()->page = page;
+ }
+
+ // Then notify.
+
+ auto widget = page ? page->d_func()->widget : nullptr;
+ auto oldWidget = oldPage ? oldPage->d_func()->widget : nullptr;
+
+ if (page && oldView != view && oldView) {
+ oldView->d_func()->pageChanged(page, nullptr);
+ if (widget)
+ oldView->d_func()->widgetChanged(widget, nullptr);
+ }
+
+ if (view && oldPage != page) {
+ view->d_func()->pageChanged(oldPage, page);
+ if (oldWidget != widget)
+ view->d_func()->widgetChanged(oldWidget, widget);
+ }
+}
+
+void QWebEnginePagePrivate::bindPageAndWidget(QWebEnginePage *page, RenderWidgetHostViewQtDelegateWidget *widget)
+{
+ auto oldPage = widget ? widget->m_page : nullptr;
+ auto oldWidget = page ? page->d_func()->widget : nullptr;
+
+ // Change pointers first.
+
+ if (widget && oldPage != page) {
+ if (oldPage)
+ oldPage->d_func()->widget = nullptr;
+ widget->m_page = page;
+ }
+
+ if (page && oldWidget != widget) {
+ if (oldWidget)
+ oldWidget->m_page = nullptr;
+ page->d_func()->widget = widget;
+ }
+
+ // Then notify.
+
+ if (widget && oldPage != page && oldPage) {
+ if (auto oldView = oldPage->d_func()->view)
+ oldView->d_func()->widgetChanged(widget, nullptr);
+ }
+
+ if (page && oldWidget != widget) {
+ if (auto view = page->d_func()->view)
+ view->d_func()->widgetChanged(oldWidget, widget);
+ }
+}
+
QWebEnginePage::QWebEnginePage(QObject* parent)
: QObject(parent)
, d_ptr(new QWebEnginePagePrivate())
@@ -895,7 +968,8 @@ QWebEnginePage::~QWebEnginePage()
Q_D(QWebEnginePage);
setDevToolsPage(nullptr);
d->adapter->stopFinding();
- QWebEngineViewPrivate::removePageFromView(this);
+ QWebEnginePagePrivate::bindPageAndView(this, nullptr);
+ QWebEnginePagePrivate::bindPageAndWidget(this, nullptr);
}
QWebEngineHistory *QWebEnginePage::history() const
@@ -1064,9 +1138,9 @@ bool QWebEnginePage::recentlyAudible() const
return d->adapter->isInitialized() && d->adapter->recentlyAudible();
}
-void QWebEnginePage::setView(QWidget *view)
+void QWebEnginePage::setView(QWidget *newViewBase)
{
- QWebEngineViewPrivate::bind(qobject_cast<QWebEngineView*>(view), this);
+ QWebEnginePagePrivate::bindPageAndView(this, qobject_cast<QWebEngineView *>(newViewBase));
}
QWidget *QWebEnginePage::view() const
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index dc8a34af6..eecbf0b65 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -65,6 +65,7 @@
namespace QtWebEngineCore {
class RenderWidgetHostViewQtDelegate;
+class RenderWidgetHostViewQtDelegateWidget;
class WebContentsAdapter;
}
@@ -150,6 +151,7 @@ public:
void printRequested() override;
const QObject *holdingQObject() const override;
ClientType clientType() override { return QtWebEngineCore::WebContentsAdapterClient::WidgetsClient; }
+ void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidget) override;
QtWebEngineCore::ProfileAdapter *profileAdapter() override;
QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override;
@@ -166,6 +168,10 @@ public:
void setFullScreenMode(bool);
void ensureInitialized() const;
+ static void bindPageAndView(QWebEnginePage *page, QWebEngineView *view);
+ static void bindPageAndWidget(QWebEnginePage *page,
+ QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget);
+
QSharedPointer<QtWebEngineCore::WebContentsAdapter> adapter;
QWebEngineHistory *history;
QWebEngineProfile *profile;
@@ -187,6 +193,7 @@ public:
bool defaultAudioMuted;
qreal defaultZoomFactor;
QTimer wasShownTimer;
+ QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget = nullptr;
mutable QtWebEngineCore::CallbackDirectory m_callbacks;
mutable QAction *actions[QWebEnginePage::WebActionCount];
diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp
index e6f9fcb49..576baad17 100644
--- a/src/webenginewidgets/api/qwebengineview.cpp
+++ b/src/webenginewidgets/api/qwebengineview.cpp
@@ -41,6 +41,7 @@
#include "qwebengineview_p.h"
#include "qwebenginepage_p.h"
+#include "render_widget_host_view_qt_delegate_widget.h"
#include "web_contents_adapter.h"
#if QT_CONFIG(action)
@@ -55,89 +56,61 @@
QT_BEGIN_NAMESPACE
-void QWebEngineViewPrivate::notify(QWebEngineView *view, QWebEnginePage *oldPage, QWebEnginePage *newPage)
+void QWebEngineViewPrivate::pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage)
{
- Q_ASSERT(view);
+ Q_Q(QWebEngineView);
+
+ if (oldPage) {
+ oldPage->disconnect(q);
+ }
+
+ if (newPage) {
+ QObject::connect(newPage, &QWebEnginePage::titleChanged, q, &QWebEngineView::titleChanged);
+ QObject::connect(newPage, &QWebEnginePage::urlChanged, q, &QWebEngineView::urlChanged);
+ QObject::connect(newPage, &QWebEnginePage::iconUrlChanged, q, &QWebEngineView::iconUrlChanged);
+ QObject::connect(newPage, &QWebEnginePage::iconChanged, q, &QWebEngineView::iconChanged);
+ QObject::connect(newPage, &QWebEnginePage::loadStarted, q, &QWebEngineView::loadStarted);
+ QObject::connect(newPage, &QWebEnginePage::loadProgress, q, &QWebEngineView::loadProgress);
+ QObject::connect(newPage, &QWebEnginePage::loadFinished, q, &QWebEngineView::loadFinished);
+ QObject::connect(newPage, &QWebEnginePage::selectionChanged, q, &QWebEngineView::selectionChanged);
+ QObject::connect(newPage, &QWebEnginePage::renderProcessTerminated, q, &QWebEngineView::renderProcessTerminated);
+ }
auto oldUrl = oldPage ? oldPage->url() : QUrl();
auto newUrl = newPage ? newPage->url() : QUrl();
if (oldUrl != newUrl)
- Q_EMIT view->urlChanged(newUrl);
+ Q_EMIT q->urlChanged(newUrl);
auto oldTitle = oldPage ? oldPage->title() : QString();
auto newTitle = newPage ? newPage->title() : QString();
if (oldTitle != newTitle)
- Q_EMIT view->titleChanged(newTitle);
+ Q_EMIT q->titleChanged(newTitle);
auto oldIcon = oldPage ? oldPage->iconUrl() : QUrl();
auto newIcon = newPage ? newPage->iconUrl() : QUrl();
if (oldIcon != newIcon) {
- Q_EMIT view->iconUrlChanged(newIcon);
- Q_EMIT view->iconChanged(newPage ? newPage->icon() : QIcon());
+ Q_EMIT q->iconUrlChanged(newIcon);
+ Q_EMIT q->iconChanged(newPage ? newPage->icon() : QIcon());
}
if ((oldPage && oldPage->hasSelection()) || (newPage && newPage->hasSelection()))
- Q_EMIT view->selectionChanged();
-}
-
-QWebEnginePage* QWebEngineViewPrivate::removeViewFromPage(QWebEngineView *view)
-{
- Q_ASSERT(view);
- QWebEnginePage *oldPage = view->d_func()->page;
-
- if (oldPage) {
- oldPage->disconnect(view);
- oldPage->d_func()->view = nullptr;
- if (oldPage->parent() != view)
- oldPage->d_func()->adapter->reattachRWHV();
- }
- return oldPage;
-}
-
-void QWebEngineViewPrivate::removePageFromView(QWebEnginePage *page)
-{
- Q_ASSERT(page);
- if (QWebEngineView *oldView = page->d_func()->view) {
- page->disconnect(oldView);
- page->d_func()->view = nullptr;
- oldView->d_func()->page = nullptr;
- notify(oldView, page, nullptr);
- }
+ Q_EMIT q->selectionChanged();
}
-void QWebEngineViewPrivate::bind(QWebEngineView *view, QWebEnginePage *page)
+void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *oldWidget,
+ QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *newWidget)
{
- if (view && page == view->d_func()->page)
- return;
-
- if (page) {
- // Un-bind page from its current view.
- removePageFromView(page);
- page->d_func()->view = view;
- page->d_func()->adapter->reattachRWHV();
- }
-
- if (view) {
- // Un-bind view from its current page.
- QWebEnginePage *oldPage = removeViewFromPage(view);
-
- view->d_func()->page = page;
- notify(view, oldPage, page);
+ Q_Q(QWebEngineView);
- if (oldPage && oldPage->parent() == view)
- delete oldPage;
+ if (oldWidget) {
+ q->layout()->removeWidget(oldWidget);
+ oldWidget->hide();
}
- if (view && page) {
- QObject::connect(page, &QWebEnginePage::titleChanged, view, &QWebEngineView::titleChanged);
- QObject::connect(page, &QWebEnginePage::urlChanged, view, &QWebEngineView::urlChanged);
- QObject::connect(page, &QWebEnginePage::iconUrlChanged, view, &QWebEngineView::iconUrlChanged);
- QObject::connect(page, &QWebEnginePage::iconChanged, view, &QWebEngineView::iconChanged);
- QObject::connect(page, &QWebEnginePage::loadStarted, view, &QWebEngineView::loadStarted);
- QObject::connect(page, &QWebEnginePage::loadProgress, view, &QWebEngineView::loadProgress);
- QObject::connect(page, &QWebEnginePage::loadFinished, view, &QWebEngineView::loadFinished);
- QObject::connect(page, &QWebEnginePage::selectionChanged, view, &QWebEngineView::selectionChanged);
- QObject::connect(page, &QWebEnginePage::renderProcessTerminated, view, &QWebEngineView::renderProcessTerminated);
+ if (newWidget) {
+ q->layout()->addWidget(newWidget);
+ q->setFocusProxy(newWidget);
+ newWidget->show();
}
}
@@ -193,7 +166,8 @@ QWebEngineView::QWebEngineView(QWidget *parent)
QWebEngineView::~QWebEngineView()
{
- QWebEngineViewPrivate::removeViewFromPage(this);
+ blockSignals(true);
+ QWebEnginePagePrivate::bindPageAndView(nullptr, this);
}
QWebEnginePage* QWebEngineView::page() const
@@ -206,9 +180,9 @@ QWebEnginePage* QWebEngineView::page() const
return d->page;
}
-void QWebEngineView::setPage(QWebEnginePage* page)
+void QWebEngineView::setPage(QWebEnginePage *newPage)
{
- QWebEngineViewPrivate::bind(this, page);
+ QWebEnginePagePrivate::bindPageAndView(newPage, this);
}
void QWebEngineView::load(const QUrl& url)
diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h
index 1845bfb60..28fb883aa 100644
--- a/src/webenginewidgets/api/qwebengineview_p.h
+++ b/src/webenginewidgets/api/qwebengineview_p.h
@@ -55,6 +55,10 @@
#include <QtWidgets/qaccessiblewidget.h>
+namespace QtWebEngineCore {
+class RenderWidgetHostViewQtDelegateWidget;
+}
+
QT_BEGIN_NAMESPACE
class QWebEngineView;
@@ -65,10 +69,9 @@ public:
Q_DECLARE_PUBLIC(QWebEngineView)
QWebEngineView *q_ptr;
- static void notify(QWebEngineView *view, QWebEnginePage *oldPage, QWebEnginePage *newPage);
- static QWebEnginePage* removeViewFromPage(QWebEngineView *view);
- static void removePageFromView(QWebEnginePage *page);
- static void bind(QWebEngineView *view, QWebEnginePage *page);
+ void pageChanged(QWebEnginePage *oldPage, QWebEnginePage *newPage);
+ void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *oldWidget,
+ QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *newWidget);
QWebEngineViewPrivate();
diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
index 13c65f1ec..7bbd85091 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -165,15 +165,28 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_AlwaysShowToolTips);
- if (parent) {
- // Unset the popup parent if the parent is being destroyed, thus making sure a double
- // delete does not happen.
- // Also in case the delegate is destroyed before its parent (when a popup is simply
- // dismissed), this connection will automatically be removed by ~QObject(), preventing
- // a use-after-free.
+ setContent(QUrl(), nullptr, m_rootItem.data());
+
+ connectRemoveParentBeforeParentDelete();
+}
+
+RenderWidgetHostViewQtDelegateWidget::~RenderWidgetHostViewQtDelegateWidget()
+{
+ QWebEnginePagePrivate::bindPageAndWidget(nullptr, this);
+}
+
+void RenderWidgetHostViewQtDelegateWidget::connectRemoveParentBeforeParentDelete()
+{
+ if (QWidget *parent = parentWidget())
connect(parent, &QObject::destroyed,
this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete);
- }
+}
+
+void RenderWidgetHostViewQtDelegateWidget::disconnectRemoveParentBeforeParentDelete()
+{
+ if (QWidget *parent = parentWidget())
+ disconnect(parent, &QObject::destroyed,
+ this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete);
}
void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete()
@@ -188,29 +201,9 @@ void RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete()
close();
}
-void RenderWidgetHostViewQtDelegateWidget::initAsChild(WebContentsAdapterClient* container)
-{
- setContent(QUrl(), nullptr, m_rootItem.data());
-
- QWebEnginePagePrivate *pagePrivate = static_cast<QWebEnginePagePrivate *>(container);
- if (pagePrivate->view) {
- if (parentWidget())
- disconnect(parentWidget(), &QObject::destroyed,
- this, &RenderWidgetHostViewQtDelegateWidget::removeParentBeforeParentDelete);
- pagePrivate->view->layout()->addWidget(this);
- if (QWidget *focusProxy = pagePrivate->view->focusProxy())
- if (focusProxy != this)
- pagePrivate->view->layout()->removeWidget(focusProxy);
- pagePrivate->view->setFocusProxy(this);
- show();
- } else
- setParent(0);
-}
-
void RenderWidgetHostViewQtDelegateWidget::initAsPopup(const QRect& screenRect)
{
m_isPopup = true;
- setContent(QUrl(), nullptr, m_rootItem.data());
// The keyboard events are supposed to go to the parent RenderHostView
// so the WebUI popups should never have focus. Besides, if the parent view
@@ -422,6 +415,18 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event)
{
bool handled = false;
+ // Track parent to make sure we don't get deleted.
+ switch (event->type()) {
+ case QEvent::ParentAboutToChange:
+ disconnectRemoveParentBeforeParentDelete();
+ break;
+ case QEvent::ParentChange:
+ connectRemoveParentBeforeParentDelete();
+ break;
+ default:
+ break;
+ }
+
// Mimic QWidget::event() by ignoring mouse, keyboard, touch and tablet events if the widget is
// disabled.
if (!isEnabled()) {
diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
index 4dc47dfdd..74c9e3413 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
@@ -46,6 +46,11 @@
#include <QQuickItem>
#include <QQuickWidget>
+QT_BEGIN_NAMESPACE
+class QWebEnginePage;
+class QWebEnginePagePrivate;
+QT_END_NAMESPACE
+
namespace QtWebEngineCore {
// Useful information keyboard and mouse QEvent propagation.
@@ -58,8 +63,8 @@ class RenderWidgetHostViewQtDelegateWidget : public QQuickWidget, public RenderW
Q_OBJECT
public:
RenderWidgetHostViewQtDelegateWidget(RenderWidgetHostViewQtDelegateClient *client, QWidget *parent = 0);
+ ~RenderWidgetHostViewQtDelegateWidget();
- void initAsChild(WebContentsAdapterClient* container) override;
void initAsPopup(const QRect&) override;
QRectF screenRect() const override;
QRectF contentsRect() const override;
@@ -95,9 +100,13 @@ protected:
private slots:
void onWindowPosChanged();
+ void connectRemoveParentBeforeParentDelete();
+ void disconnectRemoveParentBeforeParentDelete();
void removeParentBeforeParentDelete();
private:
+ friend QWebEnginePagePrivate;
+
RenderWidgetHostViewQtDelegateClient *m_client;
QScopedPointer<QQuickItem> m_rootItem;
bool m_isPopup;
@@ -105,6 +114,7 @@ private:
QColor m_clearColor;
QPoint m_lastGlobalPos;
QList<QMetaObject::Connection> m_windowConnections;
+ QWebEnginePage *m_page = nullptr;
};
} // namespace QtWebEngineCore