summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-04-30 12:03:36 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-04-30 12:03:36 +0200
commit3a35e38c4f0110349ff3413efa3cbaaef5d8826d (patch)
tree10a70344f50fba28932d4a91b08f9b5b48fc4b79
parent685430b66ab2830d5e0e5ebafc17294ff1ce1f48 (diff)
parent950e462b1d369f8140a1d54078d42b5f057adfdb (diff)
downloadqtwebengine-3a35e38c4f0110349ff3413efa3cbaaef5d8826d.tar.gz
Merge remote-tracking branch 'origin/5.15.0' into 5.15
Change-Id: I916838caf8c981d5dac876631a6e510ed2ffbe0e
-rw-r--r--dist/changes-5.15.091
m---------src/3rdparty0
-rw-r--r--src/buildtools/configure.json12
-rw-r--r--src/core/render_widget_host_view_qt.cpp16
-rw-r--r--src/core/render_widget_host_view_qt.h1
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h4
-rw-r--r--src/core/web_contents_adapter_client.h5
-rw-r--r--src/core/web_contents_delegate_qt.cpp22
-rw-r--r--src/core/web_contents_delegate_qt.h6
-rw-r--r--src/core/web_event_factory.cpp70
-rw-r--r--src/core/web_event_factory.h6
-rw-r--r--src/webengine/api/qquickwebengineview.cpp9
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h5
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp29
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h8
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp7
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h1
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp158
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp10
-rw-r--r--tools/scripts/version_resolver.py2
20 files changed, 409 insertions, 53 deletions
diff --git a/dist/changes-5.15.0 b/dist/changes-5.15.0
new file mode 100644
index 000000000..a5e3da7a1
--- /dev/null
+++ b/dist/changes-5.15.0
@@ -0,0 +1,91 @@
+Qt 5.15 introduces many new features and improvements as well as bugfixes
+over the 5.14.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.15 series is binary compatible with the 5.14.x series.
+Applications compiled for 5.14 will continue to run with 5.15.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+
+****************************************************************************
+* General *
+****************************************************************************
+
+Behavior Changes
+----------------
+
+ - XSS Auditing has been removed, and the XSSAuditingEnabled setting no
+ longer has any effect.
+ - [QTBUG-79864] The viz display compositor is now used by default on all
+ platforms, but can be disabled with --disable-viz-display-compositor.
+ - The network layer integration has been rewritten to use Chromium's network
+ service, and now runs in a separate sandboxed process by default.
+ - [QTBUG-83656] CTRL+mouse wheel page zoom fixed, and now works by default.
+
+
+Chromium Snapshot
+-----------------
+
+ - Updated the Chromium version to 80.0.3987.163
+ - Applied security fixes from Chrome up to version 81.0.4044.129
+
+
+General
+-------
+
+ - Fixed hardware accelerated video decoding on Windows and macOS.
+ - Updated where to look for Google Chrome's CDM plugin.
+ - [QTBUG-82390] Disabled picture-in-picture to avoid non-functional button
+ showing up.
+ - Command-line specified PAC files can now be loaded from QRC.
+ - [QTBUG-82012] Placeholder for missing PPAPI plugins added.
+
+
+Libraries
+---------
+
+ - Added a renderProcessPid() getter to QWebEnginePage and WebEngineView
+ which allows reading the process ID of the underlying render process.
+ - [QTBUG-83338] Avoid decoding HTML in default JavaScript message handlers.
+
+
+****************************************************************************
+* Qt PDF *
+****************************************************************************
+
+General
+-------
+
+ - The qt-labs/qtpdf module was using an out-of-date version of pdfium.
+ Development will now continue in the qtwebengine repository in order to
+ reuse Qt WebEngine's pdfium build system integration.
+ - QtPdf is still in Tech Preview.
+ - It's now possible to build QtPDF for iOS (even though Qt WebEngine does not).
+ - Added a Qt Quick API (import QtQuick.Pdf):
+ * Added an image plugin: Image { source: "my.pdf"; currentFrame: 2 } is
+ enough to view the third page in a PDF file.
+ * High-level API for full-featured viewers: PdfScrollablePageView shows
+ one page at a time; PdfMultiPageView allows flicking vertically from
+ page to page. These are implemented in QML and packaged with the module.
+ - Low-level QtQuick API:
+ * PdfDocument provides API for the document and its metadata.
+ * PdfSearchModel can find a text string and provides information about
+ the locations where it is found on each page, which can be listed in
+ a ListView and visualized by using a Repeater to instantiate
+ QtQuick.Shapes for the bounding boxes.
+ * PdfSelection allows selecting text and copying to the clipboard;
+ visualization of the selected region is done via QtQuick.Shapes.
+ * PdfLinkModel provides information about the links in the document;
+ visual feedback and clicking can be handled with QtQuick.Shapes
+ and TapHandler, respectively.
+ * PdfNavigationStack is a model for implementing forward/back navigation.
+
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 757b9f459d3770644ad83d2faf26a7539c65023
+Subproject 6f260e5b2f717b9977045419f12c7c35d31f9a9
diff --git a/src/buildtools/configure.json b/src/buildtools/configure.json
index 1298ab916..a80ef32eb 100644
--- a/src/buildtools/configure.json
+++ b/src/buildtools/configure.json
@@ -34,8 +34,9 @@
},
"webengine-xkbcommon": {
"label": "xkbcommon",
+ "headers": "xkbcommon/xkbcommon.h",
"sources": [
- { "type": "pkgConfig", "args": "xkbcommon" }
+ "-lxkbcommon"
]
},
"webengine-xcomposite": {
@@ -296,13 +297,6 @@
]
}
},
- "webengine-xkbcommon": {
- "label": "system xkbcommon",
- "type": "compile",
- "test": {
- "include": "xkbcommon/xkbcommon.h"
- }
- },
"webengine-ninja": {
"label": "system ninja",
"type": "detectNinja"
@@ -455,7 +449,7 @@
},
"webengine-system-xkbcommon": {
"label": "xkbcommon",
- "condition": "libs.webengine-xkbcommon && tests.webengine-xkbcommon",
+ "condition": "libs.webengine-xkbcommon",
"output": [ "privateFeature" ]
},
"webengine-system-xcomposite": {
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index c99c560a3..0af26314a 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -1530,7 +1530,21 @@ void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &even
m_mouseWheelPhaseHandler.AddPhaseIfNeededAndScheduleEndEvent(webEvent, false);
host()->ForwardWheelEvent(webEvent);
}
- // TODO: We could forward unhandled wheelevents to our parent.
+}
+
+void RenderWidgetHostViewQt::GestureEventAck(const blink::WebGestureEvent &event, content::InputEventAckState ack_result)
+{
+ // Forward unhandled scroll events back as wheel events
+ if (event.GetType() != blink::WebInputEvent::kGestureScrollUpdate)
+ return;
+ switch (ack_result) {
+ case content::INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
+ case content::INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
+ WebEventFactory::sendUnhandledWheelEvent(event, delegate());
+ break;
+ default:
+ break;
+ }
}
content::MouseWheelPhaseHandler *RenderWidgetHostViewQt::GetMouseWheelPhaseHandler()
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index 41ce50b34..a07d21468 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -155,6 +155,7 @@ public:
void DidCreateNewRendererCompositorFrameSink(viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) override;
void SubmitCompositorFrame(const viz::LocalSurfaceId&, viz::CompositorFrame, base::Optional<viz::HitTestRegionList>) override;
void WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState ack_result) override;
+ void GestureEventAck(const blink::WebGestureEvent &event, content::InputEventAckState ack_result) override;
content::MouseWheelPhaseHandler *GetMouseWheelPhaseHandler() override;
viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(const cc::RenderFrameMetadata &metadata) override;
void OnDidUpdateVisualPropertiesComplete(const cc::RenderFrameMetadata &metadata);
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index 4ee790ce9..46f1802a6 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -58,12 +58,13 @@
QT_BEGIN_NAMESPACE
class QEvent;
+class QInputMethodEvent;
class QSGLayer;
class QSGNode;
class QSGRectangleNode;
class QSGTexture;
class QVariant;
-class QInputMethodEvent;
+class QWheelEvent;
class QSGImageNode;
@@ -111,6 +112,7 @@ public:
virtual void setInputMethodHints(Qt::InputMethodHints hints) = 0;
virtual void setClearColor(const QColor &color) = 0;
virtual bool copySurface(const QRect &, const QSize &, QImage &) = 0;
+ virtual void unhandledWheelEvent(QWheelEvent *) {}
};
} // namespace QtWebEngineCore
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 250801f51..04df99f0e 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -469,7 +469,10 @@ public:
virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) = 0;
virtual void focusContainer() = 0;
virtual void unhandledKeyEvent(QKeyEvent *event) = 0;
- virtual void adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry, const QUrl &targetUrl) = 0;
+ virtual QSharedPointer<WebContentsAdapter>
+ adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents,
+ WindowOpenDisposition disposition, bool userGesture,
+ const QRect &initialGeometry, const QUrl &targetUrl) = 0;
virtual bool isBeingAdopted() = 0;
virtual void close() = 0;
virtual void windowCloseRejected() = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index fada874a3..216e4faf1 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -663,14 +663,17 @@ void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *webCont
m_viewClient->webEngineSettings()->overrideWebPreferences(webContents, webPreferences);
}
-QWeakPointer<WebContentsAdapter> WebContentsDelegateQt::createWindow(std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture)
+QSharedPointer<WebContentsAdapter>
+WebContentsDelegateQt::createWindow(std::unique_ptr<content::WebContents> new_contents,
+ WindowOpenDisposition disposition, const gfx::Rect &initial_pos,
+ bool user_gesture)
{
QSharedPointer<WebContentsAdapter> newAdapter = QSharedPointer<WebContentsAdapter>::create(std::move(new_contents));
- m_viewClient->adoptNewWindow(newAdapter, static_cast<WebContentsAdapterClient::WindowOpenDisposition>(disposition), user_gesture, toQt(initial_pos), m_initialTargetUrl);
-
- // If the client didn't reference the adapter, it will be deleted now, and the weak pointer zeroed.
- return newAdapter;
+ return m_viewClient->adoptNewWindow(
+ std::move(newAdapter),
+ static_cast<WebContentsAdapterClient::WindowOpenDisposition>(disposition), user_gesture,
+ toQt(initial_pos), m_initialTargetUrl);
}
void WebContentsDelegateQt::allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController)
@@ -797,6 +800,15 @@ bool WebContentsDelegateQt::TakeFocus(content::WebContents *source, bool reverse
return m_viewClient->passOnFocus(reverse);
}
+void WebContentsDelegateQt::ContentsZoomChange(bool zoom_in)
+{
+ WebContentsAdapter *adapter = webContentsAdapter();
+ if (zoom_in)
+ adapter->setZoomFactor(adapter->currentZoomFactor() + 0.1f);
+ else
+ adapter->setZoomFactor(adapter->currentZoomFactor() - 0.1f);
+}
+
FaviconManager *WebContentsDelegateQt::faviconManager()
{
return m_faviconManager.data();
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index f32b02caf..bfef9a1df 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -148,6 +148,7 @@ public:
void RegisterProtocolHandler(content::WebContents* web_contents, const std::string& protocol, const GURL& url, bool user_gesture) override;
void UnregisterProtocolHandler(content::WebContents* web_contents, const std::string& protocol, const GURL& url, bool user_gesture) override;
bool TakeFocus(content::WebContents *source, bool reverse) override;
+ void ContentsZoomChange(bool zoom_in) override;
// WebContentsObserver overrides
void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override;
@@ -200,7 +201,10 @@ public:
base::WeakPtr<WebContentsDelegateQt> AsWeakPtr() { return m_weakPtrFactory.GetWeakPtr(); }
private:
- QWeakPointer<WebContentsAdapter> createWindow(std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture);
+ QSharedPointer<WebContentsAdapter>
+ createWindow(std::unique_ptr<content::WebContents> new_contents,
+ WindowOpenDisposition disposition, const gfx::Rect &initial_pos,
+ bool user_gesture);
void EmitLoadStarted(const QUrl &url, bool isErrorPage = false);
void EmitLoadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString());
void EmitLoadCommitted();
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index f37cce6c7..9824b3f37 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -71,6 +71,8 @@
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "render_widget_host_view_qt_delegate.h"
+
#include <QtGui/private/qtgui-config_p.h>
#include <QCoreApplication>
@@ -84,6 +86,8 @@
#endif
#include <QWheelEvent>
+namespace QtWebEngineCore {
+
using namespace blink;
enum class KeyboardDriver { Unknown, Windows, Cocoa, Xkb, Evdev };
@@ -1306,6 +1310,42 @@ static inline WebInputEvent::Modifiers modifiersForEvent(const QInputEvent* even
return (WebInputEvent::Modifiers)result;
}
+static inline Qt::KeyboardModifiers keyboardModifiersForModifier(unsigned int modifier)
+{
+ Qt::KeyboardModifiers modifiers = {};
+ if (modifier & WebInputEvent::kControlKey)
+ modifiers |= Qt::ControlModifier;
+ if (modifier & WebInputEvent::kMetaKey)
+ modifiers |= Qt::MetaModifier;
+ if (modifier & WebInputEvent::kShiftKey)
+ modifiers |= Qt::ShiftModifier;
+ if (modifier & WebInputEvent::kAltKey)
+ modifiers |= Qt::AltModifier;
+ if (modifier & WebInputEvent::kIsKeyPad)
+ modifiers |= Qt::KeypadModifier;
+
+ if (keyboardDriver() == KeyboardDriver::Cocoa && !qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
+ bool controlModifier = modifiers.testFlag(Qt::ControlModifier);
+ bool metaModifier = modifiers.testFlag(Qt::MetaModifier);
+ modifiers.setFlag(Qt::ControlModifier, metaModifier);
+ modifiers.setFlag(Qt::MetaModifier, controlModifier);
+ }
+
+ return modifiers;
+}
+
+static inline Qt::MouseButtons mouseButtonsForModifier(unsigned int modifier)
+{
+ Qt::MouseButtons buttons = {};
+ if (modifier & WebInputEvent::kLeftButtonDown)
+ buttons |= Qt::LeftButton;
+ if (modifier & WebInputEvent::kRightButtonDown)
+ buttons |= Qt::RightButton;
+ if (modifier & WebInputEvent::kMiddleButtonDown)
+ buttons |= Qt::MiddleButton;
+ return buttons;
+}
+
static WebInputEvent::Type webEventTypeForEvent(const QEvent* event)
{
switch (event->type()) {
@@ -1471,6 +1511,14 @@ static void setBlinkWheelEventDelta(blink::WebMouseWheelEvent &webEvent)
webEvent.delta_y = webEvent.wheel_ticks_y * wheelScrollLines * cDefaultQtScrollStep;
}
+static QPoint getWheelEventDelta(const blink::WebGestureEvent &webEvent)
+{
+ static const float cDefaultQtScrollStep = 20.f;
+ static const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines();
+ return QPoint(webEvent.data.scroll_update.delta_x * QWheelEvent::DefaultDeltasPerStep / (wheelScrollLines * cDefaultQtScrollStep),
+ webEvent.data.scroll_update.delta_y * QWheelEvent::DefaultDeltasPerStep / (wheelScrollLines * cDefaultQtScrollStep));
+}
+
blink::WebMouseWheelEvent::Phase toBlinkPhase(QWheelEvent *ev)
{
switch (ev->phase()) {
@@ -1552,6 +1600,26 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent,
return true;
}
+static QPointF toQt(blink::WebFloatPoint p)
+{
+ return QPointF(p.x, p.y);
+}
+
+void WebEventFactory::sendUnhandledWheelEvent(const blink::WebGestureEvent &event,
+ RenderWidgetHostViewQtDelegate *delegate)
+{
+ Q_ASSERT(event.GetType() == blink::WebInputEvent::kGestureScrollUpdate);
+
+ QWheelEvent ev(toQt(event.PositionInWidget()),
+ toQt(event.PositionInScreen()),
+ QPoint(event.data.scroll_update.delta_x, event.data.scroll_update.delta_y),
+ getWheelEventDelta(event),
+ mouseButtonsForModifier(event.GetModifiers()),
+ keyboardModifiersForModifier(event.GetModifiers()),
+ Qt::NoScrollPhase, false);
+ delegate->unhandledWheelEvent(&ev);
+}
+
content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev)
{
content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev));
@@ -1686,3 +1754,5 @@ bool WebEventFactory::getEditCommand(QKeyEvent *event, std::string *editCommand)
return false;
}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h
index 526202cfb..390502a9d 100644
--- a/src/core/web_event_factory.h
+++ b/src/core/web_event_factory.h
@@ -63,6 +63,10 @@ class QNativeGestureEvent;
#endif
QT_END_NAMESPACE
+namespace QtWebEngineCore {
+
+class RenderWidgetHostViewQtDelegate;
+
class WebEventFactory {
public:
@@ -77,9 +81,11 @@ public:
#endif
static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent *);
static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent *);
+ static void sendUnhandledWheelEvent(const blink::WebGestureEvent &, RenderWidgetHostViewQtDelegate *);
static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*);
static bool getEditCommand(QKeyEvent *event, std::string *editCommand);
};
+} // namespace QtWebEngineCore
#endif // WEB_EVENT_FACTORY_H
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 7052afe42..4096eb7f6 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -547,12 +547,13 @@ void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event)
QCoreApplication::sendEvent(q->parentItem(), event);
}
-void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &, const QUrl &targetUrl)
+QSharedPointer<WebContentsAdapter>
+QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents,
+ WindowOpenDisposition disposition, bool userGesture,
+ const QRect &, const QUrl &targetUrl)
{
Q_Q(QQuickWebEngineView);
QQuickWebEngineNewViewRequest request;
- // This increases the ref-count of newWebContents and will tell Chromium
- // to start loading it and possibly return it to its parent page window.open().
request.m_adapter = newWebContents;
request.m_isUserInitiated = userGesture;
request.m_requestedUrl = targetUrl;
@@ -575,6 +576,8 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapte
}
Q_EMIT q->newViewRequested(&request);
+
+ return newWebContents;
}
bool QQuickWebEngineViewPrivate::isBeingAdopted()
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 5c884e36e..e696f6a0c 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -121,7 +121,10 @@ public:
void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) override;
void focusContainer() override;
void unhandledKeyEvent(QKeyEvent *event) override;
- void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &, const QUrl &targetUrl) override;
+ QSharedPointer<QtWebEngineCore::WebContentsAdapter>
+ adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents,
+ WindowOpenDisposition disposition, bool userGesture, const QRect &,
+ const QUrl &targetUrl) override;
bool isBeingAdopted() override;
void close() override;
void windowCloseRejected() override;
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index af98fda0b..4bbddd740 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -348,7 +348,10 @@ void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event)
QGuiApplication::sendEvent(view->parentWidget(), event);
}
-void QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry, const QUrl &targetUrl)
+QSharedPointer<WebContentsAdapter>
+QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents,
+ WindowOpenDisposition disposition, bool userGesture,
+ const QRect &initialGeometry, const QUrl &targetUrl)
{
Q_Q(QWebEnginePage);
Q_UNUSED(userGesture);
@@ -356,27 +359,11 @@ void QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> ne
QWebEnginePage *newPage = q->createWindow(toWindowType(disposition));
if (!newPage)
- return;
+ return nullptr;
- if (newPage->d_func() == this) {
- // If createWindow returns /this/ we must delay the adoption.
- Q_ASSERT(q == newPage);
- // WebContents might be null if we just opened a new page for navigation, in that case
- // avoid referencing newWebContents so that it is deleted and WebContentsDelegateQt::OpenURLFromTab
- // will fall back to navigating current page.
- if (newWebContents->webContents()) {
- QTimer::singleShot(0, q, [this, newPage, newWebContents, initialGeometry] () {
- adoptNewWindowImpl(newPage, newWebContents, initialGeometry);
- });
- }
- } else {
- adoptNewWindowImpl(newPage, newWebContents, initialGeometry);
- }
-}
+ if (!newWebContents->webContents())
+ return newPage->d_func()->adapter; // Reuse existing adapter
-void QWebEnginePagePrivate::adoptNewWindowImpl(QWebEnginePage *newPage,
- const QSharedPointer<WebContentsAdapter> &newWebContents, const QRect &initialGeometry)
-{
// Mark the new page as being in the process of being adopted, so that a second mouse move event
// sent by newWebContents->initialize() gets filtered in RenderWidgetHostViewQt::forwardEvent.
// The first mouse move event is being sent by q->createWindow(). This is necessary because
@@ -394,6 +381,8 @@ void QWebEnginePagePrivate::adoptNewWindowImpl(QWebEnginePage *newPage,
if (!initialGeometry.isEmpty())
emit newPage->geometryChangeRequested(initialGeometry);
+
+ return newWebContents;
}
bool QWebEnginePagePrivate::isBeingAdopted()
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index f37413b8e..b4424ec4b 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -112,10 +112,10 @@ public:
void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) override;
void focusContainer() override;
void unhandledKeyEvent(QKeyEvent *event) override;
- void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry, const QUrl &targetUrl) override;
- void adoptNewWindowImpl(QWebEnginePage *newPage,
- const QSharedPointer<QtWebEngineCore::WebContentsAdapter> &newWebContents,
- const QRect &initialGeometry);
+ QSharedPointer<QtWebEngineCore::WebContentsAdapter>
+ adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents,
+ WindowOpenDisposition disposition, bool userGesture,
+ const QRect &initialGeometry, const QUrl &targetUrl) override;
bool isBeingAdopted() override;
void close() override;
void windowCloseRejected() override;
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 fdd6d1c4f..66b4cffea 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -474,11 +474,16 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event)
if (!handled)
return QQuickWidget::event(event);
- // Most events are accepted by default, but tablet events are not:
event->accept();
return true;
}
+void RenderWidgetHostViewQtDelegateWidget::unhandledWheelEvent(QWheelEvent *ev)
+{
+ if (QWidget *p = parentWidget())
+ qApp->sendEvent(p, ev);
+}
+
void RenderWidgetHostViewQtDelegateWidget::onWindowPosChanged()
{
m_client->visualPropertiesChanged();
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 c7783117a..034fdd65c 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
@@ -91,6 +91,7 @@ public:
void setInputMethodHints(Qt::InputMethodHints) override;
void setClearColor(const QColor &color) override;
bool copySurface(const QRect &, const QSize &, QImage &) override;
+ void unhandledWheelEvent(QWheelEvent *ev) override;
protected:
bool event(QEvent *event) override;
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 39bbc96de..ab19548e8 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -198,6 +198,8 @@ private Q_SLOTS:
void dataURLFragment();
void devTools();
void openLinkInDifferentProfile();
+ void openLinkInNewPage_data();
+ void openLinkInNewPage();
void triggerActionWithoutMenu();
void dynamicFrame();
@@ -3380,6 +3382,162 @@ void tst_QWebEnginePage::openLinkInDifferentProfile()
QVERIFY(spy2.takeFirst().value(0).toBool());
}
+// What does createWindow do?
+enum class OpenLinkInNewPageDecision {
+ // Returns nullptr,
+ ReturnNull,
+ // Returns this,
+ ReturnSelf,
+ // Returns page != this
+ ReturnOther,
+};
+
+// What causes createWindow to be called?
+enum class OpenLinkInNewPageCause {
+ // User clicks on a link with target=_blank.
+ TargetBlank,
+ // User clicks with MiddleButton.
+ MiddleClick,
+};
+
+// What happens after createWindow?
+enum class OpenLinkInNewPageEffect {
+ // The navigation request disappears into the ether.
+ Blocked,
+ // The navigation request becomes a navigation in the original page.
+ LoadInSelf,
+ // The navigation request becomes a navigation in a different page.
+ LoadInOther,
+};
+
+Q_DECLARE_METATYPE(OpenLinkInNewPageCause)
+Q_DECLARE_METATYPE(OpenLinkInNewPageDecision)
+Q_DECLARE_METATYPE(OpenLinkInNewPageEffect)
+
+void tst_QWebEnginePage::openLinkInNewPage_data()
+{
+ using Decision = OpenLinkInNewPageDecision;
+ using Cause = OpenLinkInNewPageCause;
+ using Effect = OpenLinkInNewPageEffect;
+
+ QTest::addColumn<Decision>("decision");
+ QTest::addColumn<Cause>("cause");
+ QTest::addColumn<Effect>("effect");
+
+ // Note that the meaning of returning nullptr from createWindow is not
+ // consistent between the TargetBlank and MiddleClick scenarios.
+ //
+ // With TargetBlank, the open-in-new-page disposition comes from the HTML
+ // target attribute; something the user is probably not aware of. Returning
+ // nullptr is interpreted as a decision by the app to block an unwanted
+ // popup.
+ //
+ // With MiddleClick, the open-in-new-page disposition comes from the user's
+ // explicit intent. Returning nullptr is then interpreted as a failure by
+ // the app to fulfill this intent, which we try to compensate by ignoring
+ // the disposition and performing the navigation request normally.
+
+ QTest::newRow("BlockPopup") << Decision::ReturnNull << Cause::TargetBlank << Effect::Blocked;
+ QTest::newRow("IgnoreIntent") << Decision::ReturnNull << Cause::MiddleClick << Effect::LoadInSelf;
+ QTest::newRow("OverridePopup") << Decision::ReturnSelf << Cause::TargetBlank << Effect::LoadInSelf;
+ QTest::newRow("OverrideIntent") << Decision::ReturnSelf << Cause::MiddleClick << Effect::LoadInSelf;
+ QTest::newRow("AcceptPopup") << Decision::ReturnOther << Cause::TargetBlank << Effect::LoadInOther;
+ QTest::newRow("AcceptIntent") << Decision::ReturnOther << Cause::MiddleClick << Effect::LoadInOther;
+}
+
+void tst_QWebEnginePage::openLinkInNewPage()
+{
+ using Decision = OpenLinkInNewPageDecision;
+ using Cause = OpenLinkInNewPageCause;
+ using Effect = OpenLinkInNewPageEffect;
+
+ class Page : public QWebEnginePage
+ {
+ public:
+ Page *targetPage = nullptr;
+ QSignalSpy spy{this, &QWebEnginePage::loadFinished};
+ Page(QWebEngineProfile *profile) : QWebEnginePage(profile) {}
+ private:
+ QWebEnginePage *createWindow(WebWindowType) override { return targetPage; }
+ };
+
+ class View : public QWebEngineView
+ {
+ public:
+ View(Page *page)
+ {
+ resize(500, 500);
+ setPage(page);
+ }
+ };
+
+ QFETCH(Decision, decision);
+ QFETCH(Cause, cause);
+ QFETCH(Effect, effect);
+
+ QWebEngineProfile profile;
+ Page page1(&profile);
+ Page page2(&profile);
+ View view1(&page1);
+ View view2(&page2);
+
+ view1.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view1));
+
+ page1.setHtml("<html><body>"
+ "<a id='link' href='data:,hello' target='_blank'>link</a>"
+ "</body></html>");
+ QTRY_COMPARE(page1.spy.count(), 1);
+ QVERIFY(page1.spy.takeFirst().value(0).toBool());
+
+ switch (decision) {
+ case Decision::ReturnNull:
+ page1.targetPage = nullptr;
+ break;
+ case Decision::ReturnSelf:
+ page1.targetPage = &page1;
+ break;
+ case Decision::ReturnOther:
+ page1.targetPage = &page2;
+ break;
+ }
+
+ Qt::MouseButton button;
+ switch (cause) {
+ case Cause::TargetBlank:
+ button = Qt::LeftButton;
+ break;
+ case Cause::MiddleClick:
+ button = Qt::MiddleButton;
+ break;
+ }
+ QTest::mouseClick(view1.focusProxy(), button, {}, elementCenter(&page1, "link"));
+
+ switch (effect) {
+ case Effect::Blocked:
+ // Nothing to test
+ break;
+ case Effect::LoadInSelf:
+ QTRY_COMPARE(page1.spy.count(), 1);
+ QVERIFY(page1.spy.takeFirst().value(0).toBool());
+ QCOMPARE(page2.spy.count(), 0);
+ if (decision == Decision::ReturnSelf && cause == Cause::TargetBlank)
+ // History was discarded due to AddNewContents
+ QCOMPARE(page1.history()->count(), 1);
+ else
+ QCOMPARE(page1.history()->count(), 2);
+ QCOMPARE(page2.history()->count(), 0);
+ break;
+ case Effect::LoadInOther:
+ QTRY_COMPARE(page2.spy.count(), 1);
+ QVERIFY(page2.spy.takeFirst().value(0).toBool());
+ QCOMPARE(page1.spy.count(), 0);
+ QCOMPARE(page1.history()->count(), 1);
+ QCOMPARE(page2.history()->count(), 1);
+ break;
+ }
+}
+
void tst_QWebEnginePage::triggerActionWithoutMenu()
{
// Calling triggerAction should not crash even when for
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 935babe81..00d4bae5a 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -246,7 +246,7 @@ void tst_QWebEngineProfile::clearDataFromCache()
QTest::qWait(1000);
QVERIFY(sizeBeforeClear > totalSize(cacheDir));
- QVERIFY(server.stop());
+ (void)server.stop();
}
void tst_QWebEngineProfile::disableCache()
@@ -271,7 +271,7 @@ void tst_QWebEngineProfile::disableCache()
QVERIFY(loadSync(&page, server.url("/hedgehog.html")));
QVERIFY(cacheDir.exists("Cache"));
- QVERIFY(server.stop());
+ (void)server.stop();
}
class RedirectingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
@@ -864,7 +864,7 @@ void tst_QWebEngineProfile::changePersistentPath()
QVERIFY(loadSync(&page, server.url("/hedgehog.html")));
QVERIFY(dataDir2.exists());
- QVERIFY(server.stop());
+ (void)server.stop();
}
void tst_QWebEngineProfile::changeHttpUserAgent()
@@ -937,7 +937,7 @@ void tst_QWebEngineProfile::changeUseForGlobalCertificateVerification()
page.reset(new QWebEnginePage(&profile));
QVERIFY(loadSync(page.get(), server.url("/hedgehog.html")));
// Don't check for error: there can be disconnects during GET hedgehog.png.
- server.stop();
+ (void)server.stop();
}
void tst_QWebEngineProfile::changePersistentCookiesPolicy()
@@ -961,7 +961,7 @@ void tst_QWebEngineProfile::changePersistentCookiesPolicy()
QVERIFY(loadSync(&page, server.url("/hedgehog.html")));
QVERIFY(dataDir.exists("Cookies"));
- QVERIFY(server.stop());
+ (void)server.stop();
}
class InitiatorSpy : public QWebEngineUrlSchemeHandler
diff --git a/tools/scripts/version_resolver.py b/tools/scripts/version_resolver.py
index 20141e4b2..b3181db10 100644
--- a/tools/scripts/version_resolver.py
+++ b/tools/scripts/version_resolver.py
@@ -38,7 +38,7 @@ import json
import urllib2
import git_submodule as GitSubmodule
-chromium_version = '80.0.3987.136'
+chromium_version = '80.0.3987.163'
chromium_branch = '3987'
ninja_version = 'v1.8.2'