summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJüri Valdmann <juri.valdmann@qt.io>2018-09-20 10:26:37 +0200
committerJüri Valdmann <juri.valdmann@qt.io>2018-10-29 09:43:04 +0000
commit36d230c44c7e2f6fccf224b4a0ab5efe77117e0a (patch)
tree1a782829d2838908a461799bf4b8fd651dad6958
parent2a6193b00e1d756e9a7a6032640b413c184ae4f0 (diff)
Stop showing speculative frames
Chromium creates "speculative" frames (RenderFrameHost and company) for pending cross-process navigations (and maybe other navigations too). For example, a redirect from http://qt.io to https://qt.io will trigger this, as described in the bug report. These speculative frames are loading in the background and only shown once they are officially ready (as decided by the RenderFrameHostManager and signaled to WebContentsObserver::RenderViewHostChanged). At least, this is how it's supposed to work and how it works in Chrome. In WebEngine, however, we actually show these speculative frames as soon as they are created and before they are ready. This runs into the problem that the if the speculative frame is dropped (instead of committed), then Chromium will not ask us to re-show the old frame (since it hasn't actually asked to us to show the new frame, it naturally assumes we are still showing the old one). Fixes: QTBUG-68727 Change-Id: I9d53035ce60e3a002d5412d4473d940a32644b5d Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--src/core/render_widget_host_view_qt.cpp13
-rw-r--r--src/core/render_widget_host_view_qt.h2
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h1
-rw-r--r--src/core/web_contents_adapter.cpp9
-rw-r--r--src/core/web_contents_adapter.h2
-rw-r--r--src/core/web_contents_adapter_client.h1
-rw-r--r--src/core/web_contents_delegate_qt.cpp8
-rw-r--r--src/core/web_contents_delegate_qt.h1
-rw-r--r--src/core/web_contents_view_qt.cpp2
-rw-r--r--src/webengine/api/qquickwebengineview.cpp60
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h9
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.cpp16
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.h11
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp7
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.h1
-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
21 files changed, 263 insertions, 155 deletions
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 6c5b2ac20..0bb28bd37 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -265,7 +265,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget
, m_adapterClient(0)
, m_imeInProgress(false)
, m_receivedEmptyImeEvent(false)
- , m_initPending(false)
, m_imState(0)
, m_anchorPositionWithinSelection(-1)
, m_cursorPositionWithinSelection(-1)
@@ -319,18 +318,10 @@ void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterC
m_adapterClientDestroyedConnection = QObject::connect(adapterClient->holdingQObject(),
&QObject::destroyed, [this] {
m_adapterClient = nullptr; });
- if (m_initPending)
- InitAsChild(0);
}
void RenderWidgetHostViewQt::InitAsChild(gfx::NativeView)
{
- if (!m_adapterClient) {
- m_initPending = true;
- return;
- }
- m_initPending = false;
- m_delegate->initAsChild(m_adapterClient);
}
void RenderWidgetHostViewQt::InitAsPopup(content::RenderWidgetHostView*, const gfx::Rect& rect)
@@ -926,13 +917,13 @@ void RenderWidgetHostViewQt::notifyHidden()
void RenderWidgetHostViewQt::windowBoundsChanged()
{
host()->SendScreenRects();
- if (m_delegate->window())
+ if (m_delegate && m_delegate->window())
host()->NotifyScreenInfoChanged();
}
void RenderWidgetHostViewQt::windowChanged()
{
- if (m_delegate->window())
+ if (m_delegate && m_delegate->window())
host()->NotifyScreenInfoChanged();
}
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index ad7fc9f13..6a1134ac0 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -246,8 +246,6 @@ private:
bool m_receivedEmptyImeEvent;
QPoint m_previousMousePosition;
- bool m_initPending;
-
gfx::Vector2dF m_lastScrollOffset;
gfx::SizeF m_lastContentsSize;
viz::LocalSurfaceId m_localSurfaceId;
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index 8936ce63e..991c26ea8 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -91,7 +91,6 @@ public:
class QWEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate {
public:
virtual ~RenderWidgetHostViewQtDelegate() { }
- virtual void initAsChild(WebContentsAdapterClient*) = 0;
virtual void initAsPopup(const QRect&) = 0;
virtual QRectF screenRect() const = 0;
virtual QRectF contentsRect() const = 0;
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 5b9e61268..21540f5da 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -516,14 +516,9 @@ void WebContentsAdapter::initialize(content::SiteInstance *site)
if (!rvh->IsRenderViewLive())
static_cast<content::WebContentsImpl*>(m_webContents.get())->CreateRenderViewForRenderManager(rvh, MSG_ROUTING_NONE, MSG_ROUTING_NONE, base::UnguessableToken::Create(), content::FrameReplicationState());
- m_adapterClient->initializationFinished();
-}
+ m_webContentsDelegate->RenderViewHostChanged(nullptr, rvh);
-void WebContentsAdapter::reattachRWHV()
-{
- CHECK_INITIALIZED();
- if (content::RenderWidgetHostView *rwhv = m_webContents->GetRenderWidgetHostView())
- rwhv->InitAsChild(0);
+ m_adapterClient->initializationFinished();
}
bool WebContentsAdapter::canGoBack() const
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 8e02a852b..e8e5359be 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -109,8 +109,6 @@ public:
void load(const QWebEngineHttpRequest &request);
void setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl);
- void reattachRWHV();
-
bool canGoBack() const;
bool canGoForward() const;
void stop();
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 514d3afb4..55cbe13dd 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -474,6 +474,7 @@ public:
virtual void setToolTip(const QString& toolTipText) = 0;
virtual ClientType clientType() = 0;
virtual void printRequested() = 0;
+ virtual void widgetChanged(RenderWidgetHostViewQtDelegate *newWidget) = 0;
virtual ProfileAdapter *profileAdapter() = 0;
virtual WebContentsAdapter* webContentsAdapter() = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 9472c0be9..4bde93fd3 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -258,6 +258,14 @@ void WebContentsDelegateQt::RenderFrameDeleted(content::RenderFrameHost *render_
m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID());
}
+void WebContentsDelegateQt::RenderViewHostChanged(content::RenderViewHost *, content::RenderViewHost *newHost)
+{
+ if (newHost && newHost->GetWidget() && newHost->GetWidget()->GetView()) {
+ auto rwhv = static_cast<RenderWidgetHostViewQt *>(newHost->GetWidget()->GetView());
+ m_viewClient->widgetChanged(rwhv->delegate());
+ }
+}
+
void WebContentsDelegateQt::EmitLoadStarted(const QUrl &url, bool isErrorPage)
{
if (m_lastLoadProgress >= 0 && m_lastLoadProgress < 100) // already running
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 966494ec7..9c0f8f484 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -130,6 +130,7 @@ public:
// WebContentsObserver overrides
void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override;
+ void RenderViewHostChanged(content::RenderViewHost *old_host, content::RenderViewHost *new_host) override;
void DidStartNavigation(content::NavigationHandle *navigation_handle) override;
void DidFinishNavigation(content::NavigationHandle *navigation_handle) override;
void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) override;
diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp
index 7910688d3..3c4465ae3 100644
--- a/src/core/web_contents_view_qt.cpp
+++ b/src/core/web_contents_view_qt.cpp
@@ -78,8 +78,6 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(conten
view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view));
if (m_client)
view->setAdapterClient(m_client);
- // Tell the RWHV delegate to attach itself to the native view container.
- view->InitAsChild(0);
return view;
}
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index a3a12819b..39901e693 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -669,6 +669,12 @@ void QQuickWebEngineViewPrivate::printRequested()
});
}
+void QQuickWebEngineViewPrivate::widgetChanged(RenderWidgetHostViewQtDelegate *newWidgetBase)
+{
+ Q_Q(QQuickWebEngineView);
+ bindViewAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateQuick *>(newWidgetBase));
+}
+
WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const
{
return m_settings->d_ptr.data();
@@ -846,6 +852,52 @@ void QQuickWebEngineViewPrivate::setFullScreenMode(bool fullscreen)
}
}
+void QQuickWebEngineViewPrivate::bindViewAndWidget(QQuickWebEngineView *view,
+ RenderWidgetHostViewQtDelegateQuick *widget)
+{
+ auto oldWidget = view ? view->d_func()->widget : nullptr;
+ auto oldView = widget ? widget->m_view : nullptr;
+
+ // Change pointers first.
+
+ if (widget && oldView != view) {
+ if (oldView)
+ oldView->d_func()->widget = nullptr;
+ widget->m_view = view;
+ }
+
+ if (view && oldWidget != widget) {
+ if (oldWidget)
+ oldWidget->m_view = nullptr;
+ view->d_func()->widget = widget;
+ }
+
+ // Then notify.
+
+ if (widget && oldView != view && oldView)
+ oldView->d_func()->widgetChanged(widget, nullptr);
+
+ if (view && oldWidget != widget)
+ view->d_func()->widgetChanged(oldWidget, widget);
+}
+
+void QQuickWebEngineViewPrivate::widgetChanged(RenderWidgetHostViewQtDelegateQuick *oldWidget,
+ RenderWidgetHostViewQtDelegateQuick *newWidget)
+{
+ Q_Q(QQuickWebEngineView);
+
+ if (oldWidget)
+ oldWidget->setParentItem(nullptr);
+
+ if (newWidget) {
+ newWidget->setParentItem(q);
+ newWidget->setSize(q->boundingRect().size());
+ // Focus on creation if the view accepts it
+ if (q->activeFocusOnPress())
+ newWidget->setFocus(true);
+ }
+}
+
void QQuickWebEngineViewPrivate::updateAction(QQuickWebEngineView::WebAction action) const
{
QQuickWebEngineAction *a = actions[action];
@@ -1494,11 +1546,9 @@ void QQuickWebEngineView::fullScreenCancelled()
void QQuickWebEngineView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
QQuickItem::geometryChanged(newGeometry, oldGeometry);
- const QList<QQuickItem *> children = childItems();
- for (QQuickItem *child : children) {
- if (qobject_cast<RenderWidgetHostViewQtDelegateQuick *>(child))
- child->setSize(newGeometry.size());
- }
+ Q_D(QQuickWebEngineView);
+ if (d->widget)
+ d->widget->setSize(newGeometry.size());
}
void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &value)
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index d20bfca46..cbba9b568 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -63,8 +63,9 @@
#include <QtGui/qaccessibleobject.h>
namespace QtWebEngineCore {
-class WebContentsAdapter;
+class RenderWidgetHostViewQtDelegateQuick;
class UIDelegatesManager;
+class WebContentsAdapter;
}
QT_BEGIN_NAMESPACE
@@ -157,6 +158,7 @@ public:
QtWebEngineCore::ProfileAdapter *profileAdapter() override;
QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override;
void printRequested() override;
+ void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidgetBase) override;
void updateAction(QQuickWebEngineView::WebAction) const;
void adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents);
@@ -165,6 +167,10 @@ public:
void ensureContentsAdapter();
void setFullScreenMode(bool);
+ static void bindViewAndWidget(QQuickWebEngineView *view, QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *widget);
+ void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *oldWidget,
+ QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *newWidget);
+
// QQmlListPropertyHelpers
static void userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script);
static int userScripts_count(QQmlListProperty<QQuickWebEngineScript> *p);
@@ -198,6 +204,7 @@ public:
uint m_webChannelWorld;
bool m_isBeingAdopted;
mutable QQuickWebEngineAction *actions[QQuickWebEngineView::WebActionCount];
+ QtWebEngineCore::RenderWidgetHostViewQtDelegateQuick *widget = nullptr;
bool profileInitialized() const;
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
index baece82f3..d23e64774 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -55,7 +55,6 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW
: m_client(client)
, m_isPopup(isPopup)
, m_isPasswordInput(false)
- , m_initialized(false)
{
setFlag(ItemHasContents);
setAcceptedMouseButtons(Qt::AllButtons);
@@ -85,16 +84,9 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW
}
-void RenderWidgetHostViewQtDelegateQuick::initAsChild(WebContentsAdapterClient* container)
+RenderWidgetHostViewQtDelegateQuick::~RenderWidgetHostViewQtDelegateQuick()
{
- QQuickWebEngineView *view = static_cast<QQuickWebEngineViewPrivate *>(container)->q_func();
- setParentItem(view);
- setSize(view->boundingRect().size());
- // Focus on creation if the view accepts it
- if (view->activeFocusOnPress())
- setFocus(true);
- m_initialized = true;
-
+ QQuickWebEngineViewPrivate::bindViewAndWidget(nullptr, this);
}
void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r)
@@ -106,7 +98,6 @@ void RenderWidgetHostViewQtDelegateQuick::initAsPopup(const QRect &r)
setWidth(rect.width());
setHeight(rect.height());
setVisible(true);
- m_initialized = true;
}
QRectF RenderWidgetHostViewQtDelegateQuick::screenRect() const
@@ -361,8 +352,7 @@ void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const It
m_windowConnections.append(connect(value.window, SIGNAL(closing(QQuickCloseEvent *)), SLOT(onHide())));
}
- if (m_initialized)
- m_client->windowChanged();
+ m_client->windowChanged();
} else if (change == QQuickItem::ItemVisibleHasChanged) {
if (!m_isPopup && !value.boolValue)
onHide();
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h
index 74cddf476..6b855c824 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h
@@ -44,6 +44,11 @@
#include <QQuickItem>
+QT_BEGIN_NAMESPACE
+class QQuickWebEngineView;
+class QQuickWebEngineViewPrivate;
+QT_END_NAMESPACE
+
namespace QtWebEngineCore {
class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, public RenderWidgetHostViewQtDelegate
@@ -51,8 +56,8 @@ class RenderWidgetHostViewQtDelegateQuick : public QQuickItem, public RenderWidg
Q_OBJECT
public:
RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup);
+ ~RenderWidgetHostViewQtDelegateQuick();
- void initAsChild(WebContentsAdapterClient* container) override;
void initAsPopup(const QRect&) override;
QRectF screenRect() const override;
QRectF contentsRect() const override;
@@ -102,12 +107,14 @@ private slots:
void onHide();
private:
+ friend QQuickWebEngineViewPrivate;
+
RenderWidgetHostViewQtDelegateClient *m_client;
QList<QMetaObject::Connection> m_windowConnections;
bool m_isPopup;
bool m_isPasswordInput;
- bool m_initialized;
QPoint m_lastGlobalPos;
+ QQuickWebEngineView *m_view = nullptr;
};
} // namespace QtWebEngineCore
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
index dd37ff6fa..d3c88148e 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -54,13 +54,6 @@ RenderWidgetHostViewQtDelegateQuickWindow::~RenderWidgetHostViewQtDelegateQuickW
{
}
-void RenderWidgetHostViewQtDelegateQuickWindow::initAsChild(WebContentsAdapterClient *container)
-{
- Q_UNUSED(container);
- // We should only use this wrapper class for webUI popups.
- Q_UNREACHABLE();
-}
-
void RenderWidgetHostViewQtDelegateQuickWindow::initAsPopup(const QRect &screenRect)
{
m_realDelegate->initAsPopup(QRect(QPoint(0, 0), screenRect.size()));
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
index 6a1be8b7f..df241bf3a 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
@@ -55,7 +55,6 @@ public:
RenderWidgetHostViewQtDelegateQuickWindow(RenderWidgetHostViewQtDelegate *realDelegate);
~RenderWidgetHostViewQtDelegateQuickWindow();
- void initAsChild(WebContentsAdapterClient* container) override;
void initAsPopup(const QRect&) override;
QRectF screenRect() const override;
QRectF contentsRect() const override;
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