summaryrefslogtreecommitdiffstats
path: root/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
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 /src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
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>
Diffstat (limited to 'src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp')
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp59
1 files changed, 32 insertions, 27 deletions
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()) {