diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 6c5b2ac20f5035877bb1c7e68ce3338182a98037..0bb28bd376b95bda9865703e79d20df6eeb4b47d 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 ad7fc9f136f2be2dccabb8c4fc0adee3d7fe6047..6a1134ac0a2fb52923d9dd806aaf60cb0425bb46 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 8936ce63e11e8d5b6a2f4685e0fbaa93152cdd85..991c26ea8e00f4024552439bd4260549d2edee0b 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 5b9e612682e3da4b1285a3df971c1beb1604e32d..21540f5da7e3527f49d480aa0e6d136b7e5c1052 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 8e02a852bf6713d49a1462384405a8f42f8a356b..e8e5359beb764c5a8558253466f110374d7a9543 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 514d3afb4c90363f2c5729de31cbf9e5ecb50c83..55cbe13ddbf931a6023656a766f720dc49df3238 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 9472c0be93b95883acd94b9ca3358fd169b1f796..4bde93fd302e2ee0dc7770de6afbffc2c3483429 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 966494ec739d969e0d904e2e4abb81b91dff017e..9c0f8f484521d16a887bdf70db794a4a8eff8f47 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 7910688d3158d8ff4983177dd86804ba24de6cc8..3c4465ae3d5c39998f56d91ad2a0283223f6dadf 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 a3a12819b5cc6090b8f5f5a483ea9f24e08be69d..39901e6938863043f485de692ac8121d45090021 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 d20bfca46616c5e72aac50b0c27e741a5cf3cd43..cbba9b5682550d74d2709e45729a30ba2b03e3a8 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 baece82f3535f7a4c9469af1bc62e63f4da99942..d23e647746a2a09e7fe918c4bb56dd0a180f2ec9 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 74cddf4768c4ed6d59d0daee47dc79f73d4c1c14..6b855c824082987a1597e12c9b131a1b80c48509 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 dd37ff6faff19b67c74072b9d8c2bc575b0a70ad..d3c88148eab9c016f6050e9a97c17d4866f8b9c2 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 6a1be8b7f7d9c81802ea31c48f53869d5042303d..df241bf3a028b28b1b8e0cbc4b5e2b87c5bceafb 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 3a2a075206921b9a89f8c3c438b4c7d7e1d0df08..a6267c2231284bce59371267eff2707cd8425f34 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 dc8a34af6c4b4db07f380de434e2175e2482ed26..eecbf0b656924e8860362b930c35126546de8ee5 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 e6f9fcb49c7f7986ecccd02efec1e9ca7628ccf7..576baad17de4d66cbcd974edb2ef5197b1bff339 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 1845bfb603d3e35977fc8b687a4e6242db977c23..28fb883aa3608a7c6bd94600e9bfb89b8024cbde 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 13c65f1ec168d388886c91171c5d2aeb28018a52..7bbd8509133ed2cb46140a74f0ca39ae92b28acb 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 4dc47dfddd7fcd3c8b48556d946c63c6261063a1..74c9e3413fceba62732f4dcc1ac122c34d693e16 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