summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2019-07-25 11:12:16 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2019-07-25 14:50:41 +0200
commit83fa1d5f9b890ba251f7dc8f82acd950e9527343 (patch)
treec9beec83e2454bc7d001bdc116620b3cc323d7a4
parent9cfde2edf4736ae9533e7e1fac495a23ad905419 (diff)
parent562b294373a99d979df363e9bbbab2e5b77c67df (diff)
downloadqtwebengine-83fa1d5f9b890ba251f7dc8f82acd950e9527343.tar.gz
Merge "Merge remote-tracking branch 'origin/dev' into wip/qt6"
-rw-r--r--mkspecs/features/configure.prf10
-rw-r--r--mkspecs/features/functions.prf8
-rw-r--r--mkspecs/features/platform.prf4
m---------src/3rdparty0
-rw-r--r--src/core/api/qtwebenginecoreglobal.cpp2
-rw-r--r--src/core/api/qwebengineurlscheme.cpp10
-rw-r--r--src/core/api/qwebengineurlscheme.h1
-rw-r--r--src/core/compositor/compositor_resource_tracker.cpp3
-rw-r--r--src/core/compositor/delegated_frame_node.cpp17
-rw-r--r--src/core/config/common.pri4
-rw-r--r--src/core/config/linux.pri2
-rw-r--r--src/core/configure.json32
-rw-r--r--src/core/core_chromium.pri2
-rw-r--r--src/core/core_module.pro14
-rw-r--r--src/core/net/qrc_url_scheme_handler.cpp5
-rw-r--r--src/core/net/url_request_custom_job.cpp26
-rw-r--r--src/core/net/url_request_custom_job.h3
-rw-r--r--src/core/net/url_request_custom_job_proxy.cpp3
-rw-r--r--src/core/pref_service_adapter.cpp5
-rw-r--r--src/core/profile_adapter.cpp8
-rw-r--r--src/core/render_widget_host_view_qt.cpp5
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h2
-rw-r--r--src/core/web_contents_adapter.cpp12
-rw-r--r--src/core/web_contents_delegate_qt.cpp7
-rw-r--r--src/core/web_contents_delegate_qt.h1
-rw-r--r--src/webengine/doc/qtwebengine.qdocconf13
-rw-r--r--src/webengine/doc/src/qtwebengine-platform-notes.qdoc7
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.cpp6
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.h1
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp5
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.h1
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp18
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h1
-rw-r--r--tests/auto/quick/dialogs/WebView.qml9
-rw-r--r--tests/auto/quick/inspectorserver/tst_inspectorserver.cpp2
-rw-r--r--tests/auto/quick/qmltests/BLACKLIST5
-rw-r--r--tests/auto/quick/qmltests/data/tst_findText.qml22
-rw-r--r--tests/auto/widgets/origins/resources/redirect.css8
-rw-r--r--tests/auto/widgets/origins/resources/redirect.html10
-rw-r--r--tests/auto/widgets/origins/tst_origins.cpp70
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp69
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp9
-rw-r--r--tests/auto/widgets/spellchecking/tst_spellchecking.cpp126
43 files changed, 413 insertions, 155 deletions
diff --git a/mkspecs/features/configure.prf b/mkspecs/features/configure.prf
index b8d9d43ce..cc84182b7 100644
--- a/mkspecs/features/configure.prf
+++ b/mkspecs/features/configure.prf
@@ -94,13 +94,9 @@ defineTest(runConfigure) {
}
}
- !qtConfig(webengine-embedded-build): qtConfig(xcb) {
- for(package, $$list("libdrm xcomposite xcursor xi xtst")) {
- !qtConfig(webengine-system-$$package) {
- skipBuild("A suitable version of $$package could not be found.")
- return(false)
- }
- }
+ !qtConfig(webengine-embedded-build): qtConfig(xcb) : !qtConfig(webengine-ozone-x11) {
+ skipBuild("Could not find all necessary libraries for qpa-xcb support")
+ return(false)
}
}
}
diff --git a/mkspecs/features/functions.prf b/mkspecs/features/functions.prf
index 9efa8958f..d3eda85b2 100644
--- a/mkspecs/features/functions.prf
+++ b/mkspecs/features/functions.prf
@@ -121,11 +121,3 @@ defineReplace(pkgConfigHostExecutable) {
return($$system_quote($$system_path($$wrapper_name)))
}
-defineTest(hasX11Dependencies) {
- for(package, $$list("libdrm xcomposite xcursor xi xtst")) {
- !qtConfig(webengine-system-$$package) {
- return(false)
- }
- }
- return(true)
-}
diff --git a/mkspecs/features/platform.prf b/mkspecs/features/platform.prf
index 53ea51014..ef1c86d39 100644
--- a/mkspecs/features/platform.prf
+++ b/mkspecs/features/platform.prf
@@ -29,8 +29,8 @@ defineTest(isPlatformSupported) {
skipBuild("Qt WebEngine on Windows requires MSVC or Clang (MSVC mode).")
return(false)
}
- !isMinWinSDKVersion(10, 16299): {
- skipBuild("Qt WebEngine on Windows requires a Windows SDK version 10.0.16299 or newer.")
+ !isMinWinSDKVersion(10, 17763): {
+ skipBuild("Qt WebEngine on Windows requires a Windows SDK version 10.0.17763 or newer.")
return(false)
}
!qtConfig(webengine-winversion) {
diff --git a/src/3rdparty b/src/3rdparty
-Subproject be2f3bb839aab9ad8ba7b545b8a2bc91ce6702d
+Subproject f5613a4bc321972b8f72654d4c4bc9ba0c36ffb
diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp
index abc2bd406..0fddacb15 100644
--- a/src/core/api/qtwebenginecoreglobal.cpp
+++ b/src/core/api/qtwebenginecoreglobal.cpp
@@ -80,6 +80,8 @@ static QOpenGLContext *shareContext;
static void deleteShareContext()
{
+ if (qt_gl_global_share_context() == shareContext)
+ qt_gl_set_global_share_context(nullptr);
delete shareContext;
shareContext = 0;
}
diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp
index f4efad717..f73992c6b 100644
--- a/src/core/api/qwebengineurlscheme.cpp
+++ b/src/core/api/qwebengineurlscheme.cpp
@@ -59,6 +59,7 @@ ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::NoAccessAllowed, url::CustomScheme::NoAc
ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ServiceWorkersAllowed, url::CustomScheme::ServiceWorkersAllowed)
ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ViewSourceAllowed, url::CustomScheme::ViewSourceAllowed)
ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::ContentSecurityPolicyIgnored, url::CustomScheme::ContentSecurityPolicyIgnored)
+ASSERT_ENUMS_MATCH(QWebEngineUrlScheme::CorsEnabled, url::CustomScheme::CorsEnabled)
static bool g_schemesLocked = false;
@@ -190,6 +191,13 @@ public:
\value ContentSecurityPolicyIgnored
Indicates that accesses to this scheme should bypass all
Content-Security-Policy checks.
+
+ \value CorsEnabled
+ Enables cross-origin resource sharing (CORS) for this scheme. This flag is
+ required in order to, for example, use the scheme with the \l
+ {https://fetch.spec.whatwg.org/}{Fetch API}, or to deliver CSS fonts to a
+ different origin. The appropriate CORS headers are generated automatically by
+ the QWebEngineUrlRequestJob class. (Added in Qt 5.14)
*/
QWebEngineUrlScheme::QWebEngineUrlScheme(QWebEngineUrlSchemePrivate *d) : d(d) {}
@@ -374,7 +382,7 @@ void QWebEngineUrlScheme::registerScheme(const QWebEngineUrlScheme &scheme)
return;
}
- if (url::IsStandard(scheme.d->name.data(), url::Component(0, scheme.d->name.size()))) {
+ if (url::IsStandard(scheme.d->name.data(), url::Component(0, static_cast<int>(scheme.d->name.size())))) {
qWarning() << "QWebEngineUrlScheme::registerScheme: Scheme" << scheme.name() << "is a standard scheme";
return;
}
diff --git a/src/core/api/qwebengineurlscheme.h b/src/core/api/qwebengineurlscheme.h
index 095b47320..ecac44184 100644
--- a/src/core/api/qwebengineurlscheme.h
+++ b/src/core/api/qwebengineurlscheme.h
@@ -76,6 +76,7 @@ public:
ServiceWorkersAllowed = 0x10,
ViewSourceAllowed = 0x20,
ContentSecurityPolicyIgnored = 0x40,
+ CorsEnabled = 0x80,
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAG(Flags)
diff --git a/src/core/compositor/compositor_resource_tracker.cpp b/src/core/compositor/compositor_resource_tracker.cpp
index 73242c693..741c2717c 100644
--- a/src/core/compositor/compositor_resource_tracker.cpp
+++ b/src/core/compositor/compositor_resource_tracker.cpp
@@ -174,7 +174,8 @@ quint32 CompositorResourceTracker::consumeMailbox(const gpu::MailboxHolder &mail
DCHECK(mailboxManager);
if (mailboxHolder.sync_token.HasData())
mailboxManager->PullTextureUpdates(mailboxHolder.sync_token);
- return service_id(mailboxManager->ConsumeTexture(mailboxHolder.mailbox));
+ gpu::TextureBase *tex = mailboxManager->ConsumeTexture(mailboxHolder.mailbox);
+ return tex ? service_id(tex) : 0;
#else
NOTREACHED();
#endif // QT_CONFIG(OPENGL)
diff --git a/src/core/compositor/delegated_frame_node.cpp b/src/core/compositor/delegated_frame_node.cpp
index dc67b03e2..19e8d1b82 100644
--- a/src/core/compositor/delegated_frame_node.cpp
+++ b/src/core/compositor/delegated_frame_node.cpp
@@ -195,12 +195,10 @@ public:
{
Q_ASSERT(layer);
Q_ASSERT(m_nodeIterator != m_sceneGraphNodes->end());
- QSGInternalImageNode *imageNode = static_cast<QSGInternalImageNode*>(*m_nodeIterator++);
- imageNode->setTargetRect(rect);
- imageNode->setInnerTargetRect(rect);
- imageNode->setSubSourceRect(layer->convertToNormalizedSourceRect(sourceRect));
+ QSGImageNode *imageNode = static_cast<QSGImageNode*>(*m_nodeIterator++);
+ imageNode->setRect(rect);
+ imageNode->setSourceRect(sourceRect);
imageNode->setTexture(layer);
- imageNode->update();
}
void setupTextureContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect,
@@ -281,13 +279,10 @@ public:
QSGNode *layerChain) override
{
Q_ASSERT(layer);
- // Only QSGInternalImageNode currently supports QSGLayer textures.
- QSGInternalImageNode *imageNode = m_apiDelegate->createInternalImageNode();
- imageNode->setTargetRect(rect);
- imageNode->setInnerTargetRect(rect);
- imageNode->setSubSourceRect(layer->convertToNormalizedSourceRect(sourceRect));
+ QSGImageNode *imageNode = m_apiDelegate->createImageNode();
+ imageNode->setRect(rect);
+ imageNode->setSourceRect(sourceRect);
imageNode->setTexture(layer);
- imageNode->update();
layerChain->appendChildNode(imageNode);
m_sceneGraphNodes->append(imageNode);
diff --git a/src/core/config/common.pri b/src/core/config/common.pri
index dea904ef8..edebdb33c 100644
--- a/src/core/config/common.pri
+++ b/src/core/config/common.pri
@@ -127,3 +127,7 @@ qtConfig(webengine-kerberos) {
} else {
gn_args += use_kerberos=false
}
+
+ccache {
+ gn_args += cc_wrapper=\"ccache\"
+}
diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri
index 40bc0b73c..998aedc40 100644
--- a/src/core/config/linux.pri
+++ b/src/core/config/linux.pri
@@ -180,7 +180,7 @@ host_build {
}
!packagesExist(libpci): gn_args += use_libpci=false
- qtConfig(webengine-system-x11): hasX11Dependencies() {
+ qtConfig(webengine-ozone-x11) {
gn_args += ozone_platform_x11=true
packagesExist(xscrnsaver): gn_args += use_xscrnsaver=true
}
diff --git a/src/core/configure.json b/src/core/configure.json
index 98eee347f..66e39ddc2 100644
--- a/src/core/configure.json
+++ b/src/core/configure.json
@@ -11,6 +11,7 @@
"options": {
"webengine-alsa": "boolean",
"webengine-embedded-build": "boolean",
+ "webengine-full-debug-info": "boolean",
"webengine-icu": { "type": "enum", "name": "webengine-system-icu", "values": { "system": "yes", "qt": "no" } },
"webengine-ffmpeg": { "type": "enum", "name": "webengine-system-ffmpeg", "values": { "system": "yes", "qt": "no" } },
"webengine-opus": { "type": "enum", "name": "webengine-system-opus", "values": { "system": "yes", "qt": "no" } },
@@ -650,6 +651,17 @@
"condition": "config.unix && libs.webengine-x11",
"output": [ "privateFeature" ]
},
+ "webengine-ozone-x11" : {
+ "label": "Support qpa-xcb",
+ "condition": "config.unix
+ && features.webengine-system-x11
+ && features.webengine-system-libdrm
+ && features.webengine-system-xcomposite
+ && features.webengine-system-xcursor
+ && features.webengine-system-xi
+ && features.webengine-system-xtst",
+ "output": [ "privateFeature" ]
+ },
"webengine-sanitizer" : {
"label": "Sanitizer",
"autoDetect": "config.sanitizer && tests.webengine-sanitizer",
@@ -685,6 +697,16 @@
"section": "WebEngine",
"output": [ "privateFeature" ]
},
+ "webengine-full-debug-info": {
+ "label": "Full debug information",
+ "purpose": "Enables debug information for Blink and V8.",
+ "autoDetect": false,
+ "condition": "config.debug || features.debug_and_release || features.force_debug_info",
+ "output": [
+ { "type": "privateConfig", "name": "v8base_debug" },
+ { "type": "privateConfig", "name": "webcore_debug" }
+ ]
+ },
"webengine-noexecstack": {
"label": "linker supports -z noexecstack",
"condition": "config.unix && tests.webengine-noexecstack",
@@ -742,6 +764,7 @@
"webengine-widgets",
"webengine-qml",
"webengine-embedded-build",
+ "webengine-full-debug-info",
"webengine-pepper-plugins",
"webengine-printing-and-pdf",
"webengine-proprietary-codecs",
@@ -756,6 +779,11 @@
"webengine-extensions",
{
"type": "feature",
+ "args": "webengine-ozone-x11",
+ "condition": "config.unix"
+ },
+ {
+ "type": "feature",
"args": "webengine-v8-snapshot-support",
"condition": "config.unix && config.cross_compile && features.webengine-v8-snapshot"
},
@@ -826,8 +854,7 @@
"webengine-system-png",
"webengine-system-jpeg",
"webengine-system-harfbuzz",
- "webengine-system-freetype",
- "webengine-system-x11"
+ "webengine-system-freetype"
]
},
{
@@ -845,6 +872,7 @@
"section": "Required system libraries for qpa-xcb",
"condition": "config.unix && !config.macos",
"entries": [
+ "webengine-system-x11",
"webengine-system-libdrm",
"webengine-system-xcomposite",
"webengine-system-xcursor",
diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri
index f99513adf..908387788 100644
--- a/src/core/core_chromium.pri
+++ b/src/core/core_chromium.pri
@@ -246,7 +246,7 @@ HEADERS = \
web_engine_settings.h \
web_event_factory.h
-qtConfig(webengine-system-x11): hasX11Dependencies() {
+qtConfig(webengine-ozone-x11) {
HEADERS += ozone/gl_ozone_glx_qt.h \
ozone/gl_surface_glx_qt.h
SOURCES += ozone/gl_surface_glx_qt.cpp \
diff --git a/src/core/core_module.pro b/src/core/core_module.pro
index 02aa6ac38..b220af4a5 100644
--- a/src/core/core_module.pro
+++ b/src/core/core_module.pro
@@ -42,11 +42,15 @@ LIBS_PRIVATE += $$NINJA_LIB_DIRS $$NINJA_LIBS
unix:qtConfig(webengine-noexecstack): \
QMAKE_LFLAGS += -Wl,-z,noexecstack
linux {
- QMAKE_LFLAGS += -Wl,--gc-sections -Wl,-O1 -Wl,-z,now
- # Embedded address sanitizer symbols are undefined and are picked up by the dynamic link loader
- # at runtime. Thus we do not to pass the linker flag below, because the linker would complain
- # about the undefined sanitizer symbols.
- !sanitizer: QMAKE_LFLAGS += -Wl,-z,defs
+ # add chromium flags
+ for(flag, NINJA_LFLAGS) {
+ # filter out some flags
+ !contains(flag, .*noexecstack$): \
+ !contains(flag, .*as-needed$): \
+ !contains(flag, ^-B.*): \
+ !contains(flag, ^-fuse-ld.*): \
+ QMAKE_LFLAGS += $$flag
+ }
} else {
QMAKE_LFLAGS += $$NINJA_LFLAGS
}
diff --git a/src/core/net/qrc_url_scheme_handler.cpp b/src/core/net/qrc_url_scheme_handler.cpp
index 74a77a7ec..73bf24f1d 100644
--- a/src/core/net/qrc_url_scheme_handler.cpp
+++ b/src/core/net/qrc_url_scheme_handler.cpp
@@ -59,6 +59,11 @@ void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job)
QUrl requestUrl = job->requestUrl();
QString requestPath = requestUrl.path();
QScopedPointer<QFile> file(new QFile(':' + requestPath, job));
+ if (!file->exists() || file->size() == 0) {
+ qWarning("QResource '%s' not found or is empty", qUtf8Printable(requestPath));
+ job->fail(QWebEngineUrlRequestJob::UrlNotFound);
+ return;
+ }
QFileInfo fileInfo(*file);
QMimeDatabase mimeDatabase;
QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileInfo);
diff --git a/src/core/net/url_request_custom_job.cpp b/src/core/net/url_request_custom_job.cpp
index cba9b4dc5..dd213d4f8 100644
--- a/src/core/net/url_request_custom_job.cpp
+++ b/src/core/net/url_request_custom_job.cpp
@@ -40,10 +40,13 @@
#include "url_request_custom_job.h"
#include "url_request_custom_job_proxy.h"
+#include "api/qwebengineurlscheme.h"
+#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
+#include "net/http/http_util.h"
#include <QIODevice>
@@ -62,6 +65,9 @@ URLRequestCustomJob::URLRequestCustomJob(URLRequest *request,
, m_pendingReadSize(0)
, m_pendingReadPos(0)
, m_pendingReadBuffer(nullptr)
+ , m_corsEnabled(QWebEngineUrlScheme::schemeByName(QByteArray::fromStdString(scheme))
+ .flags().testFlag(QWebEngineUrlScheme::CorsEnabled))
+ , m_httpStatusCode(500)
{
}
@@ -136,6 +142,26 @@ bool URLRequestCustomJob::GetCharset(std::string* charset)
return false;
}
+void URLRequestCustomJob::GetResponseInfo(HttpResponseInfo* info)
+{
+ // Based on net::URLRequestRedirectJob::StartAsync()
+
+ if (!m_corsEnabled)
+ return;
+
+ std::string headers;
+ headers += base::StringPrintf("HTTP/1.1 %i OK\n", m_httpStatusCode);
+ if (m_redirect.is_valid())
+ headers += base::StringPrintf("Location: %s\n", m_redirect.spec().c_str());
+ std::string origin;
+ if (request_->extra_request_headers().GetHeader("Origin", &origin)) {
+ headers += base::StringPrintf("Access-Control-Allow-Origin: %s\n", origin.c_str());
+ headers += "Access-Control-Allow-Credentials: true\n";
+ }
+
+ info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+}
+
bool URLRequestCustomJob::IsRedirectResponse(GURL* location, int* http_status_code, bool* /*insecure_scheme_was_upgraded*/)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
diff --git a/src/core/net/url_request_custom_job.h b/src/core/net/url_request_custom_job.h
index 16be76f29..e1e8e9fba 100644
--- a/src/core/net/url_request_custom_job.h
+++ b/src/core/net/url_request_custom_job.h
@@ -64,6 +64,7 @@ public:
int ReadRawData(net::IOBuffer *buf, int buf_size) override;
bool GetMimeType(std::string *mimeType) const override;
bool GetCharset(std::string *charset) override;
+ void GetResponseInfo(net::HttpResponseInfo* info) override;
bool IsRedirectResponse(GURL* location, int* http_status_code, bool* insecure_scheme_was_upgraded) override;
protected:
@@ -80,6 +81,8 @@ private:
int m_pendingReadSize;
int m_pendingReadPos;
net::IOBuffer *m_pendingReadBuffer;
+ const bool m_corsEnabled;
+ int m_httpStatusCode;
friend class URLRequestCustomJobProxy;
diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp
index 72d14450e..b9ccf7ea4 100644
--- a/src/core/net/url_request_custom_job_proxy.cpp
+++ b/src/core/net/url_request_custom_job_proxy.cpp
@@ -100,6 +100,7 @@ void URLRequestCustomJobProxy::reply(std::string mimeType, QIODevice *device)
m_job->set_expected_content_size(size);
if (m_job->m_device && m_job->m_device->isReadable()) {
m_started = true;
+ m_job->m_httpStatusCode = 200;
m_job->NotifyHeadersComplete();
} else {
fail(ERR_INVALID_URL);
@@ -114,6 +115,7 @@ void URLRequestCustomJobProxy::redirect(GURL url)
if (m_job->m_device || m_job->m_error)
return;
m_job->m_redirect = url;
+ m_job->m_httpStatusCode = 303;
m_started = true;
m_job->NotifyHeadersComplete();
}
@@ -138,6 +140,7 @@ void URLRequestCustomJobProxy::fail(int error)
if (!m_job)
return;
m_job->m_error = error;
+ m_job->m_httpStatusCode = 500;
if (m_job->m_device)
m_job->m_device->close();
if (!m_started)
diff --git a/src/core/pref_service_adapter.cpp b/src/core/pref_service_adapter.cpp
index 0cf53dda5..8a33a4b60 100644
--- a/src/core/pref_service_adapter.cpp
+++ b/src/core/pref_service_adapter.cpp
@@ -137,6 +137,11 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
content::BrowserContext::CreateRandomMediaDeviceIDSalt());
}
+#if QT_CONFIG(webengine_spellchecker)
+ // Ignore stored values for these options to preserve backwards compatibility.
+ m_prefService->ClearPref(spellcheck::prefs::kSpellCheckEnable);
+ m_prefService->ClearPref(spellcheck::prefs::kSpellCheckDictionaries);
+#endif // QT_CONFIG(webengine_spellchecker)
}
void PrefServiceAdapter::commit()
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index fdbdbfdcb..551663cf0 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -438,7 +438,7 @@ void ProfileAdapter::setHttpCacheMaxSize(int maxSize)
m_profile->m_profileIOData->updateHttpCache();
}
-enum class SchemeType { Protected, Overridable, Custom };
+enum class SchemeType { Protected, Overridable, Custom, Unknown };
static SchemeType schemeType(const QByteArray &canonicalScheme)
{
static const QSet<QByteArray> blacklist{
@@ -463,7 +463,9 @@ static SchemeType schemeType(const QByteArray &canonicalScheme)
return SchemeType::Overridable;
if (blacklisted || (standardSyntax && !customScheme))
return SchemeType::Protected;
- return SchemeType::Custom;
+ if (customScheme)
+ return SchemeType::Custom;
+ return SchemeType::Unknown;
}
QWebEngineUrlSchemeHandler *ProfileAdapter::urlSchemeHandler(const QByteArray &scheme)
@@ -530,7 +532,7 @@ void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngin
return;
}
- if (type == SchemeType::Custom)
+ if (type == SchemeType::Unknown)
qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() "
"before installing the custom scheme handler.", scheme.constData());
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index a5ae0a04a..0242506ee 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -238,7 +238,10 @@ public:
float GetHistoricalTouchMajor(size_t pointer_index, size_t historical_index) const override { return 0; }
float GetHistoricalX(size_t pointer_index, size_t historical_index) const override { return 0; }
float GetHistoricalY(size_t pointer_index, size_t historical_index) const override { return 0; }
- ToolType GetToolType(size_t pointer_index) const override { return ui::MotionEvent::ToolType::FINGER; }
+ ToolType GetToolType(size_t pointer_index) const override {
+ return (touchPoints.at(pointer_index).flags() & QTouchEvent::TouchPoint::InfoFlag::Pen) ? ui::MotionEvent::ToolType::STYLUS
+ : ui::MotionEvent::ToolType::FINGER;
+ }
int GetButtonState() const override { return 0; }
private:
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index 6066284d9..4ee790ce9 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -65,7 +65,6 @@ class QSGTexture;
class QVariant;
class QInputMethodEvent;
-class QSGInternalImageNode;
class QSGImageNode;
QT_END_NAMESPACE
@@ -102,7 +101,6 @@ public:
virtual QWindow* window() const = 0;
virtual QSGTexture *createTextureFromImage(const QImage &) = 0;
virtual QSGLayer *createLayer() = 0;
- virtual QSGInternalImageNode *createInternalImageNode() = 0;
virtual QSGImageNode *createImageNode() = 0;
virtual QSGRectangleNode *createRectangleNode() = 0;
virtual void update() = 0;
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 2295d33c0..ee0b8cc39 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -693,19 +693,23 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request)
}
}
- auto navigate = [](WebContentsAdapter *adapter, const content::NavigationController::LoadURLParams &params) {
+ auto navigate = [](QWeakPointer<WebContentsAdapter> weakAdapter, const content::NavigationController::LoadURLParams &params) {
+ WebContentsAdapter *adapter = weakAdapter.data();
+ if (!adapter)
+ return;
adapter->webContents()->GetController().LoadURLWithParams(params);
// Follow chrome::Navigate and invalidate the URL immediately.
adapter->m_webContentsDelegate->NavigationStateChanged(adapter->webContents(), content::INVALIDATE_TYPE_URL);
adapter->focusIfNecessary();
};
+ QWeakPointer<WebContentsAdapter> weakThis(sharedFromThis());
if (resizeNeeded) {
// Schedule navigation on the event loop.
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(navigate, this, std::move(params)));
+ base::BindOnce(navigate, std::move(weakThis), std::move(params)));
} else {
- navigate(this, params);
+ navigate(std::move(weakThis), params);
}
}
@@ -1051,6 +1055,7 @@ quint64 WebContentsAdapter::findText(const QString &subString, bool caseSensitiv
// waiting for it forever.
// Assume that any unfinished find has been unsuccessful when a new one is started
// to cover that case.
+ m_webContentsDelegate->setLastReceivedFindReply(m_lastFindRequestId);
m_adapterClient->didFindText(m_lastFindRequestId, 0);
}
@@ -1071,6 +1076,7 @@ quint64 WebContentsAdapter::findText(const QString &subString, bool caseSensitiv
void WebContentsAdapter::stopFinding()
{
CHECK_INITIALIZED();
+ m_webContentsDelegate->setLastReceivedFindReply(m_lastFindRequestId);
m_webContentsDelegate->setLastSearchedString(QString());
m_webContents->StopFinding(content::STOP_FIND_ACTION_KEEP_SELECTION);
}
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 93f441636..f18617f8e 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -234,6 +234,11 @@ void WebContentsDelegateQt::AddNewContents(content::WebContents* source, std::un
{
Q_UNUSED(source)
QSharedPointer<WebContentsAdapter> newAdapter = createWindow(std::move(new_contents), disposition, initial_pos, user_gesture);
+ // Chromium can forget to pass user-agent override settings to new windows (see QTBUG-61774 and QTBUG-76249),
+ // so set it here. Note the actual value doesn't really matter here. Only the second value does, but we try
+ // to give the correct user-agent anyway.
+ if (newAdapter)
+ newAdapter->webContents()->SetUserAgentOverride(newAdapter->profileAdapter()->httpUserAgent().toStdString(), true);
if (newAdapter && !newAdapter->isInitialized())
newAdapter->loadDefault();
if (was_blocked)
@@ -575,7 +580,7 @@ void WebContentsDelegateQt::FindReply(content::WebContents *source, int request_
Q_UNUSED(source)
Q_UNUSED(selection_rect)
Q_UNUSED(active_match_ordinal)
- if (final_update) {
+ if (final_update && request_id > m_lastReceivedFindReply) {
m_lastReceivedFindReply = request_id;
m_viewClient->didFindText(request_id, number_of_matches);
}
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 11b35c549..00b715c30 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -115,6 +115,7 @@ public:
QString lastSearchedString() const { return m_lastSearchedString; }
void setLastSearchedString(const QString &s) { m_lastSearchedString = s; }
int lastReceivedFindReply() const { return m_lastReceivedFindReply; }
+ void setLastReceivedFindReply(int id) { m_lastReceivedFindReply = id; }
QUrl url() const { return m_url; }
QString title() const { return m_title; }
diff --git a/src/webengine/doc/qtwebengine.qdocconf b/src/webengine/doc/qtwebengine.qdocconf
index 50f2e2ceb..be5db9c19 100644
--- a/src/webengine/doc/qtwebengine.qdocconf
+++ b/src/webengine/doc/qtwebengine.qdocconf
@@ -1,4 +1,5 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtwebengine.qdocconf)
project = QtWebEngine
description = Qt WebEngine Reference Documentation
@@ -60,12 +61,14 @@ depends += qtcore \
qtwidgets
headerdirs += .. \
- ../../core \
- ../../webenginewidgets
+ ../../core/api \
+ ../../webenginewidgets/api
sourcedirs += .. \
- ../../core/ \
- ../../webenginewidgets \
+ ../../core/api \
+ ../../core/doc \
+ ../../webenginewidgets/api \
+ ../../webenginewidgets/doc
exampledirs += . \
../../../examples \
@@ -84,4 +87,4 @@ navigation.qmltypespage = "Qt WebEngine QML Types"
# \QWE macro expands to 'Qt WebEngine' without auto-linking anywhere.
macro.QWE = "Qt \\WebEngine"
-Cpp.ignoretokens += Q_WEBENGINE_EXPORT QWEBENGINEWIDGETS_EXPORT
+Cpp.ignoretokens += Q_WEBENGINE_EXPORT Q_WEBENGINECORE_EXPORT QWEBENGINEWIDGETS_EXPORT
diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc
index fefb47795..5b7d750ff 100644
--- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc
+++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc
@@ -69,7 +69,12 @@
\section2 Windows
- On Windows, Visual Studio 2017 and Windows 10 SDK are required.
+ On Windows, the following additional tools are required:
+
+ \list
+ \li Visual Studio 2017 version 15.8 or later
+ \li Windows 10 SDK
+ \endlist
\QWE can only be built on 64-bit Windows, with a x64-bit toolchain.
For building \QWE for x86 applications, you need to configure
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 b636448b3..3a103b9aa 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -170,12 +170,6 @@ QSGLayer *RenderWidgetHostViewQtDelegateQuick::createLayer()
return renderContext->sceneGraphContext()->createLayer(renderContext);
}
-QSGInternalImageNode *RenderWidgetHostViewQtDelegateQuick::createInternalImageNode()
-{
- QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context;
- return renderContext->sceneGraphContext()->createInternalImageNode();
-}
-
QSGImageNode *RenderWidgetHostViewQtDelegateQuick::createImageNode()
{
return QQuickItem::window()->createImageNode();
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 00158b3ac..b55b2d658 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h
@@ -71,7 +71,6 @@ public:
QWindow* window() const override;
QSGTexture *createTextureFromImage(const QImage &) override;
QSGLayer *createLayer() override;
- QSGInternalImageNode *createInternalImageNode() override;
QSGImageNode *createImageNode() override;
QSGRectangleNode *createRectangleNode() override;
void update() override;
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 c085aacd7..23b9e02c2 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -131,11 +131,6 @@ QSGLayer *RenderWidgetHostViewQtDelegateQuickWindow::createLayer()
return m_realDelegate->createLayer();
}
-QSGInternalImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createInternalImageNode()
-{
- return m_realDelegate->createInternalImageNode();
-}
-
QSGImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createImageNode()
{
return m_realDelegate->createImageNode();
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 ab583bd63..bebbfa439 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h
@@ -68,7 +68,6 @@ public:
QWindow* window() const override;
QSGTexture *createTextureFromImage(const QImage &) override;
QSGLayer *createLayer() override;
- QSGInternalImageNode *createInternalImageNode() override;
QSGImageNode *createImageNode() override;
QSGRectangleNode *createRectangleNode() override;
void update() 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 817d6e408..894dca4fa 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -77,14 +77,6 @@ protected:
{
m_client->forwardEvent(event);
}
- void keyPressEvent(QKeyEvent *event) override
- {
- m_client->forwardEvent(event);
- }
- void keyReleaseEvent(QKeyEvent *event) override
- {
- m_client->forwardEvent(event);
- }
void inputMethodEvent(QInputMethodEvent *event) override
{
m_client->forwardEvent(event);
@@ -309,12 +301,6 @@ QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer()
return renderContext->sceneGraphContext()->createLayer(renderContext);
}
-QSGInternalImageNode *RenderWidgetHostViewQtDelegateWidget::createInternalImageNode()
-{
- QSGRenderContext *renderContext = QQuickWindowPrivate::get(quickWindow())->context;
- return renderContext->sceneGraphContext()->createInternalImageNode();
-}
-
QSGImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode()
{
return quickWindow()->createImageNode();
@@ -479,7 +465,7 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event)
// where we can simply ignore the DblClick event.
QMouseEvent *dblClick = static_cast<QMouseEvent *>(event);
QMouseEvent press(QEvent::MouseButtonPress, dblClick->localPos(), dblClick->windowPos(), dblClick->screenPos(),
- dblClick->button(), dblClick->buttons(), dblClick->modifiers());
+ dblClick->button(), dblClick->buttons(), dblClick->modifiers(), dblClick->source());
press.setTimestamp(dblClick->timestamp());
handled = m_client->forwardEvent(&press);
} else
@@ -487,6 +473,8 @@ 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;
}
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 7746c4405..18f848da5 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h
@@ -78,7 +78,6 @@ public:
QWindow* window() const override;
QSGTexture *createTextureFromImage(const QImage &) override;
QSGLayer *createLayer() override;
- QSGInternalImageNode *createInternalImageNode() override;
QSGImageNode *createImageNode() override;
QSGRectangleNode *createRectangleNode() override;
void update() override;
diff --git a/tests/auto/quick/dialogs/WebView.qml b/tests/auto/quick/dialogs/WebView.qml
index 4f8b7a0ce..01f4ac297 100644
--- a/tests/auto/quick/dialogs/WebView.qml
+++ b/tests/auto/quick/dialogs/WebView.qml
@@ -56,11 +56,12 @@ Window {
WebEngineView {
id: view
anchors.fill: parent
- onLoadingChanged: function(reqeust) {
- if (reqeust.status === WebEngineView.LoadSucceededStatus) {
+ onLoadingChanged: function(request) {
+ if (request.status === WebEngineView.LoadSucceededStatus) {
handler.ready = true
- } else {
- console.log("Wooohooo loading page from qrc failed !")
+ } else if (request.status === WebEngineView.LoadFailedStatus) {
+ console.log("Page was not successfully loaded from qrc! Status: " + request.status
+ + ", error [code: " + request.errorCode + "]: '" + request.errorString + "'")
}
}
diff --git a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp
index 8e23e86e8..922c7769e 100644
--- a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp
+++ b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp
@@ -167,7 +167,7 @@ void tst_InspectorServer::openRemoteDebuggingSession()
// - The page list didn't return a valid inspector URL
// - Or the front-end couldn't be loaded through the inspector HTTP server
// - Or the web socket connection couldn't be established between the front-end and the page through the inspector server
- QTRY_VERIFY(inspectorWebView->title().startsWith("DevTools -"));
+ QTRY_VERIFY_WITH_TIMEOUT(inspectorWebView->title().startsWith("DevTools -"), 20000);
}
QTEST_MAIN(tst_InspectorServer)
diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST
index 0a71e9f27..46bc65923 100644
--- a/tests/auto/quick/qmltests/BLACKLIST
+++ b/tests/auto/quick/qmltests/BLACKLIST
@@ -1,7 +1,2 @@
-[WebViewFindText::test_findTextInterruptedByLoad]
-linux
-qemu
-b2qt
-windows
[WebEngineViewSource::test_viewSourceURL]
*
diff --git a/tests/auto/quick/qmltests/data/tst_findText.qml b/tests/auto/quick/qmltests/data/tst_findText.qml
index 1ec574fae..14053a675 100644
--- a/tests/auto/quick/qmltests/data/tst_findText.qml
+++ b/tests/auto/quick/qmltests/data/tst_findText.qml
@@ -43,13 +43,21 @@ TestWebEngineView {
matchCount = -1
}
+ function findCallbackCalled() { return matchCount != -1 }
+
function findTextCallback(matchCount) {
+ // If this starts to fail then either clear was not called before findText
+ // or unexpected callback was triggered from some search.
+ // On c++ side callback id can be checked to verify
+ testcase.verify(!findCallbackCalled(), 'Unexpected callback call or uncleared state before findText call!')
+
webEngineView.matchCount = matchCount
findFailed = matchCount == 0
}
TestCase {
+ id: testcase
name: "WebViewFindText"
function getBodyInnerHTML() {
@@ -207,13 +215,17 @@ TestWebEngineView {
webEngineView.findText("hello", findFlags, webEngineView.findTextCallback);
// This should not crash.
- webEngineView.url = "https://www.qt.io";
- if (!webEngineView.waitForLoadSucceeded(12000))
- skip("Couldn't load page from network, skipping test.");
+ webEngineView.loadHtml("<html><body>New page with same hello text</body></html>")
+ verify(webEngineView.waitForLoadSucceeded())
// The callback is not supposed to be called, see QTBUG-61506.
- // Check whether the callback was called (-1 = no, other values = yes).
- tryVerify(function() { return webEngineView.matchCount == -1; }, 20000);
+ expectFailContinue('', 'No unexpected findText callback calls occurred.')
+ tryVerify(function() { return webEngineView.findCallbackCalled() })
+ verify(!webEngineView.findCallbackCalled())
+
+ webEngineView.clear();
+ webEngineView.findText('New page', findFlags, webEngineView.findTextCallback)
+ tryCompare(webEngineView, 'matchCount', 1)
}
}
}
diff --git a/tests/auto/widgets/origins/resources/redirect.css b/tests/auto/widgets/origins/resources/redirect.css
new file mode 100644
index 000000000..41d7560cc
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/redirect.css
@@ -0,0 +1,8 @@
+@font-face {
+ font-family: 'MyWebFont';
+ src: url('redirect1:/resources/Akronim-Regular.woff2') format('woff2');
+}
+
+body {
+ font-family: 'MyWebFont', Fallback, sans-serif;
+}
diff --git a/tests/auto/widgets/origins/resources/redirect.html b/tests/auto/widgets/origins/resources/redirect.html
new file mode 100644
index 000000000..04948e14b
--- /dev/null
+++ b/tests/auto/widgets/origins/resources/redirect.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>redirect</title>
+ <link rel="stylesheet" href="redirect1:/resources/redirect.css">
+ </head>
+ <body>
+ Text
+ </body>
+</html>
diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp
index c1307c5e6..02d5bfba3 100644
--- a/tests/auto/widgets/origins/tst_origins.cpp
+++ b/tests/auto/widgets/origins/tst_origins.cpp
@@ -122,6 +122,18 @@ void registerSchemes()
scheme.setDefaultPort(42);
QWebEngineUrlScheme::registerScheme(scheme);
}
+
+ {
+ QWebEngineUrlScheme scheme(QBAL("redirect1"));
+ scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
+ QWebEngineUrlScheme::registerScheme(scheme);
+ }
+
+ {
+ QWebEngineUrlScheme scheme(QBAL("redirect2"));
+ scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
+ QWebEngineUrlScheme::registerScheme(scheme);
+ }
}
Q_CONSTRUCTOR_FUNCTION(registerSchemes)
@@ -145,13 +157,26 @@ public:
profile->installUrlSchemeHandler(QBAL("HostSyntax-ContentSecurityPolicyIgnored"), this);
profile->installUrlSchemeHandler(QBAL("HostAndPortSyntax"), this);
profile->installUrlSchemeHandler(QBAL("HostPortAndUserInformationSyntax"), this);
+ profile->installUrlSchemeHandler(QBAL("redirect1"), this);
+ profile->installUrlSchemeHandler(QBAL("redirect2"), this);
}
+ QVector<QUrl> &requests() { return m_requests; }
+
private:
void requestStarted(QWebEngineUrlRequestJob *job) override
{
+ QUrl url = job->requestUrl();
+ m_requests << url;
+
+ if (url.scheme() == QBAL("redirect1")) {
+ url.setScheme(QBAL("redirect2"));
+ job->redirect(url);
+ return;
+ }
+
QString pathPrefix = QSL(THIS_DIR);
- QString pathSuffix = job->requestUrl().path();
+ QString pathSuffix = url.path();
QFile *file = new QFile(pathPrefix + pathSuffix, job);
if (!file->open(QIODevice::ReadOnly)) {
job->fail(QWebEngineUrlRequestJob::RequestFailed);
@@ -160,8 +185,12 @@ private:
QByteArray mimeType = QBAL("text/html");
if (pathSuffix.endsWith(QSL(".js")))
mimeType = QBAL("application/javascript");
+ else if (pathSuffix.endsWith(QSL(".css")))
+ mimeType = QBAL("text/css");
job->reply(mimeType, file);
}
+
+ QVector<QUrl> m_requests;
};
class tst_Origins final : public QObject {
@@ -169,6 +198,7 @@ class tst_Origins final : public QObject {
private Q_SLOTS:
void initTestCase();
+ void cleanup();
void cleanupTestCase();
void jsUrlCanon();
@@ -187,6 +217,7 @@ private Q_SLOTS:
void serviceWorker();
void viewSource();
void createObjectURL();
+ void redirect();
private:
bool load(const QUrl &url)
@@ -209,10 +240,19 @@ private:
void tst_Origins::initTestCase()
{
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ QRegularExpression("Please register the custom scheme 'tst'.*"));
+
m_page = new QWebEnginePage(&m_profile, nullptr);
m_handler = new TstUrlSchemeHandler(&m_profile);
}
+void tst_Origins::cleanup()
+{
+ m_handler->requests().clear();
+}
+
void tst_Origins::cleanupTestCase()
{
delete m_handler;
@@ -346,11 +386,7 @@ void tst_Origins::jsUrlOrigin()
QCOMPARE(eval(QSL("new URL(\"file:/etc/passwd\").origin")), QVariant(QSL("file://")));
QCOMPARE(eval(QSL("new URL(\"file://foo.com/etc/passwd\").origin")), QVariant(QSL("file://")));
- // The qrc scheme should behave like file.
- QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc://")));
- QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc://")));
-
- // Unregistered schemes behaves like opaque origins.
+ // Unregistered schemes behave like file.
QCOMPARE(eval(QSL("new URL(\"tst:/banana\").origin")), QVariant(QSL("tst://")));
QCOMPARE(eval(QSL("new URL(\"tst://foo.com/banana\").origin")), QVariant(QSL("tst://")));
@@ -367,8 +403,9 @@ void tst_Origins::jsUrlOrigin()
QVariant(QSL("hostportanduserinformationsyntax://foo")));
// A PathSyntax scheme should have a 'universal' origin.
- QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")),
- QVariant(QSL("pathsyntax://")));
+ QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")), QVariant(QSL("pathsyntax:")));
+ QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc:")));
+ QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc:")));
// The NoAccessAllowed flag forces opaque origins.
QCOMPARE(eval(QSL("new URL(\"PathSyntax-NoAccessAllowed:foo\").origin")),
@@ -709,7 +746,7 @@ void tst_Origins::serviceWorker()
QVERIFY(load(QSL("qrc:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('qrc://') is not supported.")));
+ .contains(QSL("The URL protocol of the current origin ('qrc:') is not supported.")));
QVERIFY(load(QSL("tst:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
@@ -724,7 +761,7 @@ void tst_Origins::serviceWorker()
QVERIFY(load(QSL("PathSyntax-Secure:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
QVERIFY(eval(QSL("error")).toString()
- .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure://') is not supported.")));
+ .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure:') is not supported.")));
QVERIFY(load(QSL("PathSyntax-ServiceWorkersAllowed:/resources/serviceWorker.html")));
QTRY_VERIFY(eval(QSL("done")).toBool());
@@ -775,5 +812,18 @@ void tst_Origins::createObjectURL()
QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:tst:")));
}
+void tst_Origins::redirect()
+{
+ QVERIFY(load(QSL("redirect1:/resources/redirect.html")));
+ QTRY_COMPARE(m_handler->requests().size(), 7);
+ QCOMPARE(m_handler->requests()[0], QUrl(QStringLiteral("redirect1:/resources/redirect.html")));
+ QCOMPARE(m_handler->requests()[1], QUrl(QStringLiteral("redirect2:/resources/redirect.html")));
+ QCOMPARE(m_handler->requests()[2], QUrl(QStringLiteral("redirect1:/resources/redirect.css")));
+ QCOMPARE(m_handler->requests()[3], QUrl(QStringLiteral("redirect2:/resources/redirect.css")));
+ QCOMPARE(m_handler->requests()[4], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2")));
+ QCOMPARE(m_handler->requests()[5], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2")));
+ QCOMPARE(m_handler->requests()[6], QUrl(QStringLiteral("redirect2:/resources/Akronim-Regular.woff2")));
+}
+
QTEST_MAIN(tst_Origins)
#include "tst_origins.moc"
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 27f2a9c2b..713feca6d 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -220,6 +220,8 @@ private Q_SLOTS:
void editActionsWithFocusOnIframe();
void editActionsWithoutSelection();
+ void customUserAgentInNewTab();
+
private:
static QPoint elementCenter(QWebEnginePage *page, const QString &id);
@@ -932,6 +934,7 @@ void tst_QWebEnginePage::findText()
QTRY_COMPARE(loadSpy.count(), 1);
// Select whole page contents.
+ QTRY_VERIFY(m_view->page()->action(QWebEnginePage::SelectAll)->isEnabled());
m_view->page()->triggerAction(QWebEnginePage::SelectAll);
QTRY_COMPARE(m_view->hasSelection(), true);
@@ -1709,12 +1712,15 @@ void tst_QWebEnginePage::runJavaScriptFromSlot()
{
QWebEngineProfile profile;
QWebEnginePage page(&profile);
+ page.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished);
page.setHtml("<html><body>"
" <input type='text' id='input1' value='QtWebEngine' size='50' />"
"</body></html>");
QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ // Workaround for QTBUG-74718
+ QTRY_VERIFY(page.action(QWebEnginePage::SelectAll)->isEnabled());
QVariant result(-1);
connect(&page, &QWebEnginePage::selectionChanged, [&]() {
@@ -4180,6 +4186,69 @@ void tst_QWebEnginePage::editActionsWithoutSelection()
QVERIFY(page->action(QWebEnginePage::Unselect)->isEnabled());
}
+void tst_QWebEnginePage::customUserAgentInNewTab()
+{
+ HttpServer server;
+ QByteArray lastUserAgent;
+ connect(&server, &HttpServer::newRequest, [&](HttpReqRep *rr) {
+ QCOMPARE(rr->requestMethod(), "GET");
+ lastUserAgent = rr->requestHeader("user-agent");
+ rr->setResponseBody(QByteArrayLiteral("<html><body>Test</body></html>"));
+ rr->sendResponse();
+ });
+ QVERIFY(server.start());
+
+ class Page : public QWebEnginePage {
+ public:
+ QWebEngineProfile *targetProfile = nullptr;
+ QScopedPointer<QWebEnginePage> newPage;
+ Page(QWebEngineProfile *profile) : QWebEnginePage(profile) {}
+ private:
+ QWebEnginePage *createWindow(WebWindowType) override
+ {
+ newPage.reset(new QWebEnginePage(targetProfile ? targetProfile : profile(), nullptr));
+ return newPage.data();
+ }
+ };
+ QWebEngineProfile profile1, profile2;
+ profile1.setHttpUserAgent(QStringLiteral("custom 1"));
+ profile2.setHttpUserAgent(QStringLiteral("custom 2"));
+ Page page(&profile1);
+ QWebEngineView view;
+ view.resize(500, 500);
+ view.setPage(&page);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QSignalSpy spy(&page, &QWebEnginePage::loadFinished);
+
+ // First check we can get the user-agent passed through normally
+ page.setHtml(QString("<html><body><a id='link' target='_blank' href='") +
+ server.url("/test1").toEncoded() +
+ QString("'>link</a></body></html>"));
+ QTRY_COMPARE(spy.count(), 1);
+ QVERIFY(spy.takeFirst().value(0).toBool());
+ QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), profile1.httpUserAgent());
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, elementCenter(&page, "link"));
+ QTRY_VERIFY(page.newPage);
+ QTRY_VERIFY(!lastUserAgent.isEmpty());
+ QCOMPARE(lastUserAgent, profile1.httpUserAgent().toUtf8());
+
+ // Now check we can get the new user-agent of the profile
+ page.newPage.reset();
+ page.targetProfile = &profile2;
+ spy.clear();
+ lastUserAgent = { };
+ page.setHtml(QString("<html><body><a id='link' target='_blank' href='") +
+ server.url("/test2").toEncoded() +
+ QString("'>link</a></body></html>"));
+ QTRY_COMPARE(spy.count(), 1);
+ QVERIFY(spy.takeFirst().value(0).toBool());
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, elementCenter(&page, "link"));
+ QTRY_VERIFY(page.newPage);
+ QTRY_VERIFY(!lastUserAgent.isEmpty());
+ QCOMPARE(lastUserAgent, profile2.httpUserAgent().toUtf8());
+}
+
static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")};
W_QTEST_MAIN(tst_QWebEnginePage, params)
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 4334498b9..fa179f2f8 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -1829,11 +1829,14 @@ void tst_QWebEngineView::softwareInputPanel()
void tst_QWebEngineView::inputContextQueryInput()
{
- TestInputContext testContext;
QWebEngineView view;
view.resize(640, 480);
view.show();
+ // testContext will be destroyed before the view, so no events are sent accidentally
+ // when the view is destroyed.
+ TestInputContext testContext;
+
QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged()));
QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool)));
view.setHtml("<html><body>"
@@ -1891,7 +1894,7 @@ void tst_QWebEngineView::inputContextQueryInput()
QApplication::sendEvent(view.focusProxy(), &event);
}
QTRY_COMPARE(testContext.infos.count(), 2);
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
// As a first step, Chromium moves the cursor to the start of the selection.
// We don't filter this in QtWebEngine because we don't know yet if this is part of a selection.
@@ -1917,7 +1920,7 @@ void tst_QWebEngineView::inputContextQueryInput()
QApplication::sendEvent(view.focusProxy(), &event);
}
QTRY_COMPARE(testContext.infos.count(), 1);
- QCOMPARE(selectionChangedSpy.count(), 1);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
QCOMPARE(testContext.infos[0].cursorPosition, 0);
QCOMPARE(testContext.infos[0].anchorPosition, 0);
QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!"));
diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
index b6582083d..64df05d89 100644
--- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
+++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
@@ -72,10 +72,7 @@ class tst_Spellchecking : public QObject
private Q_SLOTS:
void init();
void cleanup();
- void initTestCase();
- void spellCheckLanguage();
- void spellCheckLanguages();
- void spellCheckEnabled();
+ void settings();
void spellcheck();
void spellcheck_data();
@@ -84,19 +81,8 @@ private:
WebView *m_view;
};
-void tst_Spellchecking::initTestCase()
-{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- QVERIFY(!profile->isSpellCheckEnabled());
- QVERIFY(profile->spellCheckLanguages().isEmpty());
-}
-
void tst_Spellchecking::init()
{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- profile->setSpellCheckEnabled(false);
- profile->setSpellCheckLanguages(QStringList());
m_view = new WebView();
}
@@ -106,7 +92,6 @@ void tst_Spellchecking::load()
m_view->show();
QSignalSpy spyFinished(m_view->page(), &QWebEnginePage::loadFinished);
QVERIFY(spyFinished.wait());
-
}
void tst_Spellchecking::cleanup()
@@ -114,29 +99,57 @@ void tst_Spellchecking::cleanup()
delete m_view;
}
-void tst_Spellchecking::spellCheckLanguage()
+void tst_Spellchecking::settings()
{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- profile->setSpellCheckLanguages({"en-US"});
- QVERIFY(profile->spellCheckLanguages() == QStringList({"en-US"}));
-}
+ // Default profile has spellchecking disabled
-void tst_Spellchecking::spellCheckLanguages()
-{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- profile->setSpellCheckLanguages({"en-US","de-DE"});
- QVERIFY(profile->spellCheckLanguages() == QStringList({"en-US","de-DE"}));
-}
+ QVERIFY(!QWebEngineProfile::defaultProfile()->isSpellCheckEnabled());
+ QVERIFY(QWebEngineProfile::defaultProfile()->spellCheckLanguages().isEmpty());
+ // New named profiles have spellchecking disabled
-void tst_Spellchecking::spellCheckEnabled()
-{
- QWebEngineProfile *profile = QWebEngineProfile::defaultProfile();
- QVERIFY(profile);
- profile->setSpellCheckEnabled(true);
- QVERIFY(profile->isSpellCheckEnabled());
+ auto profile1 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile1"));
+ QVERIFY(!profile1->isSpellCheckEnabled());
+ QVERIFY(profile1->spellCheckLanguages().isEmpty());
+
+ auto profile2 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile2"));
+ QVERIFY(!profile2->isSpellCheckEnabled());
+ QVERIFY(profile2->spellCheckLanguages().isEmpty());
+
+ // New otr profiles have spellchecking disabled
+
+ auto profile3 = std::make_unique<QWebEngineProfile>();
+ QVERIFY(!profile2->isSpellCheckEnabled());
+ QVERIFY(profile2->spellCheckLanguages().isEmpty());
+
+ // Settings can be changed
+
+ profile1->setSpellCheckEnabled(true);
+ QVERIFY(profile1->isSpellCheckEnabled());
+
+ profile1->setSpellCheckLanguages({"en-US"});
+ QVERIFY(profile1->spellCheckLanguages() == QStringList({"en-US"}));
+
+ profile1->setSpellCheckLanguages({"en-US","de-DE"});
+ QVERIFY(profile1->spellCheckLanguages() == QStringList({"en-US","de-DE"}));
+
+ // Settings are per profile
+
+ QVERIFY(!profile2->isSpellCheckEnabled());
+ QVERIFY(profile2->spellCheckLanguages().isEmpty());
+
+ QVERIFY(!profile3->isSpellCheckEnabled());
+ QVERIFY(profile3->spellCheckLanguages().isEmpty());
+
+ // Settings are not persisted
+
+ // TODO(juvaldma): Write from dtor currently usually happens *after* the
+ // read from the ctor, so this test would pass even if settings were
+ // persisted. It would start to fail on the second run though.
+ profile1.reset();
+ profile1 = std::make_unique<QWebEngineProfile>(QStringLiteral("Profile1"));
+ QVERIFY(!profile1->isSpellCheckEnabled());
+ QVERIFY(profile1->spellCheckLanguages().isEmpty());
}
void tst_Spellchecking::spellcheck()
@@ -174,14 +187,41 @@ void tst_Spellchecking::spellcheck()
QString result = evaluateJavaScriptSync(m_view->page(), "text();").toString();
QVERIFY(result == text);
- // open menu on misspelled word
- m_view->activateMenu(m_view->focusWidget(), rect.center());
- QSignalSpy spyMenuReady(m_view, &WebView::menuReady);
- QVERIFY(spyMenuReady.wait());
-
- // check if menu is valid
- QVERIFY(m_view->data().isValid());
- QVERIFY(m_view->data().isContentEditable());
+ bool gotMisspelledWord = false; // clumsy QTRY_VERIFY still execs expr after first success
+ QString detail;
+
+ // check that spellchecker has done text processing and filled misspelled word
+ QTRY_VERIFY2([&] () {
+ detail.clear();
+ if (gotMisspelledWord)
+ return true;
+
+ // open menu on misspelled word
+ m_view->activateMenu(m_view->focusWidget(), rect.center());
+ QSignalSpy spyMenuReady(m_view, &WebView::menuReady);
+ if (!spyMenuReady.wait()) {
+ detail = "menu was not shown";
+ return false;
+ }
+
+ if (!m_view->data().isValid()) {
+ detail = "invalid data";
+ return false;
+ }
+
+ if (!m_view->data().isContentEditable()) {
+ detail = "content is not editable";
+ return false;
+ }
+
+ if (m_view->data().misspelledWord().isEmpty()) {
+ detail = "no misspelled word";
+ return false;
+ };
+
+ gotMisspelledWord = true;
+ return true;
+ } (), qPrintable(QString("Context menu: %1").arg(detail)));
// check misspelled word
QCOMPARE(m_view->data().misspelledWord(), QStringLiteral("lowe"));