diff options
Diffstat (limited to 'src/core')
123 files changed, 11820 insertions, 3234 deletions
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index 2ddd0d69f..7b0c3eb0c 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -1,10 +1,15 @@ +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) +QT_FOR_CONFIG += webenginecore webenginecore-private + TARGET = qtwebenginecoreapi$$qtPlatformTargetSuffix() DESTDIR = $$OUT_PWD/$$getConfigDir() TEMPLATE = lib CONFIG += staticlib -QT += network core-private webenginecoreheaders-private +QT += network core-private webenginecoreheaders-private quick qml + +qtConfig(webengine-printing-and-pdf): QT += printsupport # Don't create .prl file for this intermediate library because # their contents get used when linking against them, breaking @@ -37,9 +42,11 @@ HEADERS = \ qwebengineclientcertificatestore.h \ qtwebenginecoreglobal.h \ qtwebenginecoreglobal_p.h \ + qwebenginecertificateerror.h \ qwebenginecookiestore.h \ qwebenginecookiestore_p.h \ qwebenginefindtextresult.h \ + qwebenginefullscreenrequest.h \ qwebenginehttprequest.h \ qwebenginemessagepumpscheduler_p.h \ qwebenginenotification.h \ @@ -50,13 +57,31 @@ HEADERS = \ qwebengineurlrequestinfo_p.h \ qwebengineurlrequestjob.h \ qwebengineurlscheme.h \ - qwebengineurlschemehandler.h + qwebengineurlschemehandler.h \ + qwebenginecontextmenurequest.h \ + qwebenginecontextmenurequest_p.h \ + qwebenginedownloadrequest.h \ + qwebenginedownloadrequest_p.h \ + qwebengineloadrequest.h \ + qwebenginesettings.h \ + qwebenginescript.h \ + qwebenginescriptcollection.h \ + qwebenginescriptcollection_p.h \ + qwebengineprofile.h \ + qwebengineprofile_p.h \ + qwebengineclientcertificateselection.h \ + qwebenginehistory.h \ + qwebenginehistory_p.h \ + qwebenginepage.h \ + qwebenginepage_p.h SOURCES = \ qtwebenginecoreglobal.cpp \ + qwebenginecertificateerror.cpp \ qwebengineclientcertificatestore.cpp \ qwebenginecookiestore.cpp \ qwebenginefindtextresult.cpp \ + qwebenginefullscreenrequest.cpp \ qwebenginehttprequest.cpp \ qwebenginemessagepumpscheduler.cpp \ qwebenginenotification.cpp \ @@ -65,13 +90,17 @@ SOURCES = \ qwebengineurlrequestinfo.cpp \ qwebengineurlrequestjob.cpp \ qwebengineurlscheme.cpp \ - qwebengineurlschemehandler.cpp - -### Qt6 Remove this workaround -unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static { - SOURCES += qtbug-60565.cpp \ - qtbug-61521.cpp -} + qwebengineurlschemehandler.cpp \ + qwebenginecontextmenurequest.cpp \ + qwebenginedownloadrequest.cpp \ + qwebengineloadrequest.cpp \ + qwebenginesettings.cpp \ + qwebenginescript.cpp \ + qwebenginescriptcollection.cpp \ + qwebengineprofile.cpp \ + qwebengineclientcertificateselection.cpp \ + qwebenginehistory.cpp \ + qwebenginepage.cpp # Chromium headers included are not remotely clean CONFIG -= warning_clean diff --git a/src/core/api/qtbug-60565.cpp b/src/core/api/qtbug-60565.cpp deleted file mode 100644 index f48a2a701..000000000 --- a/src/core/api/qtbug-60565.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <new> -#include <unistd.h> - -#if defined(__LP64__) -# define SIZE_T_MANGLING "m" -#else -# define SIZE_T_MANGLING "j" -#endif - -#define SHIM_ALIAS_SYMBOL(fn) __attribute__((weak, alias(#fn))) -#define SHIM_HIDDEN __attribute__ ((visibility ("hidden"))) - -extern "C" { - -__asm__(".symver __ShimCppNew, _Znw" SIZE_T_MANGLING "@Qt_5"); -void* __ShimCppNew(size_t size) - SHIM_ALIAS_SYMBOL(ShimCppNew); - -__asm__(".symver __ShimCppDelete, _ZdlPv@Qt_5"); -void __ShimCppDelete(void* address) - SHIM_ALIAS_SYMBOL(ShimCppDelete); - -__asm__(".symver __ShimCppNewArray, _Zna" SIZE_T_MANGLING "@Qt_5"); -void* __ShimCppNewArray(size_t size) - SHIM_ALIAS_SYMBOL(ShimCppNewArray); - -__asm__(".symver __ShimCppDeleteArray, _ZdaPv@Qt_5"); -void __ShimCppDeleteArray(void* address) - SHIM_ALIAS_SYMBOL(ShimCppDeleteArray); - -__asm__(".symver __ShimCppNewNoThrow, _Znw" SIZE_T_MANGLING "RKSt9nothrow_t@Qt_5"); -void *__ShimCppNewNoThrow(size_t size, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppNewNoThrow); - -__asm__(".symver __ShimCppNewArrayNoThrow, _Zna" SIZE_T_MANGLING "RKSt9nothrow_t@Qt_5"); -void *__ShimCppNewArrayNoThrow(size_t size, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppNewArrayNoThrow); - -__asm__(".symver __ShimCppDeleteNoThrow, _ZdlPvRKSt9nothrow_t@Qt_5"); -void __ShimCppDeleteNoThrow(void* address, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppDeleteNoThrow); - -__asm__(".symver __ShimCppDeleteArrayNoThrow, _ZdaPvRKSt9nothrow_t@Qt_5"); -void __ShimCppDeleteArrayNoThrow(void* address, const std::nothrow_t&) noexcept - SHIM_ALIAS_SYMBOL(ShimCppDeleteArrayNoThrow); - -static void* __shimCppNew(size_t size); -static void* __shimCppNewArray(size_t size); -static void __shimCppDelete(void *address); -static void __shimCppDeleteArray(void *address); - -SHIM_HIDDEN void* ShimCppNew(size_t size) { - return __shimCppNew(size); -} - -SHIM_HIDDEN void* ShimCppNewNoThrow(size_t size, const std::nothrow_t&) noexcept { - return __shimCppNew(size); -} - -SHIM_HIDDEN void* ShimCppNewArray(size_t size) { - return __shimCppNewArray(size); -} - -SHIM_HIDDEN void* ShimCppNewArrayNoThrow(size_t size, const std::nothrow_t&) noexcept { - return __shimCppNewArray(size); -} - -SHIM_HIDDEN void ShimCppDelete(void* address) { - __shimCppDelete(address); -} - -SHIM_HIDDEN void ShimCppDeleteNoThrow(void* address, const std::nothrow_t&) noexcept { - __shimCppDelete(address); -} - -SHIM_HIDDEN void ShimCppDeleteArray(void* address) { - __shimCppDeleteArray(address); -} - -SHIM_HIDDEN void ShimCppDeleteArrayNoThrow(void* address, const std::nothrow_t&) noexcept { - __shimCppDeleteArray(address); -} -} // extern "C" - -static void* __shimCppNew(size_t size) { - return operator new(size); -} - -static void* __shimCppNewArray(size_t size) { - return operator new[](size); -} - -static void __shimCppDelete(void* address) { - operator delete(address); -} - -static void __shimCppDeleteArray(void* address) { - operator delete[](address); -} diff --git a/src/core/api/qtbug-61521.cpp b/src/core/api/qtbug-61521.cpp deleted file mode 100644 index 002a1af22..000000000 --- a/src/core/api/qtbug-61521.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <stdlib.h> -#include <malloc.h> - -#define SHIM_ALIAS_SYMBOL(fn) __attribute__((weak, alias(#fn))) -#define SHIM_SYMBOL_VERSION(fn) __asm__(".symver __" #fn "," #fn "@Qt_5") -#define SHIM_HIDDEN __attribute__ ((visibility ("hidden"))) - -extern "C" { - -SHIM_SYMBOL_VERSION(malloc); -void* __malloc(size_t size) - SHIM_ALIAS_SYMBOL(ShimMalloc); - -SHIM_SYMBOL_VERSION(free); -void __free(void* ptr) - SHIM_ALIAS_SYMBOL(ShimFree); - -SHIM_SYMBOL_VERSION(realloc); -void* __realloc(void* ptr, size_t size) - SHIM_ALIAS_SYMBOL(ShimRealloc); - -SHIM_SYMBOL_VERSION(calloc); -void* __calloc(size_t n, size_t size) - SHIM_ALIAS_SYMBOL(ShimCalloc); - -SHIM_SYMBOL_VERSION(cfree); -void __cfree(void* ptr) - SHIM_ALIAS_SYMBOL(ShimCFree); - -SHIM_SYMBOL_VERSION(memalign); -void* __memalign(size_t align, size_t s) - SHIM_ALIAS_SYMBOL(ShimMemalign); - -SHIM_SYMBOL_VERSION(valloc); -void* __valloc(size_t size) - SHIM_ALIAS_SYMBOL(ShimValloc); - -SHIM_SYMBOL_VERSION(pvalloc); -void* __pvalloc(size_t size) - SHIM_ALIAS_SYMBOL(ShimPvalloc); - -SHIM_SYMBOL_VERSION(posix_memalign); -int __posix_memalign(void** r, size_t a, size_t s) - SHIM_ALIAS_SYMBOL(ShimPosixMemalign); - -SHIM_HIDDEN void* ShimMalloc(size_t size) { - return malloc(size); -} - -SHIM_HIDDEN void ShimFree(void* ptr) { - free(ptr); -} - -SHIM_HIDDEN void* ShimRealloc(void* ptr, size_t size) { - return realloc(ptr,size); -} - -SHIM_HIDDEN void* ShimCalloc(size_t n, size_t size) { - return calloc(n,size); -} - -SHIM_HIDDEN void ShimCFree(void* ptr) { - free(ptr); -} - -SHIM_HIDDEN void* ShimMemalign(size_t align, size_t s) { - return memalign(align,s); -} - -SHIM_HIDDEN void* ShimValloc(size_t size) { - return valloc(size); -} - -SHIM_HIDDEN void* ShimPvalloc(size_t size) { - return pvalloc(size); -} - -SHIM_HIDDEN int ShimPosixMemalign(void** r, size_t a, size_t s) { - return posix_memalign(r,a,s); -} -} // extern "C" diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index 3c9387a10..e6a551e65 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -50,6 +50,7 @@ #endif #endif #include <QThread> +#include <QQuickWindow> #if QT_CONFIG(opengl) QT_BEGIN_NAMESPACE @@ -105,83 +106,125 @@ Q_WEBENGINECORE_PRIVATE_EXPORT void initialize() qputenv("QT_MAC_PRO_WEBENGINE_WORKAROUND", "1"); #endif // No need to override the shared context if QApplication already set one (e.g with Qt::AA_ShareOpenGLContexts). - if (qt_gl_global_share_context()) - return; + if (!qt_gl_global_share_context()) { - QCoreApplication *app = QCoreApplication::instance(); - if (!app) { - qFatal("QtWebEngine::initialize() but no core application instance."); - return; - } - - // Bail out silently if the user did not construct a QGuiApplication. - if (!qobject_cast<QGuiApplication *>(app)) - return; - - if (app->thread() != QThread::currentThread()) { - qFatal("QtWebEngine::initialize() must be called from the Qt gui thread."); - return; - } + QCoreApplication *app = QCoreApplication::instance(); + if (!app) { + qFatal("QtWebEngine::initialize() but no core application instance."); + return; + } - if (shareContext) - return; + // Bail out silently if the user did not construct a QGuiApplication. + if (!qobject_cast<QGuiApplication *>(app)) + return; - shareContext = new QOpenGLContext; - QSurfaceFormat format = QSurfaceFormat::defaultFormat(); -// format.setOption(QSurfaceFormat::ResetNotification); + if (app->thread() != QThread::currentThread()) { + qFatal("QtWebEngine::initialize() must be called from the Qt gui thread."); + return; + } -#ifdef Q_OS_MACOS - if (format == QSurfaceFormat()) { - QOpenGLContext testContext; - - // Chromium turns off OpenGL for CoreProfiles with versions < 4.1 - // The newest Mac that only supports 3.3 was released in Mid 2011, - // so it should be safe to request 4.1, but we still double check it - // works in order not to set an invalid default surface format. - format.setVersion(4, 1); - format.setProfile(QSurfaceFormat::CoreProfile); - - testContext.setFormat(format); - if (testContext.create()) { - QOffscreenSurface surface; - surface.setFormat(format); - surface.create(); - - if (testContext.makeCurrent(&surface)) { - // The Cocoa QPA integration allows sharing between OpenGL 3.2 and 4.1 contexts, - // which means even though we requested a 4.1 context, if we only get a 3.2 context, - // it will still work an Chromium will not black list it. - if (testContext.format().version() >= qMakePair(3, 2) && - testContext.format().profile() == QSurfaceFormat::CoreProfile && - !isCurrentContextSoftware()) { - QSurfaceFormat::setDefaultFormat(format); - } else { - qWarning("The available OpenGL surface format was either not version 3.2 or higher or not a Core Profile.\n" - "Chromium on macOS will fall back to software rendering in this case.\n" - "Hardware acceleration and features such as WebGL will not be available."); - format = QSurfaceFormat::defaultFormat(); - } - testContext.doneCurrent(); + if (shareContext) + return; + + shareContext = new QOpenGLContext; + QSurfaceFormat format = QSurfaceFormat::defaultFormat(); + +#if defined(Q_OS_MACOS) + if (format == QSurfaceFormat()) { + QOpenGLContext testContext; + + // Chromium turns off OpenGL for CoreProfiles with versions < 4.1 + // The newest Mac that only supports 3.3 was released in Mid 2011, + // so it should be safe to request 4.1, but we still double check it + // works in order not to set an invalid default surface format. + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::CoreProfile); + + testContext.setFormat(format); + if (testContext.create()) { + QOffscreenSurface surface; + surface.setFormat(format); + surface.create(); + + if (testContext.makeCurrent(&surface)) { + // The Cocoa QPA integration allows sharing between OpenGL 3.2 and 4.1 contexts, + // which means even though we requested a 4.1 context, if we only get a 3.2 + // context, it will still work an Chromium will not black list it. + if (testContext.format().version() >= qMakePair(3, 2) + && testContext.format().profile() == QSurfaceFormat::CoreProfile + && !isCurrentContextSoftware()) { + QSurfaceFormat::setDefaultFormat(format); + } else { + qWarning("The available OpenGL surface format was either not version 3.2 " + "or higher or not a Core Profile.\n" + "Chromium on macOS will fall back to software rendering in this " + "case.\n" + "Hardware acceleration and features such as WebGL will not be " + "available."); + format = QSurfaceFormat::defaultFormat(); + } + testContext.doneCurrent(); + } + surface.destroy(); + } + } else { + // The user explicitly requested a specific surface format that does not fit Chromium's + // requirements. Warn them about this. + if (format.version() < qMakePair(3, 2) + || format.profile() != QSurfaceFormat::CoreProfile) { + qWarning("An OpenGL surfcace format was requested that is either not version 3.2 " + "or higher or a not Core Profile.\n" + "Chromium on macOS will fall back to software rendering in this case.\n" + "Hardware acceleration and features such as WebGL will not be available."); } - surface.destroy(); - } - } else { - // The user explicitly requested a specific surface format that does not fit Chromium's requirements. Warn them about this. - if (format.version() < qMakePair(3,2) || format.profile() != QSurfaceFormat::CoreProfile) { - qWarning("An OpenGL surfcace format was requested that is either not version 3.2 or higher or a not Core Profile.\n" - "Chromium on macOS will fall back to software rendering in this case.\n" - "Hardware acceleration and features such as WebGL will not be available."); } - } #endif - shareContext->setFormat(format); - shareContext->create(); - qAddPostRoutine(deleteShareContext); - qt_gl_set_global_share_context(shareContext); + shareContext->setFormat(format); + shareContext->create(); + qAddPostRoutine(deleteShareContext); + qt_gl_set_global_share_context(shareContext); + + // Classes like QOpenGLWidget check for the attribute + app->setAttribute(Qt::AA_ShareOpenGLContexts); + } + +#if defined(Q_OS_MACOS) + // Check that the default QSurfaceFormat OpenGL profile is compatible with the global OpenGL + // shared context profile, otherwise this could lead to a nasty crash. + QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat(); + + if (defaultFormat.profile() != sharedFormat.profile() + && defaultFormat.profile() == QSurfaceFormat::CoreProfile + && defaultFormat.version() >= qMakePair(3, 2)) { + qFatal("QWebEngine: Default QSurfaceFormat OpenGL profile is not compatible with the " + "global shared context OpenGL profile. Please make sure you set a compatible " + "QSurfaceFormat before the QtGui application instance is created."); + } +#endif - // Classes like QOpenGLWidget check for the attribute - app->setAttribute(Qt::AA_ShareOpenGLContexts); #endif // QT_CONFIG(opengl) } } // namespace QtWebEngineCore + +static void initialize() +{ +#if QT_CONFIG(opengl) + if (QCoreApplication::instance()) { + // On window/ANGLE, calling QtWebEngine::initialize from DllMain will result in a crash. + if (!qt_gl_global_share_context()) { + qWarning("Qt WebEngine seems to be initialized from a plugin. Please " + "set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute and " + "QSGRendererInterface::OpenGLRhi using QQuickWindow::setGraphicsApi " + "before constructing QGuiApplication."); + } + return; + } + // QCoreApplication is not yet instantiated, ensuring the call will be deferred + qAddPreRoutine(QtWebEngineCore::initialize); + QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi); +#endif // QT_CONFIG(opengl) +} + +Q_CONSTRUCTOR_FUNCTION(initialize) diff --git a/src/core/api/qwebenginecallback_p.h b/src/core/api/qwebenginecallback_p.h index 133a86f6d..9cc25b7fd 100644 --- a/src/core/api/qwebenginecallback_p.h +++ b/src/core/api/qwebenginecallback_p.h @@ -244,7 +244,7 @@ inline void CallbackDirectory::CallbackSharedDataPointer<T>::invokeEmpty() parent->invokeEmptyInternal(callback); } -#define CHECK_RELOCATABLE(x) Q_STATIC_ASSERT((QTypeInfoQuery<QWebEngineCallback<x>>::isRelocatable)); +#define CHECK_RELOCATABLE(x) Q_STATIC_ASSERT((QTypeInfo<QWebEngineCallback<x>>::isRelocatable)); FOR_EACH_TYPE(CHECK_RELOCATABLE) #undef CHECK_RELOCATABLE diff --git a/src/core/api/qwebenginecertificateerror.cpp b/src/core/api/qwebenginecertificateerror.cpp new file mode 100644 index 000000000..40c9a1c7b --- /dev/null +++ b/src/core/api/qwebenginecertificateerror.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginecertificateerror.h" + +#include "certificate_error_controller.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineCertificateError + \brief The QWebEngineCertificateError class provides information about a certificate error. + \since 5.4 + \inmodule QtWebEngineCore + + Provides information about a certificate error. This class is used as a parameter of + QWebEnginePage::certificateError(). +*/ + +/*! \internal +*/ +QWebEngineCertificateError::QWebEngineCertificateError( + const QSharedPointer<QtWebEngineCore::CertificateErrorController> &controller) + : d(controller) +{ +} + +QWebEngineCertificateError::QWebEngineCertificateError(const QWebEngineCertificateError &) = default; + +QWebEngineCertificateError& QWebEngineCertificateError::operator=(const QWebEngineCertificateError &) = default; + +/*! \internal +*/ +QWebEngineCertificateError::~QWebEngineCertificateError() = default; + +/*! + \enum QWebEngineCertificateError::Type + + This enum describes the type of certificate error encountered. + + The values of this enum type match the SSL errors Chromium provides. + QSslError::SslError values are not used directly, because the Qt error + categories cannot be mapped to the Chromium error categories. + + \value SslPinnedKeyNotInCertificateChain The certificate did not match the built-in public keys + pinned for the host name. + \value CertificateCommonNameInvalid The certificate's common name did not match the host name. + \value CertificateDateInvalid The certificate is not valid at the current date and time. + \value CertificateAuthorityInvalid The certificate is not signed by a trusted authority. + \value CertificateContainsErrors The certificate contains errors. + \value CertificateNoRevocationMechanism The certificate has no mechanism for determining if it has been revoked. + \value CertificateUnableToCheckRevocation Revocation information for the certificate is not available. + \value CertificateRevoked The certificate has been revoked. + \value CertificateInvalid The certificate is invalid. + \value CertificateWeakSignatureAlgorithm The certificate is signed using a weak signature algorithm. + \value CertificateNonUniqueName The host name specified in the certificate is not unique. + \value CertificateWeakKey The certificate contains a weak key. + \value CertificateNameConstraintViolation The certificate claimed DNS names that are in violation of name constraints. + \value CertificateValidityTooLong The certificate has a validity period that is too long. (Added in Qt 5.7) + \value CertificateTransparencyRequired Certificate Transparency was required for this connection, but the server + did not provide CT information that complied with the policy. (Added in Qt 5.8) + \value CertificateKnownInterceptionBlocked The certificate is known to be + used for interception by an entity other the device owner. (Added in + 5.15) + \value SslObsoleteVersion The connection uses an obsolete version of SSL/TLS. (Added in Qt 6.0) +*/ + +/*! + Returns whether this error can be overridden and accepted. + + \sa error(), description() +*/ +bool QWebEngineCertificateError::isOverridable() const +{ + return d->overridable(); +} + +/*! + Returns the URL that triggered the error. + + \sa error(), description() +*/ +QUrl QWebEngineCertificateError::url() const +{ + return d->url(); +} + +/*! + Returns the type of the error. + + \sa description(), isOverridable() +*/ +QWebEngineCertificateError::Type QWebEngineCertificateError::type() const +{ + return d->error(); +} + +/*! + Returns a short localized human-readable description of the error. + + \sa error(), url(), isOverridable() +*/ +QString QWebEngineCertificateError::description() const +{ + return d->errorString(); +} + +/*! + \since 5.14 + + Marks the certificate error for delayed handling. + + This function should be called when there is a need to postpone the decision whether to accept a + certificate, for example, while waiting for user input. When called, the function pauses the + URL request until acceptCertificate() or rejectCertificate() is called. + + \note It is only possible to defer overridable certificate errors. + + \sa isOverridable(), deferred() +*/ +void QWebEngineCertificateError::defer() +{ + d->defer(); +} + +/*! + \since 5.14 + + Accepts the certificate and continues the loading of the requested URL. +*/ +void QWebEngineCertificateError::acceptCertificate() +{ + d->ignoreCertificateError(); +} + +/*! + \since 5.14 + + Rejects the certificate and aborts the loading of the requested URL. +*/ +void QWebEngineCertificateError::rejectCertificate() +{ + d->rejectCertificate(); +} + +/*! + \since 5.14 + + Returns the peer's chain of digital certificates. + + Chain starts with the peer's immediate certificate and ending with the CA's certificate. +*/ +QList<QSslCertificate> QWebEngineCertificateError::certificateChain() const +{ + return d->certificateChain(); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginecertificateerror.h b/src/core/api/qwebenginecertificateerror.h new file mode 100644 index 000000000..ffcebaf9b --- /dev/null +++ b/src/core/api/qwebenginecertificateerror.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINECERTIFICATEERROR_H +#define QWEBENGINECERTIFICATEERROR_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qsharedpointer.h> +#include <QtCore/qurl.h> +#include <QtNetwork/QSslCertificate> + +namespace QtWebEngineCore { +class WebContentsDelegateQt; +class CertificateErrorController; +} + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_EXPORT QWebEngineCertificateError { + Q_GADGET + Q_PROPERTY(QUrl url READ url CONSTANT FINAL) + Q_PROPERTY(Type type READ type CONSTANT FINAL) + Q_PROPERTY(QString description READ description CONSTANT FINAL) + Q_PROPERTY(bool overridable READ isOverridable CONSTANT FINAL) + +public: + QWebEngineCertificateError(const QWebEngineCertificateError &other); + QWebEngineCertificateError& operator=(const QWebEngineCertificateError &other); + ~QWebEngineCertificateError(); + + // Keep this identical to NET_ERROR in net_error_list.h, or add mapping layer. + enum Type { + SslPinnedKeyNotInCertificateChain = -150, + CertificateCommonNameInvalid = -200, + CertificateDateInvalid = -201, + CertificateAuthorityInvalid = -202, + CertificateContainsErrors = -203, + CertificateNoRevocationMechanism = -204, + CertificateUnableToCheckRevocation = -205, + CertificateRevoked = -206, + CertificateInvalid = -207, + CertificateWeakSignatureAlgorithm = -208, + CertificateNonUniqueName = -210, + CertificateWeakKey = -211, + CertificateNameConstraintViolation = -212, + CertificateValidityTooLong = -213, + CertificateTransparencyRequired = -214, + CertificateSymantecLegacy = -215, + CertificateKnownInterceptionBlocked = -217, + SslObsoleteVersion = -218, + }; + Q_ENUM(Type) + + Type type() const; + QUrl url() const; + bool isOverridable() const; + QString description() const; + + Q_INVOKABLE void defer(); + Q_INVOKABLE void rejectCertificate(); + Q_INVOKABLE void acceptCertificate(); + + QList<QSslCertificate> certificateChain() const; + +private: + friend class QtWebEngineCore::WebContentsDelegateQt; + QWebEngineCertificateError( + const QSharedPointer<QtWebEngineCore::CertificateErrorController> &controller); + QSharedPointer<QtWebEngineCore::CertificateErrorController> d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QWebEngineCertificateError) + +#endif // QWEBENGINECERTIFICATEERROR_H diff --git a/src/core/api/qwebengineclientcertificateselection.cpp b/src/core/api/qwebengineclientcertificateselection.cpp new file mode 100644 index 000000000..febfe0a21 --- /dev/null +++ b/src/core/api/qwebengineclientcertificateselection.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebengineclientcertificateselection.h" +#include "client_cert_select_controller.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineClientCertificateSelection + \brief The QWebEngineClientCertSelection class wraps a client certificate selection. + \since 5.12 + \inmodule QtWebEngineWidgets + + When a web site requests an SSL client certificate, and one or more certificates + are found in the system's client certificate store, this class provides access to + the certificates to choose from, as well as a method for selecting one. + + The selection is asynchronous. If no certificate is selected and no copy of the + object is kept alive, loading will continue without a certificate. + + \sa QWebEnginePage::selectClientCertificate() +*/ + +/*! \internal +*/ +QWebEngineClientCertificateSelection::QWebEngineClientCertificateSelection( + QSharedPointer<QtWebEngineCore::ClientCertSelectController> selectController) + : d_ptr(selectController) +{} + +QWebEngineClientCertificateSelection::QWebEngineClientCertificateSelection(const QWebEngineClientCertificateSelection &other) + : d_ptr(other.d_ptr) +{} + +QWebEngineClientCertificateSelection &QWebEngineClientCertificateSelection::operator=(const QWebEngineClientCertificateSelection &other) +{ + d_ptr = other.d_ptr; + return *this; +} + +QWebEngineClientCertificateSelection::~QWebEngineClientCertificateSelection() +{ +} + +/*! + Returns the client certificates available to choose from. + + \sa select() +*/ +QList<QSslCertificate> QWebEngineClientCertificateSelection::certificates() const +{ + return d_ptr->certificates(); +} + +/*! + Selects the client certificate \a certificate. The certificate must be one + of those offered in certificates(). + + \sa certificates(), selectNone() +*/ +void QWebEngineClientCertificateSelection::select(const QSslCertificate &certificate) +{ + d_ptr->select(certificate); +} + +/*! + Continue without using any of the offered certificates. This is the same + action as taken when destroying the last copy of this object if no + selection has been made. + + \sa select() +*/ +void QWebEngineClientCertificateSelection::selectNone() +{ + d_ptr->selectNone(); +} + +/*! + Returns the host and port of the server requesting the client certificate. +*/ +QUrl QWebEngineClientCertificateSelection::host() const +{ + return d_ptr->hostAndPort(); +} + +QT_END_NAMESPACE + diff --git a/src/core/compositor/display_consumer.h b/src/core/api/qwebengineclientcertificateselection.h index d220088ad..81c626f73 100644 --- a/src/core/compositor/display_consumer.h +++ b/src/core/api/qwebengineclientcertificateselection.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,26 +37,43 @@ ** ****************************************************************************/ -#ifndef DISPLAY_CONSUMER_H -#define DISPLAY_CONSUMER_H +#ifndef QWEBENGINECLIENTCERTSELECTION_H +#define QWEBENGINECLIENTCERTSELECTION_H -#include "qtwebenginecoreglobal_p.h" +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtNetwork/qtnetwork-config.h> +#include <QtCore/qlist.h> +#include <QtCore/qscopedpointer.h> +#include <QtNetwork/qsslcertificate.h> namespace QtWebEngineCore { +class ClientCertSelectController; +} -// Receives composited frames for display. -class DisplayConsumer -{ +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_EXPORT QWebEngineClientCertificateSelection { public: - // Schedule a call to updatePaintNode soon. - // - // Called on the consumer thread. - virtual void scheduleUpdate() = 0; + QWebEngineClientCertificateSelection(const QWebEngineClientCertificateSelection &); + ~QWebEngineClientCertificateSelection(); + + QWebEngineClientCertificateSelection &operator=(const QWebEngineClientCertificateSelection &); + + QUrl host() const; + + void select(const QSslCertificate &certificate); + void selectNone(); + QList<QSslCertificate> certificates() const; + +private: + friend class QWebEnginePagePrivate; + + QWebEngineClientCertificateSelection( + QSharedPointer<QtWebEngineCore::ClientCertSelectController>); -protected: - ~DisplayConsumer() {} + QSharedPointer<QtWebEngineCore::ClientCertSelectController> d_ptr; }; -} // namespace QtWebEngineCore +QT_END_NAMESPACE -#endif // !DISPLAY_CONSUMER_H +#endif // QWEBENGINECLIENTCERTSELECTION_H diff --git a/src/core/api/qwebengineclientcertificatestore.cpp b/src/core/api/qwebengineclientcertificatestore.cpp index 84f273328..462a63b26 100644 --- a/src/core/api/qwebengineclientcertificatestore.cpp +++ b/src/core/api/qwebengineclientcertificatestore.cpp @@ -88,9 +88,9 @@ void QWebEngineClientCertificateStore::add(const QSslCertificate &certificate, c Returns an empty list if the store does not contain any certificates. */ -QVector<QSslCertificate> QWebEngineClientCertificateStore::certificates() const +QList<QSslCertificate> QWebEngineClientCertificateStore::certificates() const { - QVector<QSslCertificate> certificateList; + QList<QSslCertificate> certificateList; for (auto data : qAsConst(m_storeData->extraCerts)) certificateList.append(data->certificate); return certificateList; diff --git a/src/core/api/qwebengineclientcertificatestore.h b/src/core/api/qwebengineclientcertificatestore.h index a4c83bb2e..a9282f0fb 100644 --- a/src/core/api/qwebengineclientcertificatestore.h +++ b/src/core/api/qwebengineclientcertificatestore.h @@ -41,8 +41,10 @@ #define QWEBENGINECLIENTCERTIFICATESTORE_H #include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtNetwork/qtnetwork-config.h> -#include <QtCore/qvector.h> +#if QT_CONFIG(ssl) +#include <QtCore/qlist.h> #include <QtNetwork/qsslcertificate.h> #include <QtNetwork/qsslkey.h> @@ -53,13 +55,11 @@ class ProfileAdapter; QT_BEGIN_NAMESPACE -#if QT_CONFIG(ssl) - class Q_WEBENGINECORE_EXPORT QWebEngineClientCertificateStore { public: void add(const QSslCertificate &certificate, const QSslKey &privateKey); - QVector<QSslCertificate> certificates() const; + QList<QSslCertificate> certificates() const; void remove(const QSslCertificate &certificate); void clear(); @@ -72,8 +72,7 @@ private: QtWebEngineCore::ClientCertificateStoreData *m_storeData; }; -#endif // QT_CONFIG(ssl) - QT_END_NAMESPACE +#endif // QT_CONFIG(ssl) #endif // QWebEngineClientCertificateStore_H diff --git a/src/core/api/qwebenginecontextmenurequest.cpp b/src/core/api/qwebenginecontextmenurequest.cpp new file mode 100644 index 000000000..62a328b72 --- /dev/null +++ b/src/core/api/qwebenginecontextmenurequest.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginecontextmenurequest.h" +#include "qwebenginecontextmenurequest_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineContextMenuRequest + \since 6.0 + \brief The QWebEngineContextMenuRequest class provides request for populating or extending a context menu with actions. + + \inmodule QtWebEngineCore + + QWebEngineContextMenuRequest is returned by QWebEngineView::lastContextMenuRequest() after a context menu event, + and contains information about where the context menu event took place. This is also in the context + in which any context specific QWebEnginePage::WebAction will be performed. +*/ + +/*! + \enum QWebEngineContextMenuRequest::MediaType + \readonly + \since 6.0 + + This enum describes the media type of the context menu request if any. + + \value MediaTypeNone The context is not a media type. + \value MediaTypeImage The context is an image element. + \value MediaTypeVideo The context is a video element. + \value MediaTypeAudio The context is an audio element. + \value MediaTypeCanvas The context is a canvas element. + \value MediaTypeFile The context is a file. + \value MediaTypePlugin The context is a plugin element. +*/ + +/*! + \enum QWebEngineContextMenuRequest::EditFlag + \readonly + \since 6.0 + + The available edit operations in the current context menu request. + + \value CanUndo Undo is available. + \value CanRedo Redo is available. + \value CanCut Cut is available. + \value CanCopy Copy is available. + \value CanPaste Paste is available. + \value CanDelete Delete is available. + \value CanSelectAll Select All is available. + \value CanTranslate Translate is available. + \value CanEditRichly Context is richly editable. +*/ + +/*! + \enum QWebEngineContextMenuRequest::MediaFlag + \readonly + \since 6.0 + + The current media element's status and its available operations. + \c MediaNone if the selected web page content is not a media element. + + \value MediaInError An error occurred. + \value MediaPaused Media is paused. + \value MediaMuted Media is muted. + \value MediaLoop Media can be looped. + \value MediaCanSave Media can be saved. + \value MediaHasAudio Media has audio. + \value MediaCanToggleControls Media can show controls. + \value MediaControls Media controls are shown. + \value MediaCanPrint Media is printable. + \value MediaCanRotate Media is rotatable. +*/ + +/*! + \internal +*/ +QWebEngineContextMenuRequest::QWebEngineContextMenuRequest( + QWebEngineContextMenuRequestPrivate *request) + : d(request) +{ +} + +/*! + Destroys the context menu request. +*/ +QWebEngineContextMenuRequest::~QWebEngineContextMenuRequest() = default; + +/*! + Returns the position of the context menu request, usually the mouse + position where the context menu event was triggered. +*/ +QPoint QWebEngineContextMenuRequest::position() const +{ + return d->m_position; +} + +/*! + Returns the selected text of the context menu request. +*/ +QString QWebEngineContextMenuRequest::selectedText() const +{ + return d->m_selectedText; +} + +/*! + Returns the text of a link if the context menu request was requested for a link. +*/ +QString QWebEngineContextMenuRequest::linkText() const +{ + return d->m_linkText; +} + +/*! + Returns the URL of a link if the menu context request is a link. + It is not guaranteed to be a valid URL. +*/ +QUrl QWebEngineContextMenuRequest::linkUrl() const +{ + return d->m_unfilteredLinkUrl; +} + +/*! + If the context menu request is a media element, returns the URL of that media. +*/ +QUrl QWebEngineContextMenuRequest::mediaUrl() const +{ + return d->m_mediaUrl; +} + +/*! + Returns the type of the media element or \c MediaTypeNone + if the context menu requestis not a media element. +*/ +QWebEngineContextMenuRequest::MediaType QWebEngineContextMenuRequest::mediaType() const +{ + return static_cast<QWebEngineContextMenuRequest::MediaType>(d->m_mediaType); +} + +/*! + Returns \c true if the context menu request is editable by the user; + otherwise returns \c false. +*/ +bool QWebEngineContextMenuRequest::isContentEditable() const +{ + return d->m_isEditable; +} + +/*! + If the menu context request is a word considered misspelled by the spell-checker, + returns the misspelled word. + + For possible replacements of the word, see spellCheckerSuggestions(). +*/ +QString QWebEngineContextMenuRequest::misspelledWord() const +{ + return d->m_misspelledWord; +} + + +/*! + If the menu context request is a word considered misspelled by the spell-checker, + returns a list of suggested replacements for misspelledWord(). +*/ +QStringList QWebEngineContextMenuRequest::spellCheckerSuggestions() const +{ + return d->m_spellCheckerSuggestions; +} + +/*! + TODO: needs api in page +*/ +bool QWebEngineContextMenuRequest::isAccepted() const +{ + return d->m_accepted; +} + +/*! + TODO: needs api in page +*/ +void QWebEngineContextMenuRequest::setAccepted(bool accepted) +{ + d->m_accepted = accepted; +} + +/*! + Returns the current media element's status and its available operations. + \c MediaNone if the selected web page content is not a media element. +*/ +QWebEngineContextMenuRequest::MediaFlags QWebEngineContextMenuRequest::mediaFlags() const +{ + return static_cast<QWebEngineContextMenuRequest::MediaFlags>(d->m_mediaFlags); +} + +/*! + Returns the available edit operations in the current context + or \c CanDoNone if no actions are available. +*/ +QWebEngineContextMenuRequest::EditFlags QWebEngineContextMenuRequest::editFlags() const +{ + return static_cast<QWebEngineContextMenuRequest::EditFlags>(d->m_editFlags); +} + +/*! + \internal +*/ +QUrl QWebEngineContextMenuRequest::filteredLinkUrl() const +{ + return d->m_filteredLinkUrl; +} + +/*! + \internal +*/ +QString QWebEngineContextMenuRequest::altText() const +{ + return d->m_altText; +} + +/*! + \internal +*/ +QString QWebEngineContextMenuRequest::titleText() const +{ + return d->m_titleText; +} + +/*! + \internal +*/ +QUrl QWebEngineContextMenuRequest::referrerUrl() const +{ + return !d->m_frameUrl.isEmpty() ? d->m_frameUrl : d->m_pageUrl; +} + +/*! + \internal +*/ +QtWebEngineCore::ReferrerPolicy QWebEngineContextMenuRequest::referrerPolicy() const +{ + return d->m_referrerPolicy; +} + +/*! + \internal +*/ +QString QWebEngineContextMenuRequest::suggestedFileName() const +{ + return d->m_suggestedFileName; +} + +/*! + \internal +*/ +bool QWebEngineContextMenuRequest::hasImageContent() const +{ + return d->m_hasImageContent; +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginecontextmenurequest.h b/src/core/api/qwebenginecontextmenurequest.h new file mode 100644 index 000000000..d9041d797 --- /dev/null +++ b/src/core/api/qwebenginecontextmenurequest.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINECONTEXTMENUREQUEST_H +#define QWEBENGINECONTEXTMENUREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/QObject> +#include <QtCore/QUrl> +#include <QtCore/QPoint> +#include <QScopedPointer> + +namespace extensions { +class MimeHandlerViewGuestDelegateQt; +} + +namespace QtWebEngineCore { +class RenderViewContextMenuQt; +class WebContentsViewQt; + +// Must match blink::WebReferrerPolicy +enum class ReferrerPolicy { + Always, + Default, + NoReferrerWhenDowngrade, + Never, + Origin, + OriginWhenCrossOrigin, + NoReferrerWhenDowngradeOriginWhenCrossOrigin, + SameOrigin, + StrictOrigin, + Last = StrictOrigin, +}; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineContextMenuRequestPrivate; +class Q_WEBENGINECORE_EXPORT QWebEngineContextMenuRequest : public QObject +{ + Q_OBJECT +public: + enum MediaType { + MediaTypeNone, + MediaTypeImage, + MediaTypeVideo, + MediaTypeAudio, + MediaTypeCanvas, + MediaTypeFile, + MediaTypePlugin + }; + Q_ENUM(MediaType) + + // Must match QWebEngineCore::WebEngineContextMenuData::MediaFlags: + enum MediaFlag { + MediaInError = 0x1, + MediaPaused = 0x2, + MediaMuted = 0x4, + MediaLoop = 0x8, + MediaCanSave = 0x10, + MediaHasAudio = 0x20, + MediaCanToggleControls = 0x40, + MediaControls = 0x80, + MediaCanPrint = 0x100, + MediaCanRotate = 0x200, + }; + Q_DECLARE_FLAGS(MediaFlags, MediaFlag) + Q_FLAG(MediaFlags) + + // Must match QWebEngineCore::WebEngineContextMenuData::EditFlags: + enum EditFlag { + CanUndo = 0x1, + CanRedo = 0x2, + CanCut = 0x4, + CanCopy = 0x8, + CanPaste = 0x10, + CanDelete = 0x20, + CanSelectAll = 0x40, + CanTranslate = 0x80, + CanEditRichly = 0x100, + }; + Q_DECLARE_FLAGS(EditFlags, EditFlag) + Q_FLAG(EditFlags) + + Q_PROPERTY(QPoint position READ position CONSTANT FINAL) + Q_PROPERTY(QString selectedText READ selectedText CONSTANT FINAL) + Q_PROPERTY(QString linkText READ linkText CONSTANT FINAL) + Q_PROPERTY(QUrl linkUrl READ linkUrl CONSTANT FINAL) + Q_PROPERTY(QUrl mediaUrl READ mediaUrl CONSTANT FINAL) + Q_PROPERTY(MediaType mediaType READ mediaType CONSTANT FINAL) + Q_PROPERTY(bool isContentEditable READ isContentEditable CONSTANT FINAL) + Q_PROPERTY(QString misspelledWord READ misspelledWord CONSTANT FINAL) + Q_PROPERTY(QStringList spellCheckerSuggestions READ spellCheckerSuggestions CONSTANT FINAL) + Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted FINAL) + Q_PROPERTY(MediaFlags mediaFlags READ mediaFlags CONSTANT FINAL REVISION 1) + Q_PROPERTY(EditFlags editFlags READ editFlags CONSTANT FINAL REVISION 1) + + virtual ~QWebEngineContextMenuRequest(); + QPoint position() const; + QString selectedText() const; + QString linkText() const; + QUrl linkUrl() const; + QUrl mediaUrl() const; + MediaType mediaType() const; + bool isContentEditable() const; + QString misspelledWord() const; + QStringList spellCheckerSuggestions() const; + bool isAccepted() const; + void setAccepted(bool accepted); + MediaFlags mediaFlags() const; + EditFlags editFlags() const; + +private: + QUrl filteredLinkUrl() const; + QString altText() const; + QString titleText() const; + QUrl referrerUrl() const; + QtWebEngineCore::ReferrerPolicy referrerPolicy() const; + bool hasImageContent() const; + QString suggestedFileName() const; + +private: + QWebEngineContextMenuRequest(QWebEngineContextMenuRequestPrivate *d); + QScopedPointer<QWebEngineContextMenuRequestPrivate> d; + friend class QtWebEngineCore::WebContentsViewQt; + friend class QtWebEngineCore::RenderViewContextMenuQt; + friend class extensions::MimeHandlerViewGuestDelegateQt; + friend class QQuickWebEngineViewPrivate; + friend class QQuickWebEngineView; + friend class ContextMenuRequestJSWrapper; + friend class QWebEngineViewPrivate; + friend class QWebEnginePage; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINECONTEXTMENUREQUEST_H diff --git a/src/core/api/qwebenginecontextmenurequest_p.h b/src/core/api/qwebenginecontextmenurequest_p.h new file mode 100644 index 000000000..c7b98a871 --- /dev/null +++ b/src/core/api/qwebenginecontextmenurequest_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINECONTEXTMENUREQUEST_P_H +#define QWEBENGINECONTEXTMENUREQUEST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtwebenginecoreglobal_p.h" +#include "qwebenginecontextmenurequest.h" +#include <QPoint> +#include <QUrl> + +QT_BEGIN_NAMESPACE + +class QWebEngineContextMenuRequestPrivate +{ +public: + bool m_accepted = false; + bool m_hasImageContent = false; + bool m_isEditable = false; + bool m_isSpellCheckerEnabled = false; + uint m_mediaType = 0; + uint m_mediaFlags = 0; + uint m_editFlags = 0; + QPoint m_position; + QUrl m_filteredLinkUrl; + QUrl m_unfilteredLinkUrl; + QUrl m_mediaUrl; + QString m_altText; + QString m_linkText; + QString m_titleText; + QString m_selectedText; + QString m_suggestedFileName; + QString m_misspelledWord; + QStringList m_spellCheckerSuggestions; + QUrl m_pageUrl; + QUrl m_frameUrl; + QtWebEngineCore::ReferrerPolicy m_referrerPolicy = QtWebEngineCore::ReferrerPolicy::Default; + // Some likely candidates for future additions as we add support for the related actions: + // bool isImageBlocked; + // <enum tbd> mediaType; + // ... +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/core/api/qwebenginecookiestore_p.h b/src/core/api/qwebenginecookiestore_p.h index a79e2b095..e6fa245c2 100644 --- a/src/core/api/qwebenginecookiestore_p.h +++ b/src/core/api/qwebenginecookiestore_p.h @@ -56,7 +56,7 @@ #include "qwebenginecallback_p.h" #include "qwebenginecookiestore.h" -#include <QVector> +#include <QList> #include <QNetworkCookie> #include <QUrl> @@ -79,7 +79,7 @@ class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineCookieStorePrivate { public: QtWebEngineCore::CallbackDirectory callbackDirectory; std::function<bool(const QWebEngineCookieStore::FilterRequest &)> filterCallback; - QVector<CookieData> m_pendingUserCookies; + QList<CookieData> m_pendingUserCookies; quint64 m_nextCallbackId; bool m_deleteSessionCookiesPending; bool m_deleteAllCookiesPending; diff --git a/src/core/api/qwebenginedownloadrequest.cpp b/src/core/api/qwebenginedownloadrequest.cpp new file mode 100644 index 000000000..58f02ee4f --- /dev/null +++ b/src/core/api/qwebenginedownloadrequest.cpp @@ -0,0 +1,682 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginedownloadrequest.h" +#include "qwebenginedownloadrequest_p.h" + +#include "profile_adapter.h" + +#include <QDir> +#include "QFileInfo" + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::ProfileAdapterClient; + +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NoReason, QWebEngineDownloadRequest::NoReason) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileFailed, QWebEngineDownloadRequest::FileFailed) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileAccessDenied, QWebEngineDownloadRequest::FileAccessDenied) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileNoSpace, QWebEngineDownloadRequest::FileNoSpace) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileNameTooLong, QWebEngineDownloadRequest::FileNameTooLong) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileTooLarge, QWebEngineDownloadRequest::FileTooLarge) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileVirusInfected, QWebEngineDownloadRequest::FileVirusInfected) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileTransientError, QWebEngineDownloadRequest::FileTransientError) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileBlocked, QWebEngineDownloadRequest::FileBlocked) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileSecurityCheckFailed, QWebEngineDownloadRequest::FileSecurityCheckFailed) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileTooShort, QWebEngineDownloadRequest::FileTooShort) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::FileHashMismatch, QWebEngineDownloadRequest::FileHashMismatch) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkFailed, QWebEngineDownloadRequest::NetworkFailed) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkTimeout, QWebEngineDownloadRequest::NetworkTimeout) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkDisconnected, QWebEngineDownloadRequest::NetworkDisconnected) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkServerDown, QWebEngineDownloadRequest::NetworkServerDown) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::NetworkInvalidRequest, QWebEngineDownloadRequest::NetworkInvalidRequest) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerFailed, QWebEngineDownloadRequest::ServerFailed) +//ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerNoRange, QWebEngineDownloadRequest::ServerNoRange) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerBadContent, QWebEngineDownloadRequest::ServerBadContent) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerUnauthorized, QWebEngineDownloadRequest::ServerUnauthorized) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerCertProblem, QWebEngineDownloadRequest::ServerCertProblem) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerForbidden, QWebEngineDownloadRequest::ServerForbidden) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::ServerUnreachable, QWebEngineDownloadRequest::ServerUnreachable) +ASSERT_ENUMS_MATCH(ProfileAdapterClient::UserCanceled, QWebEngineDownloadRequest::UserCanceled) +//ASSERT_ENUMS_MATCH(ProfileAdapterClient::UserShutdown, QWebEngineDownloadRequest::UserShutdown) +//ASSERT_ENUMS_MATCH(ProfileAdapterClient::Crash, QWebEngineDownloadRequest::Crash) + +static inline QWebEngineDownloadRequest::DownloadState toDownloadState(int state) +{ + switch (state) { + case ProfileAdapterClient::DownloadInProgress: + return QWebEngineDownloadRequest::DownloadInProgress; + case ProfileAdapterClient::DownloadCompleted: + return QWebEngineDownloadRequest::DownloadCompleted; + case ProfileAdapterClient::DownloadCancelled: + return QWebEngineDownloadRequest::DownloadCancelled; + case ProfileAdapterClient::DownloadInterrupted: + return QWebEngineDownloadRequest::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QWebEngineDownloadRequest::DownloadCancelled; + } +} + +static inline QWebEngineDownloadRequest::DownloadInterruptReason toDownloadInterruptReason(int reason) +{ + return static_cast<QWebEngineDownloadRequest::DownloadInterruptReason>(reason); +} + +/*! + \class QWebEngineDownloadRequest + \brief The QWebEngineDownloadRequest class provides information about a download. + + \inmodule QtWebEngineCore + + QWebEngineDownloadRequest models a download throughout its life cycle, starting + with a pending download request and finishing with a completed download. It + can be used, for example, to get information about new downloads, to monitor + progress, and to pause, resume, and cancel downloads. + + Downloads are usually triggered by user interaction on a web page. It is the + QWebEngineProfile's responsibility to notify the application of new download + requests, which it does by emitting the + \l{QWebEngineProfile::downloadRequested}{downloadRequested} signal together + with a newly created QWebEngineDownloadRequest. The application can then + examine this item and decide whether to accept it or not. A signal handler + must explicitly call accept() on the item for \QWE to actually start + downloading and writing data to disk. If no signal handler calls accept(), + then the download request will be automatically rejected and nothing will be + written to disk. + + \note Some properties, such as setting the path and file name where the file + will be saved (see \l downloadDirectory() and \l downloadFileName()), can + only be changed before calling accept(). + + \section2 Object Life Cycle + + All items are guaranteed to be valid during the emission of the + \l{QWebEngineProfile::downloadRequested}{downloadRequested} signal. If + accept() is \e not called by any signal handler, then the item will be + deleted \e immediately after signal emission. This means that the + application \b{must not} keep references to rejected download items. It also + means the application should not use a queued connection to this signal. + + If accept() \e is called by a signal handler, then the QWebEngineProfile + will take ownership of the item. However, it is safe for the application to + delete the item at any time, except during the handling of the + \l{QWebEngineProfile::downloadRequested}{downloadRequested} signal. The + QWebEngineProfile being a long-lived object, it is in fact recommended that + the application delete any items it is no longer interested in. + + \note Deleting an item will also automatically cancel a download since 5.12.2, + but it is recommended to cancel manually before deleting for portability. + + \section2 Web Page Downloads + + In addition to normal file downloads, which consist simply of retrieving + some raw bytes from the network and writing them to disk, \QWE also + supports saving complete web pages, which involves parsing the page's HTML, + downloading any dependent resources, and potentially packaging everything + into a special file format (\l savePageFormat). To check if a download is + for a file or a web page, use \l isSavePageDownload. + + \sa QWebEngineProfile, QWebEngineProfile::downloadRequested, + QWebEnginePage::download, QWebEnginePage::save +*/ + +QWebEngineDownloadRequestPrivate::QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter, const QUrl &url) + : m_profileAdapter(adapter) + , downloadFinished(false) + , downloadId(-1) + , downloadState(QWebEngineDownloadRequest::DownloadCancelled) + , savePageFormat(QWebEngineDownloadRequest::MimeHtmlSaveFormat) + , interruptReason(QWebEngineDownloadRequest::NoReason) + , downloadUrl(url) + , downloadPaused(false) + , isCustomFileName(false) + , totalBytes(-1) + , receivedBytes(0) + , isSavePageDownload(false) + , m_adapterClient(nullptr) +{ +} + +QWebEngineDownloadRequestPrivate::~QWebEngineDownloadRequestPrivate() +{ +} + +void QWebEngineDownloadRequestPrivate::update(const ProfileAdapterClient::DownloadItemInfo &info) +{ + Q_Q(QWebEngineDownloadRequest); + + Q_ASSERT(downloadState != QWebEngineDownloadRequest::DownloadRequested); + + if (toDownloadInterruptReason(info.downloadInterruptReason) != interruptReason) { + interruptReason = toDownloadInterruptReason(info.downloadInterruptReason); + Q_EMIT q->interruptReasonChanged(); + } + if (toDownloadState(info.state) != downloadState) { + downloadState = toDownloadState(info.state); + Q_EMIT q->stateChanged(downloadState); + } + + if (info.receivedBytes != receivedBytes || info.totalBytes != totalBytes) { + + if (info.receivedBytes != receivedBytes) { + receivedBytes = info.receivedBytes; + Q_EMIT q->receivedBytesChanged(); + } + if (info.totalBytes != totalBytes) { + totalBytes = info.totalBytes; + Q_EMIT q->totalBytesChanged(); + } + Q_EMIT q->downloadProgress(receivedBytes, totalBytes); + } + + if (info.done) + setFinished(); + + if (downloadPaused != info.paused) { + downloadPaused = info.paused; + Q_EMIT q->isPausedChanged(); + } +} + +void QWebEngineDownloadRequestPrivate::setFinished() +{ + if (downloadFinished) + return; + + downloadFinished = true; + Q_EMIT q_ptr->isFinishedChanged(); +} + +/*! + Accepts the current download request, which will start the download. + + If the item is in the \l DownloadRequested state, then it will transition + into the \l DownloadInProgress state and the downloading will begin. If the + item is in any other state, then nothing will happen. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadRequest::accept() +{ + Q_D(QWebEngineDownloadRequest); + + if (d->downloadState != QWebEngineDownloadRequest::DownloadRequested) + return; + + d->downloadState = QWebEngineDownloadRequest::DownloadInProgress; + Q_EMIT stateChanged(d->downloadState); +} + +/*! + Cancels the current download. + + If the item is in the \l DownloadInProgress state, then it will transition + into the \l DownloadCancelled state, the downloading will stop, and partially + downloaded files will be deleted from disk. + + If the item is in the \l DownloadCompleted state, then nothing will happen. + If the item is in any other state, then it will transition into the \l + DownloadCancelled state without further effect. + + \sa finished(), stateChanged() +*/ + +void QWebEngineDownloadRequest::cancel() +{ + Q_D(QWebEngineDownloadRequest); + + QWebEngineDownloadRequest::DownloadState state = d->downloadState; + + if (state == QWebEngineDownloadRequest::DownloadCompleted + || state == QWebEngineDownloadRequest::DownloadCancelled) + return; + + // We directly cancel the download request if the user cancels + // before it even started, so no need to notify the profile here. + if (state == QWebEngineDownloadRequest::DownloadInProgress) { + if (d->m_profileAdapter) + d->m_profileAdapter->cancelDownload(d->downloadId); + } else { + d->downloadState = QWebEngineDownloadRequest::DownloadCancelled; + Q_EMIT stateChanged(d->downloadState); + d->setFinished(); + } +} + +/*! + Pauses the download. + + Has no effect if the state is not \l DownloadInProgress. Does not change the + state. + + \sa resume(), isPaused() +*/ + +void QWebEngineDownloadRequest::pause() +{ + Q_D(QWebEngineDownloadRequest); + + QWebEngineDownloadRequest::DownloadState state = d->downloadState; + + if (state != QWebEngineDownloadRequest::DownloadInProgress) + return; + + if (d->m_profileAdapter) + d->m_profileAdapter->pauseDownload(d->downloadId); +} + +/*! + Resumes the current download if it was paused or interrupted. + + Has no effect if the state is not \l DownloadInProgress or \l + DownloadInterrupted. Does not change the state. + + \sa pause(), isPaused(), state() +*/ +void QWebEngineDownloadRequest::resume() +{ + Q_D(QWebEngineDownloadRequest); + + QWebEngineDownloadRequest::DownloadState state = d->downloadState; + + if (d->downloadFinished || (state != QWebEngineDownloadRequest::DownloadInProgress && state != QWebEngineDownloadRequest::DownloadInterrupted)) + return; + if (d->m_profileAdapter) + d->m_profileAdapter->resumeDownload(d->downloadId); +} + +/*! + Returns the download item's ID. +*/ + +quint32 QWebEngineDownloadRequest::id() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadId; +} + +/*! + \fn void QWebEngineDownloadRequest::finished() + + This signal is emitted when the download finishes. + + \sa state(), isFinished() +*/ + +/*! + \fn void QWebEngineDownloadRequest::isPausedChanged(bool isPaused) + + This signal is emitted whenever \a isPaused changes. + + \sa pause(), isPaused() +*/ + +/*! + \fn void QWebEngineDownloadRequest::stateChanged(DownloadState state) + + This signal is emitted whenever the download's \a state changes. + + \sa state(), DownloadState +*/ + +/*! + \fn void QWebEngineDownloadRequest::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) + + This signal is emitted to indicate the progress of the download request. + + The \a bytesReceived parameter indicates the number of bytes received, while + \a bytesTotal indicates the total number of bytes expected to be downloaded. + If the size of the file to be downloaded is not known, \c bytesTotal will be + 0. + + \sa totalBytes(), receivedBytes() +*/ + +/*! + \enum QWebEngineDownloadRequest::DownloadState + + This enum describes the state of the download: + + \value DownloadRequested Download has been requested, but has not been accepted yet. + \value DownloadInProgress Download is in progress. + \value DownloadCompleted Download completed successfully. + \value DownloadCancelled Download has been cancelled. + \value DownloadInterrupted Download has been interrupted (by the server or because of lost + connectivity). +*/ + +/*! + \enum QWebEngineDownloadRequest::SavePageFormat + + This enum describes the format that is used to save a web page. + + \value UnknownSaveFormat This is not a request for downloading a complete web page. + \value SingleHtmlSaveFormat The page is saved as a single HTML page. Resources such as images + are not saved. + \value CompleteHtmlSaveFormat The page is saved as a complete HTML page, for example a directory + containing the single HTML page and the resources. + \value MimeHtmlSaveFormat The page is saved as a complete web page in the MIME HTML format. +*/ + +/*! + \enum QWebEngineDownloadRequest::DownloadInterruptReason + + Describes the reason why a download was interrupted: + + \value NoReason Unknown reason or not interrupted. + \value FileFailed General file operation failure. + \value FileAccessDenied The file cannot be written locally, due to access restrictions. + \value FileNoSpace Insufficient space on the target drive. + \value FileNameTooLong The directory or file name is too long. + \value FileTooLarge The file size exceeds the file system limitation. + \value FileVirusInfected The file is infected with a virus. + \value FileTransientError Temporary problem (for example the file is in use, + out of memory, or too many files are opened at once). + \value FileBlocked The file was blocked due to local policy. + \value FileSecurityCheckFailed An attempt to check the safety of the download + failed due to unexpected reasons. + \value FileTooShort An attempt was made to seek past the end of a file when + opening a file (as part of resuming a previously interrupted download). + \value FileHashMismatch The partial file did not match the expected hash. + + \value NetworkFailed General network failure. + \value NetworkTimeout The network operation has timed out. + \value NetworkDisconnected The network connection has been terminated. + \value NetworkServerDown The server has gone down. + \value NetworkInvalidRequest The network request was invalid (for example, the + original or redirected URL is invalid, has an unsupported scheme, or is disallowed by policy). + + \value ServerFailed General server failure. + \value ServerBadContent The server does not have the requested data. + \value ServerUnauthorized The server did not authorize access to the resource. + \value ServerCertProblem A problem with the server certificate occurred. + \value ServerForbidden Access forbidden by the server. + \value ServerUnreachable Unexpected server response (might indicate that + the responding server may not be the intended server). + \value UserCanceled The user canceled the download. +*/ + +/*! + Returns the download item's current state. + + \sa DownloadState +*/ + +QWebEngineDownloadRequest::DownloadState QWebEngineDownloadRequest::state() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadState; +} + +/*! + Returns the the total amount of data to download in bytes. + + \c -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadRequest::totalBytes() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->totalBytes; +} + +/*! + Returns the amount of data in bytes that has been downloaded so far. + + \c -1 means the size is unknown. +*/ + +qint64 QWebEngineDownloadRequest::receivedBytes() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->receivedBytes; +} + +/*! + Returns the download's origin URL. +*/ + +QUrl QWebEngineDownloadRequest::url() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadUrl; +} + +/*! + Returns the MIME type of the download. +*/ + +QString QWebEngineDownloadRequest::mimeType() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->mimeType; +} + +/*! + Returns the download directory path. +*/ + +QString QWebEngineDownloadRequest::downloadDirectory() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadDirectory; +} + +/*! + Sets \a directory as the directory path to download the file to. + + The download directory path can only be set in response to the QWebEngineProfile::downloadRequested() + signal before the download is accepted. Past that point, this function has no effect on the + download item's state. +*/ + +void QWebEngineDownloadRequest::setDownloadDirectory(const QString &directory) +{ + Q_D(QWebEngineDownloadRequest); + if (d->downloadState != QWebEngineDownloadRequest::DownloadRequested) { + qWarning("Setting the download directory is not allowed after the download has been accepted."); + return; + } + + if (!directory.isEmpty() && d->downloadDirectory != directory) + d->downloadDirectory = directory; + + if (!d->isCustomFileName && d->m_profileAdapter) + d->downloadFileName = QFileInfo(d->m_profileAdapter->determineDownloadPath(d->downloadDirectory, + d->suggestedFileName, + d->startTime)).fileName(); +} + +/*! + Returns the file name to download the file to. +*/ + +QString QWebEngineDownloadRequest::downloadFileName() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadFileName; +} + +/*! + Sets \a fileName as the file name to download the file to. + + The download file name can only be set in response to the QWebEngineProfile::downloadRequested() + signal before the download is accepted. Past that point, this function has no effect on the + download item's state. +*/ + +void QWebEngineDownloadRequest::setDownloadFileName(const QString &fileName) +{ + Q_D(QWebEngineDownloadRequest); + if (d->downloadState != QWebEngineDownloadRequest::DownloadRequested) { + qWarning("Setting the download file name is not allowed after the download has been accepted."); + return; + } + + if (!fileName.isEmpty()) { + d->downloadFileName = fileName; + d->isCustomFileName = true; + } +} + +/*! + Returns the suggested file name. +*/ + +QString QWebEngineDownloadRequest::suggestedFileName() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->suggestedFileName; +} + +/*! + Returns whether this download is finished (completed, cancelled, or non-resumable interrupted state). + + \sa finished(), state(), +*/ + +bool QWebEngineDownloadRequest::isFinished() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadFinished; +} + +/*! + Returns whether this download is paused. + + \sa pause(), resume() +*/ + +bool QWebEngineDownloadRequest::isPaused() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->downloadPaused; +} + +/*! + Returns the format the web page will be saved in if this is a download request for a web page. + \sa setSavePageFormat(), isSavePageDownload() +*/ +QWebEngineDownloadRequest::SavePageFormat QWebEngineDownloadRequest::savePageFormat() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->savePageFormat; +} + +/*! + Sets the \a format the web page will be saved in if this is a download request for a web page. + + \sa savePageFormat(), isSavePageDownload() +*/ +void QWebEngineDownloadRequest::setSavePageFormat(QWebEngineDownloadRequest::SavePageFormat format) +{ + Q_D(QWebEngineDownloadRequest); + if (d->savePageFormat != format) { + d->savePageFormat = format; + Q_EMIT savePageFormatChanged(); + } +} + +/*! + Returns \c true if this is a download request for saving a web page. + + \sa savePageFormat(), setSavePageFormat() + */ +bool QWebEngineDownloadRequest::isSavePageDownload() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->isSavePageDownload; +} + +/*! + Returns the reason why the download was interrupted. + + \sa interruptReasonString() +*/ + +QWebEngineDownloadRequest::DownloadInterruptReason QWebEngineDownloadRequest::interruptReason() const +{ + Q_D(const QWebEngineDownloadRequest); + return d->interruptReason; +} + +/*! + Returns a human-readable description of the reason for interrupting the download. + + \sa interruptReason() +*/ + +QString QWebEngineDownloadRequest::interruptReasonString() const +{ + return ProfileAdapterClient::downloadInterruptReasonToString( + static_cast<ProfileAdapterClient::DownloadInterruptReason>(interruptReason())); +} + +/*! + Returns the page the download was requested on. If the download was not triggered by content in a page, + \c nullptr is returned. +*/ +QObject *QWebEngineDownloadRequest::page() const +{ + Q_D(const QWebEngineDownloadRequest); + //TODO: come back here when page is in core + Q_UNREACHABLE(); + return nullptr; +} + +QWebEngineDownloadRequest::QWebEngineDownloadRequest(QWebEngineDownloadRequestPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineDownloadRequest::~QWebEngineDownloadRequest() +{ + // MEMO Items are owned by profile by default and will be destroyed on profile's destruction + // It's not safe to access profile in that case, so we rely on profile to clean up items + if (!isFinished()) + cancel(); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginedownloadrequest.h b/src/core/api/qwebenginedownloadrequest.h new file mode 100644 index 000000000..3e0e0d044 --- /dev/null +++ b/src/core/api/qwebenginedownloadrequest.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEDOWNLOADREQUEST_H +#define QWEBENGINEDOWNLOADREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qobject.h> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +//TODO: class QWebEnginePage; +class QWebEngineDownloadRequestPrivate; +class QWebEngineProfilePrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineDownloadRequest : public QObject +{ + Q_OBJECT +public: + Q_PROPERTY(quint32 id READ id CONSTANT FINAL) + Q_PROPERTY(DownloadState state READ state NOTIFY stateChanged FINAL) + Q_PROPERTY(SavePageFormat savePageFormat READ savePageFormat WRITE setSavePageFormat NOTIFY savePageFormatChanged FINAL) + Q_PROPERTY(qint64 totalBytes READ totalBytes NOTIFY totalBytesChanged FINAL) + Q_PROPERTY(qint64 receivedBytes READ receivedBytes NOTIFY receivedBytesChanged FINAL) + Q_PROPERTY(QString mimeType READ mimeType FINAL) + Q_PROPERTY(DownloadInterruptReason interruptReason READ interruptReason NOTIFY interruptReasonChanged FINAL) + Q_PROPERTY(QString interruptReasonString READ interruptReasonString NOTIFY interruptReasonChanged FINAL) + Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged FINAL) + Q_PROPERTY(bool isPaused READ isPaused NOTIFY isPausedChanged FINAL) + Q_PROPERTY(bool isSavePageDownload READ isSavePageDownload CONSTANT FINAL) + //TODO: Q_PROPERTY(QQuickWebEngineView *view READ view CONSTANT REVISION 7 FINAL) + Q_PROPERTY(QUrl url READ url CONSTANT FINAL) + Q_PROPERTY(QString suggestedFileName READ suggestedFileName CONSTANT FINAL) + Q_PROPERTY(QString downloadDirectory READ downloadDirectory WRITE setDownloadDirectory NOTIFY downloadDirectoryChanged FINAL) + Q_PROPERTY(QString downloadFileName READ downloadFileName WRITE setDownloadFileName NOTIFY downloadFileNameChanged FINAL) + + ~QWebEngineDownloadRequest(); + + enum DownloadState { + DownloadRequested, + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUM(DownloadState) + + enum SavePageFormat { + UnknownSaveFormat = -1, + SingleHtmlSaveFormat, + CompleteHtmlSaveFormat, + MimeHtmlSaveFormat + }; + Q_ENUM(SavePageFormat) + + enum DownloadInterruptReason { + NoReason = 0, + FileFailed = 1, + FileAccessDenied = 2, + FileNoSpace = 3, + FileNameTooLong = 5, + FileTooLarge = 6, + FileVirusInfected = 7, + FileTransientError = 10, + FileBlocked = 11, + FileSecurityCheckFailed = 12, + FileTooShort = 13, + FileHashMismatch = 14, + NetworkFailed = 20, + NetworkTimeout = 21, + NetworkDisconnected = 22, + NetworkServerDown = 23, + NetworkInvalidRequest = 24, + ServerFailed = 30, + //ServerNoRange = 31, + ServerBadContent = 33, + ServerUnauthorized = 34, + ServerCertProblem = 35, + ServerForbidden = 36, + ServerUnreachable = 37, + UserCanceled = 40, + //UserShutdown = 41, + //Crash = 50 + }; + Q_ENUM(DownloadInterruptReason) + + quint32 id() const; + DownloadState state() const; + qint64 totalBytes() const; + qint64 receivedBytes() const; + QUrl url() const; + QString mimeType() const; + bool isFinished() const; + bool isPaused() const; + SavePageFormat savePageFormat() const; + void setSavePageFormat(SavePageFormat format); + DownloadInterruptReason interruptReason() const; + QString interruptReasonString() const; + bool isSavePageDownload() const; + QString suggestedFileName() const; + QString downloadDirectory() const; + void setDownloadDirectory(const QString &directory); + QString downloadFileName() const; + void setDownloadFileName(const QString &fileName); + + //TODO: + QObject *page() const; + +public Q_SLOTS: + void accept(); + void cancel(); + void pause(); + void resume(); + +Q_SIGNALS: + void stateChanged(QWebEngineDownloadRequest::DownloadState state); + //TODO: fix it for qml + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void savePageFormatChanged(); + void receivedBytesChanged(); + void totalBytesChanged(); + void interruptReasonChanged(); + void isFinishedChanged(); + void isPausedChanged(); + void downloadDirectoryChanged(); + void downloadFileNameChanged(); + +private: + Q_DISABLE_COPY(QWebEngineDownloadRequest) + Q_DECLARE_PRIVATE(QWebEngineDownloadRequest) + + friend class QWebEngineProfilePrivate; + friend class QQuickWebEngineProfilePrivate; + friend class QWebEnginePage; + QWebEngineDownloadRequest(QWebEngineDownloadRequestPrivate*, QObject *parent = Q_NULLPTR); + QScopedPointer<QWebEngineDownloadRequestPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADREQUEST_H diff --git a/src/core/api/qwebenginedownloadrequest_p.h b/src/core/api/qwebenginedownloadrequest_p.h new file mode 100644 index 000000000..db2e70852 --- /dev/null +++ b/src/core/api/qwebenginedownloadrequest_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEDOWNLOADREQUEST_P_H +#define QWEBENGINEDOWNLOADREQUEST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtwebenginecoreglobal.h" +#include "qwebenginedownloadrequest.h" +#include "profile_adapter_client.h" +#include <QString> +#include <QPointer> + +namespace QtWebEngineCore { +class ProfileAdapter; +class WebContentsAdapterClient; +} + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineDownloadRequestPrivate { +public: + QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter, const QUrl &url); + ~QWebEngineDownloadRequestPrivate(); + + void update(const QtWebEngineCore::ProfileAdapterClient::DownloadItemInfo &info); + void setFinished(); + + bool downloadFinished; + quint32 downloadId; + qint64 startTime; + QWebEngineDownloadRequest::DownloadState downloadState; + QWebEngineDownloadRequest::SavePageFormat savePageFormat; + QWebEngineDownloadRequest::DownloadInterruptReason interruptReason; + QString downloadPath; + const QUrl downloadUrl; + QString mimeType; + bool downloadPaused; + QString suggestedFileName; + QString downloadDirectory; + QString downloadFileName; + bool isCustomFileName; + qint64 totalBytes; + qint64 receivedBytes; + bool isSavePageDownload; + QWebEngineDownloadRequest *q_ptr; + QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter; + QtWebEngineCore::WebContentsAdapterClient *m_adapterClient; + Q_DECLARE_PUBLIC(QWebEngineDownloadRequest) +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEDOWNLOADREQUEST_P_H + diff --git a/src/core/api/qwebenginefullscreenrequest.cpp b/src/core/api/qwebenginefullscreenrequest.cpp new file mode 100644 index 000000000..facc8910d --- /dev/null +++ b/src/core/api/qwebenginefullscreenrequest.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginefullscreenrequest.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineFullScreenRequest + \brief The QWebEngineFullScreenRequest class enables accepting or rejecting + requests for entering and exiting the fullscreen mode. + + \since 5.6 + + \inmodule QtWebEngineCore + + To allow elements such as videos to be shown in the fullscreen mode, + applications must set QWebEngineSettings::FullScreenSupportEnabled and + connect to QWebEnginePage::fullScreenRequested, which takes a + QWebEngineFullScreenRequest instance as an argument. + + If an element of a web page requests to be shown in the fullscreen mode, + QWebEnginePage::fullScreenRequested will be emitted with an + QWebEngineFullScreenRequest instance as an argument where toggleOn() returns + \c true. The signal handler needs to then either call accept() or reject(). + + If the request to enter the fullscreen mode is accepted, the element + requesting fullscreen mode will fill the viewport, but it is up to the + application to make the view fullscreen or to move the page to a view that + is in the fullscreen mode. + + Likewise, a QWebEnginePage::fullScreenRequested will be emitted when + the user wants to leave the full screen mode (that is, through the + QWebEnginePage::ExitFullScreen context menu action). In this case, + toggleOn() will return \c false, and the signal handler again needs to + accept() or reject() the request. If it is accepted, the applicaton needs to + make sure that the global window state is restored. +*/ + +/*! + \property QWebEngineFullScreenRequest::toggleOn + \brief Whether the web page has issued a request to enter fullscreen mode. +*/ + +/*! + \property QWebEngineFullScreenRequest::origin + \brief The URL to be opened in the fullscreen mode. +*/ + +/*! + Creates a request for opening the \a page from the URL specified by + \a origin in the fullscreen mode if \a fullscreen is \c true. +*/ + +class QWebEngineFullScreenRequestPrivate : public QSharedData { +public: + QWebEngineFullScreenRequestPrivate(const QUrl &origin, bool toggleOn, const std::function<void (bool)> &setFullScreenCallback) + : m_origin(origin) + , m_toggleOn(toggleOn) + , m_setFullScreenCallback(setFullScreenCallback) { } + + const QUrl m_origin; + const bool m_toggleOn; + const std::function<void (bool)> m_setFullScreenCallback; +}; + +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(const QUrl &origin, bool toggleOn, const std::function<void (bool)> &setFullScreenCallback) + : d_ptr(new QWebEngineFullScreenRequestPrivate(origin, toggleOn, setFullScreenCallback)) { } + +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(const QWebEngineFullScreenRequest &other) = default; +QWebEngineFullScreenRequest& QWebEngineFullScreenRequest::operator=(const QWebEngineFullScreenRequest &other) = default; +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(QWebEngineFullScreenRequest &&other) = default; +QWebEngineFullScreenRequest& QWebEngineFullScreenRequest::operator=(QWebEngineFullScreenRequest &&other) = default; +QWebEngineFullScreenRequest::~QWebEngineFullScreenRequest() = default; + +/*! + Rejects a request to enter or exit the fullscreen mode. +*/ +void QWebEngineFullScreenRequest::reject() +{ + d_ptr->m_setFullScreenCallback(!d_ptr->m_toggleOn); +} + +/*! + Accepts the request to enter or exit the fullscreen mode. +*/ +void QWebEngineFullScreenRequest::accept() +{ + d_ptr->m_setFullScreenCallback(d_ptr->m_toggleOn); +} + +/*! + \fn QWebEngineFullScreenRequest::toggleOn() const + Returns \c true if the web page has issued a request to enter the fullscreen + mode, otherwise returns \c false. +*/ +bool QWebEngineFullScreenRequest::toggleOn() const +{ + return d_ptr->m_toggleOn; +} + +/*! + \fn QWebEngineFullScreenRequest::origin() const + Returns the URL to be opened in the fullscreen mode. +*/ +QUrl QWebEngineFullScreenRequest::origin() const +{ + return d_ptr->m_origin; +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginefullscreenrequest.h b/src/core/api/qwebenginefullscreenrequest.h new file mode 100644 index 000000000..95911ed0a --- /dev/null +++ b/src/core/api/qwebenginefullscreenrequest.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEFULLSCREENREQUEST_H +#define QWEBENGINEFULLSCREENREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qurl.h> + +#include <functional> + +QT_BEGIN_NAMESPACE + +class QWebEngineFullScreenRequestPrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineFullScreenRequest +{ + Q_GADGET + Q_PROPERTY(bool toggleOn READ toggleOn CONSTANT) + Q_PROPERTY(QUrl origin READ origin CONSTANT) + +public: + QWebEngineFullScreenRequest(const QWebEngineFullScreenRequest &other); + QWebEngineFullScreenRequest &operator=(const QWebEngineFullScreenRequest &other); + QWebEngineFullScreenRequest(QWebEngineFullScreenRequest &&other); + QWebEngineFullScreenRequest &operator=(QWebEngineFullScreenRequest &&other); + ~QWebEngineFullScreenRequest(); + + Q_INVOKABLE void reject(); + Q_INVOKABLE void accept(); + bool toggleOn() const; + QUrl origin() const; + +private: + friend class QWebEnginePagePrivate; + friend class QQuickWebEngineViewPrivate; + QWebEngineFullScreenRequest(const QUrl &origin, bool toggleOn, const std::function<void (bool)> &setFullScreenCallback); + QExplicitlySharedDataPointer<QWebEngineFullScreenRequestPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/core/api/qwebenginehistory.cpp b/src/core/api/qwebenginehistory.cpp new file mode 100644 index 000000000..2f32444b2 --- /dev/null +++ b/src/core/api/qwebenginehistory.cpp @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginehistory.h" +#include "qwebenginehistory_p.h" + +#include "web_contents_adapter.h" + +QT_BEGIN_NAMESPACE + +/*! + \fn QWebEngineHistoryItem::swap(QWebEngineHistoryItem &other) + Swaps the history item with the \a other item. +*/ + +QWebEngineHistoryItemPrivate::QWebEngineHistoryItemPrivate( + QtWebEngineCore::WebContentsAdapterClient *adapter, int index) + : m_adapter(adapter), index(index) +{ +} + +QWebEngineHistoryItem::QWebEngineHistoryItem(QWebEngineHistoryItemPrivate *d) : d(d) { } + +QWebEngineHistoryItem::QWebEngineHistoryItem(const QWebEngineHistoryItem &other) : d(other.d) { } + +QWebEngineHistoryItem &QWebEngineHistoryItem::operator=(const QWebEngineHistoryItem &other) +{ + d = other.d; + return *this; +} + +QWebEngineHistoryItem::~QWebEngineHistoryItem() { } + +QUrl QWebEngineHistoryItem::originalUrl() const +{ + Q_D(const QWebEngineHistoryItem); + return d->m_adapter + ? d->m_adapter->webContentsAdapter()->getNavigationEntryOriginalUrl(d->index) + : QUrl(); +} + +QUrl QWebEngineHistoryItem::url() const +{ + Q_D(const QWebEngineHistoryItem); + return d->m_adapter ? d->m_adapter->webContentsAdapter()->getNavigationEntryUrl(d->index) + : QUrl(); +} + +QString QWebEngineHistoryItem::title() const +{ + Q_D(const QWebEngineHistoryItem); + return d->m_adapter ? d->m_adapter->webContentsAdapter()->getNavigationEntryTitle(d->index) + : QString(); +} + +QDateTime QWebEngineHistoryItem::lastVisited() const +{ + Q_D(const QWebEngineHistoryItem); + return d->m_adapter ? d->m_adapter->webContentsAdapter()->getNavigationEntryTimestamp(d->index) + : QDateTime(); +} + +/*! + Returns the URL of the icon associated with the history item. + + \sa url(), originalUrl(), title() +*/ +QUrl QWebEngineHistoryItem::iconUrl() const +{ + Q_D(const QWebEngineHistoryItem); + return d->m_adapter ? d->m_adapter->webContentsAdapter()->getNavigationEntryIconUrl(d->index) + : QUrl(); +} + +bool QWebEngineHistoryItem::isValid() const +{ + Q_D(const QWebEngineHistoryItem); + if (!d->m_adapter) + return false; + return d->index >= 0 && d->index < d->m_adapter->webContentsAdapter()->navigationEntryCount(); +} + +QWebEngineHistoryPrivate::QWebEngineHistoryPrivate( + QtWebEngineCore::WebContentsAdapterClient *adapter) + : m_adapter(adapter) +{ +} + +QWebEngineHistoryPrivate::~QWebEngineHistoryPrivate() +{ + // Invalidate shared item references possibly still out there. + QList<QWebEngineHistoryItem>::iterator it, end; + for (it = items.begin(), end = items.end(); it != end; ++it) + it->d->m_adapter = 0; +} + +void QWebEngineHistoryPrivate::updateItems() const +{ + // Keep track of items we return to be able to invalidate them + // and avoid dangling references to our m_adapter. + int entryCount = m_adapter->webContentsAdapter()->navigationEntryCount(); + while (items.size() > entryCount) { + items.last().d->m_adapter = 0; + items.removeLast(); + } + while (items.size() < entryCount) { + int nextIndex = items.size(); + items.append(QWebEngineHistoryItem(new QWebEngineHistoryItemPrivate(m_adapter, nextIndex))); + } +} + +QWebEngineHistory::QWebEngineHistory(QWebEngineHistoryPrivate *d) : d_ptr(d) { } + +QWebEngineHistory::~QWebEngineHistory() { } + +void QWebEngineHistory::clear() +{ + Q_D(const QWebEngineHistory); + d->m_adapter->webContentsAdapter()->clearNavigationHistory(); + d->m_adapter->updateNavigationActions(); +} + +QList<QWebEngineHistoryItem> QWebEngineHistory::items() const +{ + Q_D(const QWebEngineHistory); + d->updateItems(); + return d->items; +} + +QList<QWebEngineHistoryItem> QWebEngineHistory::backItems(int maxItems) const +{ + Q_D(const QWebEngineHistory); + d->updateItems(); + const int end = currentItemIndex(); + const int start = std::max(0, end - maxItems); + return d->items.mid(start, end - start); +} + +QList<QWebEngineHistoryItem> QWebEngineHistory::forwardItems(int maxItems) const +{ + Q_D(const QWebEngineHistory); + d->updateItems(); + const int start = currentItemIndex() + 1; + const int end = std::min(count(), start + maxItems); + return d->items.mid(start, end - start); +} + +bool QWebEngineHistory::canGoBack() const +{ + Q_D(const QWebEngineHistory); + return d->m_adapter->webContentsAdapter()->canGoToOffset(-1); +} + +bool QWebEngineHistory::canGoForward() const +{ + Q_D(const QWebEngineHistory); + return d->m_adapter->webContentsAdapter()->canGoToOffset(1); +} + +void QWebEngineHistory::back() +{ + Q_D(const QWebEngineHistory); + d->m_adapter->webContentsAdapter()->navigateToOffset(-1); +} + +void QWebEngineHistory::forward() +{ + Q_D(const QWebEngineHistory); + d->m_adapter->webContentsAdapter()->navigateToOffset(1); +} + +void QWebEngineHistory::goToItem(const QWebEngineHistoryItem &item) +{ + Q_D(const QWebEngineHistory); + Q_ASSERT(item.d->m_adapter == d->m_adapter); + d->m_adapter->webContentsAdapter()->navigateToIndex(item.d->index); +} + +QWebEngineHistoryItem QWebEngineHistory::backItem() const +{ + return itemAt(currentItemIndex() - 1); +} + +QWebEngineHistoryItem QWebEngineHistory::currentItem() const +{ + return itemAt(currentItemIndex()); +} + +QWebEngineHistoryItem QWebEngineHistory::forwardItem() const +{ + return itemAt(currentItemIndex() + 1); +} + +QWebEngineHistoryItem QWebEngineHistory::itemAt(int i) const +{ + Q_D(const QWebEngineHistory); + if (i >= 0 && i < count()) { + d->updateItems(); + return d->items[i]; + } else { + // Return an invalid item right away. + QWebEngineHistoryItem item(new QWebEngineHistoryItemPrivate(0, i)); + Q_ASSERT(!item.isValid()); + return item; + } +} + +int QWebEngineHistory::currentItemIndex() const +{ + Q_D(const QWebEngineHistory); + return d->m_adapter->webContentsAdapter()->currentNavigationEntryIndex(); +} + +int QWebEngineHistory::count() const +{ + Q_D(const QWebEngineHistory); + if (!d->m_adapter->webContentsAdapter()->isInitialized()) + return 0; + return d->m_adapter->webContentsAdapter()->navigationEntryCount(); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginehistory.h b/src/core/api/qwebenginehistory.h new file mode 100644 index 000000000..f7e591e38 --- /dev/null +++ b/src/core/api/qwebenginehistory.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEHISTORY_H +#define QWEBENGINEHISTORY_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/qurl.h> +#include <QtCore/qstring.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qshareddata.h> +#include <QtGui/qicon.h> + +QT_BEGIN_NAMESPACE + +class QWebEngineHistory; +class QWebEngineHistoryItemPrivate; +class QWebEnginePage; +class QWebEnginePagePrivate; + +class Q_WEBENGINECORE_EXPORT QWebEngineHistoryItem +{ +public: + QWebEngineHistoryItem(const QWebEngineHistoryItem &other); + QWebEngineHistoryItem &operator=(const QWebEngineHistoryItem &other); + ~QWebEngineHistoryItem(); + + QUrl originalUrl() const; + QUrl url() const; + + QString title() const; + QDateTime lastVisited() const; + QUrl iconUrl() const; + + bool isValid() const; + + void swap(QWebEngineHistoryItem &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + +private: + QWebEngineHistoryItem(QWebEngineHistoryItemPrivate *priv); + Q_DECLARE_PRIVATE_D(d.data(), QWebEngineHistoryItem) + QExplicitlySharedDataPointer<QWebEngineHistoryItemPrivate> d; + friend class QWebEngineHistory; + friend class QWebEngineHistoryPrivate; +}; + +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineHistoryItem) + +class QWebEngineHistoryPrivate; +class Q_WEBENGINECORE_EXPORT QWebEngineHistory +{ +public: + void clear(); + + QList<QWebEngineHistoryItem> items() const; + QList<QWebEngineHistoryItem> backItems(int maxItems) const; + QList<QWebEngineHistoryItem> forwardItems(int maxItems) const; + + bool canGoBack() const; + bool canGoForward() const; + + void back(); + void forward(); + void goToItem(const QWebEngineHistoryItem &item); + + QWebEngineHistoryItem backItem() const; + QWebEngineHistoryItem currentItem() const; + QWebEngineHistoryItem forwardItem() const; + QWebEngineHistoryItem itemAt(int i) const; + + int currentItemIndex() const; + + int count() const; + +private: + QWebEngineHistory(QWebEngineHistoryPrivate *d); + ~QWebEngineHistory(); + + Q_DISABLE_COPY(QWebEngineHistory) + Q_DECLARE_PRIVATE(QWebEngineHistory) + QScopedPointer<QWebEngineHistoryPrivate> d_ptr; + + friend Q_WEBENGINECORE_EXPORT QDataStream &operator>>(QDataStream &, QWebEngineHistory &); + friend Q_WEBENGINECORE_EXPORT QDataStream &operator<<(QDataStream &, const QWebEngineHistory &); + friend class QWebEnginePage; + friend class QWebEnginePagePrivate; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEHISTORY_H diff --git a/src/core/certificate_error_controller_p.h b/src/core/api/qwebenginehistory_p.h index b0b0bc658..2ca944e5b 100644 --- a/src/core/certificate_error_controller_p.h +++ b/src/core/api/qwebenginehistory_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef CERTIFICATE_ERROR_CONTROLLER_P_H -#define CERTIFICATE_ERROR_CONTROLLER_P_H +#ifndef QWEBENGINEHISTORY_P_H +#define QWEBENGINEHISTORY_P_H // // W A R N I N G @@ -50,30 +50,36 @@ // // We mean it. // +#include "qtwebenginecoreglobal_p.h" +#include <QtCore/qshareddata.h> -#include "content/public/browser/content_browser_client.h" - -#include "certificate_error_controller.h" +namespace QtWebEngineCore { +class WebContentsAdapterClient; +} QT_BEGIN_NAMESPACE +class QWebEnginePagePrivate; -class CertificateErrorControllerPrivate { +class QWebEngineHistoryItemPrivate : public QSharedData +{ public: - CertificateErrorControllerPrivate(int cert_error, const net::SSLInfo& ssl_info, const GURL& request_url, bool main_frame, bool fatal_error, bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> callback); + QWebEngineHistoryItemPrivate(QtWebEngineCore::WebContentsAdapterClient *adapter = nullptr, + int index = 0); + QtWebEngineCore::WebContentsAdapterClient *m_adapter; + int index; +}; - void accept(bool accepted); +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineHistoryPrivate +{ +public: + QWebEngineHistoryPrivate(QtWebEngineCore::WebContentsAdapterClient *adapter); + ~QWebEngineHistoryPrivate(); + void updateItems() const; - CertificateErrorController::CertificateError certError; - const QUrl requestUrl; - QDateTime validStart; - QDateTime validExpiry; - CertificateErrorController::ResourceType resourceType; - bool fatalError; - bool strictEnforcement; - base::OnceCallback<void(content::CertificateRequestResultType)> callback; - QList<QSslCertificate> certificateChain; + QtWebEngineCore::WebContentsAdapterClient *m_adapter; + mutable QList<QWebEngineHistoryItem> items; }; QT_END_NAMESPACE -#endif // CERTIFICATE_ERROR_CONTROLLER_P_H +#endif // QWEBENGINEHISTORY_P_H diff --git a/src/core/api/qwebenginehttprequest.cpp b/src/core/api/qwebenginehttprequest.cpp index 3395cc99f..f5733cde4 100644 --- a/src/core/api/qwebenginehttprequest.cpp +++ b/src/core/api/qwebenginehttprequest.cpp @@ -72,7 +72,7 @@ public: QUrl url; QWebEngineHttpRequest::Method method; typedef QPair<QByteArray, QByteArray> HeaderPair; - typedef QVector<HeaderPair> Headers; + typedef QList<HeaderPair> Headers; Headers headers; QByteArray postData; @@ -96,7 +96,7 @@ public: Headers::ConstIterator findHeader(const QByteArray &key) const; Headers allHeaders() const; - QVector<QByteArray> headersKeys() const; + QList<QByteArray> headersKeys() const; void setHeader(const QByteArray &key, const QByteArray &value); void unsetHeader(const QByteArray &key); void setAllHeaders(const Headers &list); @@ -293,7 +293,7 @@ QByteArray QWebEngineHttpRequest::header(const QByteArray &headerName) const \sa setHeader(), header(), hasHeader(), unsetHeader() */ -QVector<QByteArray> QWebEngineHttpRequest::headers() const +QList<QByteArray> QWebEngineHttpRequest::headers() const { return d->headersKeys(); } @@ -339,9 +339,9 @@ QWebEngineHttpRequestPrivate::Headers QWebEngineHttpRequestPrivate::allHeaders() return headers; } -QVector<QByteArray> QWebEngineHttpRequestPrivate::headersKeys() const +QList<QByteArray> QWebEngineHttpRequestPrivate::headersKeys() const { - QVector<QByteArray> result; + QList<QByteArray> result; result.reserve(headers.size()); Headers::ConstIterator it = headers.constBegin(), end = headers.constEnd(); for (; it != end; ++it) diff --git a/src/core/api/qwebenginehttprequest.h b/src/core/api/qwebenginehttprequest.h index 1c4d7837b..ce77c04dd 100644 --- a/src/core/api/qwebenginehttprequest.h +++ b/src/core/api/qwebenginehttprequest.h @@ -41,9 +41,9 @@ #define QWEBENGINEHTTPREQUEST_H #include <QtWebEngineCore/qtwebenginecoreglobal.h> -#include <QtCore/qshareddata.h> -#include <QtCore/qvector.h> +#include <QtCore/qlist.h> #include <QtCore/qmap.h> +#include <QtCore/qshareddata.h> #include <QtCore/qstring.h> #include <QtCore/qurl.h> @@ -87,7 +87,7 @@ public: void setPostData(const QByteArray &postData); bool hasHeader(const QByteArray &headerName) const; - QVector<QByteArray> headers() const; + QList<QByteArray> headers() const; QByteArray header(const QByteArray &headerName) const; void setHeader(const QByteArray &headerName, const QByteArray &value); void unsetHeader(const QByteArray &headerName); diff --git a/src/core/api/qwebengineloadrequest.cpp b/src/core/api/qwebengineloadrequest.cpp new file mode 100644 index 000000000..f260e8252 --- /dev/null +++ b/src/core/api/qwebengineloadrequest.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qwebengineloadrequest.h> + +#include <web_engine_error.h> + +QT_BEGIN_NAMESPACE + +using LoadStatus = QWebEngineLoadRequest::LoadStatus; +using ErrorDomain = QWebEngineLoadRequest::ErrorDomain; + +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::NoErrorDomain) == static_cast<int>(ErrorDomain::NoErrorDomain)); +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::InternalErrorDomain) == static_cast<int>(ErrorDomain::InternalErrorDomain)); +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::ConnectionErrorDomain) == static_cast<int>(ErrorDomain::ConnectionErrorDomain)); +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::CertificateErrorDomain) == static_cast<int>(ErrorDomain::CertificateErrorDomain)); +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::HttpErrorDomain) == static_cast<int>(ErrorDomain::HttpErrorDomain)); +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::FtpErrorDomain) == static_cast<int>(ErrorDomain::FtpErrorDomain)); +Q_STATIC_ASSERT(static_cast<int>(WebEngineError::DnsErrorDomain) == static_cast<int>(ErrorDomain::DnsErrorDomain)); + +class QWebEngineLoadRequest::QWebEngineLoadRequestPrivate : public QSharedData { +public: + QWebEngineLoadRequestPrivate(const QUrl& url, LoadStatus status, const QString& errorString, int errorCode, ErrorDomain errorDomain) + : url(url) + , status(status) + , errorString(errorString) + , errorCode(errorCode) + , errorDomain(errorDomain) + { + } + + QUrl url; + LoadStatus status; + QString errorString; + int errorCode; + ErrorDomain errorDomain; +}; + +/*! + \class QWebEngineLoadRequest + \brief A utility type for the WebEngineView::loadingChanged signal. + \inmodule QtWebEngineCore + \since 6.2 + + Contains information about a web page loading status change, such as the URL and + current loading status (started, succeeded, stopped, failed). + + \sa QWebEnginePage::loadStarted, QWebEnginePage::loadFinished, WebEngineView::loadingChanged +*/ +QWebEngineLoadRequest::QWebEngineLoadRequest(const QUrl& url, LoadStatus status, const QString& errorString, + int errorCode, ErrorDomain errorDomain) + : d_ptr(new QWebEngineLoadRequestPrivate(url, status, errorString, errorCode, errorDomain)) +{ +} + +QWebEngineLoadRequest::QWebEngineLoadRequest(const QWebEngineLoadRequest &other) = default; +QWebEngineLoadRequest& QWebEngineLoadRequest::operator=(const QWebEngineLoadRequest &other) = default; +QWebEngineLoadRequest::QWebEngineLoadRequest(QWebEngineLoadRequest &&other) = default; +QWebEngineLoadRequest& QWebEngineLoadRequest::operator=(QWebEngineLoadRequest &&other) = default; + +QWebEngineLoadRequest::~QWebEngineLoadRequest() +{ +} +/*! + \property QWebEngineLoadRequest::url + \brief Holds the URL of the load request. +*/ +/*! + Returns the URL of the load request. +*/ +QUrl QWebEngineLoadRequest::url() const +{ + Q_D(const QWebEngineLoadRequest); + return d->url; +} +/*! + \enum QWebEngineLoadRequest::status + + This enumeration represents the load status of a web page load request: + + \value LoadStartedStatus Page is currently loading. + \value LoadStoppedStatus + Loading the page was stopped by the stop() method or by the loader + code or network stack in Chromium. + \value LoadSucceededStatus Page has been loaded with success. + \value LoadFailedStatus Page could not be loaded. +*/ +/*! + \property Holds the page's load status. +*/ +/*! + Returns the page's load status. +*/ +LoadStatus QWebEngineLoadRequest::status() const +{ + Q_D(const QWebEngineLoadRequest); + return d->status; +} +/*! + \property QWebEngineLoadRequest::errorString + \brief Holds the error message. +*/ +/* + Returns the error message. +*/ +QString QWebEngineLoadRequest::errorString() const +{ + Q_D(const QWebEngineLoadRequest); + return d->errorString; +} +/*! + \enum enumeration QWebEngineLoadRequest::errorDomain + This enumeration holds the type of a load error: + + \value NoErrorDomain + Error type is not known. + \value InternalErrorDomain + Content cannot be interpreted by \QWE. + \value ConnectionErrorDomain + Error results from a faulty network connection. + \value CertificateErrorDomain + Error is related to the SSL/TLS certificate. + \value HttpErrorDomain + Error is related to the HTTP connection. + \value FtpErrorDomain + Error is related to the FTP connection. + \value DnsErrorDomain + Error is related to the DNS connection. +*/ +/* + \property QWebEngineLoadRequest::errorDomain + \brief Holds the error domain +*/ +/* + Returns the error domain. +*/ +ErrorDomain QWebEngineLoadRequest::errorDomain() const +{ + Q_D(const QWebEngineLoadRequest); + return d->errorDomain; +} + +/*! + \property int QWebEngineLoadRequest::errorCode + \brief Holds the error code. +*/ +/* + Returns the error code. +*/ +int QWebEngineLoadRequest::errorCode() const +{ + Q_D(const QWebEngineLoadRequest); + return d->errorCode; +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebengineloadrequest.h b/src/core/api/qwebengineloadrequest.h new file mode 100644 index 000000000..6520d8982 --- /dev/null +++ b/src/core/api/qwebengineloadrequest.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINELOADREQUEST_H +#define QWEBENGINELOADREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QObject> +#include <QUrl> + +QT_BEGIN_NAMESPACE + + +class Q_WEBENGINECORE_EXPORT QWebEngineLoadRequest +{ + Q_GADGET + Q_PROPERTY(QUrl url READ url CONSTANT FINAL) + Q_PROPERTY(LoadStatus status READ status CONSTANT FINAL) + Q_PROPERTY(QString errorString READ errorString CONSTANT FINAL) + Q_PROPERTY(ErrorDomain errorDomain READ errorDomain CONSTANT FINAL) + Q_PROPERTY(int errorCode READ errorCode CONSTANT FINAL) + +public: + enum LoadStatus { + LoadStartedStatus, + LoadStoppedStatus, + LoadSucceededStatus, + LoadFailedStatus + }; + Q_ENUM(LoadStatus) + + enum ErrorDomain { + NoErrorDomain, + InternalErrorDomain, + ConnectionErrorDomain, + CertificateErrorDomain, + HttpErrorDomain, + FtpErrorDomain, + DnsErrorDomain + }; + Q_ENUM(ErrorDomain) + + QWebEngineLoadRequest(const QWebEngineLoadRequest &other); + QWebEngineLoadRequest &operator=(const QWebEngineLoadRequest &other); + QWebEngineLoadRequest(QWebEngineLoadRequest &&other); + QWebEngineLoadRequest &operator=(QWebEngineLoadRequest &&other); + ~QWebEngineLoadRequest(); + + QUrl url() const; + LoadStatus status() const; + QString errorString() const; + ErrorDomain errorDomain() const; + int errorCode() const; + +private: + QWebEngineLoadRequest(const QUrl& url, LoadStatus status, const QString& errorString = QString(), + int errorCode = 0, ErrorDomain errorDomain = NoErrorDomain); + class QWebEngineLoadRequestPrivate; + Q_DECLARE_PRIVATE(QWebEngineLoadRequest) + QExplicitlySharedDataPointer<QWebEngineLoadRequestPrivate> d_ptr; + friend class QQuickWebEngineViewPrivate; + friend class QQuickWebEngineErrorPage; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINELOADREQUEST_H diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp new file mode 100644 index 000000000..c168ca93e --- /dev/null +++ b/src/core/api/qwebenginepage.cpp @@ -0,0 +1,2457 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginepage.h" +#include "qwebenginepage_p.h" + +#include "qwebenginedownloadrequest_p.h" +#include "authentication_dialog_controller.h" +#include "profile_adapter.h" +#include "color_chooser_controller.h" +#include "favicon_manager.h" +#include "find_text_helper.h" +#include "file_picker_controller.h" +#include "javascript_dialog_controller.h" +#if QT_CONFIG(webengine_printing_and_pdf) +#include "printing/printer_worker.h" +#endif +#include "qwebenginecertificateerror.h" +#include "qwebenginefindtextresult.h" +#include "qwebenginefullscreenrequest.h" +#include "qwebenginehistory.h" +#include "qwebenginehistory_p.h" +#include "qwebenginenotification.h" +#include "qwebengineprofile.h" +#include "qwebengineprofile_p.h" +#include "qwebenginequotarequest.h" +#include "qwebengineregisterprotocolhandlerrequest.h" +#include "qwebenginescriptcollection_p.h" +#include "qwebenginesettings.h" +#include "user_notification_controller.h" +#include "render_widget_host_view_qt_delegate.h" +#include "web_contents_adapter.h" +#include "web_engine_settings.h" +#include "qwebenginescript.h" +#include "render_view_context_menu_qt.h" +#include "render_widget_host_view_qt_delegate_client.h" +#include <QAction> +#include <QGuiApplication> +#include <QAuthenticator> +#include <QClipboard> +#include <QKeyEvent> +#include <QIcon> +#include <QLoggingCategory> +#include <QMimeData> +#if QT_CONFIG(webengine_printing_and_pdf) +#include <QPrinter> +#include <QThread> +#endif +#include <QTimer> +#include <QUrl> + +QT_BEGIN_NAMESPACE + +using namespace QtWebEngineCore; + +static const int MaxTooltipLength = 1024; + +// add temporary dummy code to cover the case when page is loading and there is no view +class DummyDelegate : public QObject, public QtWebEngineCore::RenderWidgetHostViewQtDelegate +{ +public: + DummyDelegate(RenderWidgetHostViewQtDelegateClient *client) : m_delegateClient(client) {}; + ~DummyDelegate() = default; + void initAsPopup(const QRect &) override { Q_UNREACHABLE(); } + QRectF viewGeometry() const override { return QRectF(m_pos, m_size); } + void setKeyboardFocus() override { } + bool hasKeyboardFocus() override { return false; } + void lockMouse() override { Q_UNREACHABLE(); } + void unlockMouse() override { Q_UNREACHABLE(); } + void show() override { m_delegateClient->notifyShown(); } + void hide() override { m_delegateClient->notifyHidden(); } + bool isVisible() const override { Q_UNREACHABLE(); } + QWindow *window() const override { return nullptr; } + void updateCursor(const QCursor &cursor) override + { /*setCursor(cursor);*/ + } + void resize(int width, int height) override + { + m_size = QSize(width, height); + m_delegateClient->visualPropertiesChanged(); + } + void move(const QPoint &) override { Q_UNREACHABLE(); } + void inputMethodStateChanged(bool, bool) override { } + void setInputMethodHints(Qt::InputMethodHints) override { } + void setClearColor(const QColor &) override { } + void adapterClientChanged(WebContentsAdapterClient *client) override { } + bool copySurface(const QRect &rect, const QSize &size, QImage &image) + { + Q_UNREACHABLE(); + return false; + } + QRect windowGeometry() const override { return QRect(m_pos, m_size); } + bool forwardEvent(QEvent *ev) { return m_delegateClient->forwardEvent(ev); } + +private: + RenderWidgetHostViewQtDelegateClient *m_delegateClient; + QPoint m_pos; + QSize m_size; +}; + +static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::WindowOpenDisposition disposition) +{ + switch (disposition) { + case WebContentsAdapterClient::NewForegroundTabDisposition: + return QWebEnginePage::WebBrowserTab; + case WebContentsAdapterClient::NewBackgroundTabDisposition: + return QWebEnginePage::WebBrowserBackgroundTab; + case WebContentsAdapterClient::NewPopupDisposition: + return QWebEnginePage::WebDialog; + case WebContentsAdapterClient::NewWindowDisposition: + return QWebEnginePage::WebBrowserWindow; + default: + Q_UNREACHABLE(); + } +} + +QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) + : adapter(QSharedPointer<WebContentsAdapter>::create()) + , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this))) + , profile(_profile ? _profile : QWebEngineProfile::defaultProfile()) + , settings(new QWebEngineSettings(profile->settings())) + , view(0) + , isLoading(false) + , scriptCollection(new QWebEngineScriptCollectionPrivate(profileAdapter()->userResourceController(), adapter)) + , m_isBeingAdopted(false) + , m_backgroundColor(Qt::white) + , fullscreenMode(false) + , webChannel(nullptr) + , webChannelWorldId(QWebEngineScript::MainWorld) + , defaultAudioMuted(false) + , defaultZoomFactor(1.0) +#if QT_CONFIG(webengine_printing_and_pdf) + , currentPrinter(nullptr) +#endif +{ + memset(actions, 0, sizeof(actions)); + + qRegisterMetaType<QWebEngineQuotaRequest>(); + qRegisterMetaType<QWebEngineRegisterProtocolHandlerRequest>(); + qRegisterMetaType<QWebEngineFindTextResult>(); + + // See setVisible(). + wasShownTimer.setSingleShot(true); + QObject::connect(&wasShownTimer, &QTimer::timeout, [this](){ + ensureInitialized(); + }); + + profile->d_ptr->addWebContentsAdapterClient(this); +} + +QWebEnginePagePrivate::~QWebEnginePagePrivate() +{ + delete history; + delete settings; + profile->d_ptr->removeWebContentsAdapterClient(this); +} + +RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) +{ + // Set the QWebEngineView as the parent for a popup delegate, so that the new popup window + // responds properly to clicks in case the QWebEngineView is inside a modal QDialog. Setting the + // parent essentially notifies the OS that the popup window is part of the modal session, and + // should allow interaction. + // The new delegate will not be deleted by the parent view though, because we unset the parent + // when the parent is destroyed. The delegate will be destroyed by Chromium when the popup is + // dismissed. + return view ? view->CreateRenderWidgetHostViewQtDelegate(client) : new DummyDelegate(client); +} + +void QWebEnginePagePrivate::initializationFinished() +{ + if (m_backgroundColor != Qt::white) + adapter->setBackgroundColor(m_backgroundColor); +#if QT_CONFIG(webengine_webchannel) + if (webChannel) + adapter->setWebChannel(webChannel, webChannelWorldId); +#endif + if (defaultAudioMuted != adapter->isAudioMuted()) + adapter->setAudioMuted(defaultAudioMuted); + if (!qFuzzyCompare(adapter->currentZoomFactor(), defaultZoomFactor)) + adapter->setZoomFactor(defaultZoomFactor); + if (view) + adapter->setVisible(view->isVisible()); + + scriptCollection.d->initializationFinished(adapter); + + m_isBeingAdopted = false; +} + +void QWebEnginePagePrivate::titleChanged(const QString &title) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->titleChanged(title); +} + +void QWebEnginePagePrivate::urlChanged() +{ + Q_Q(QWebEnginePage); + QUrl qurl = adapter->activeUrl(); + if (url != qurl) { + url = qurl; + Q_EMIT q->urlChanged(qurl); + } +} + +void QWebEnginePagePrivate::iconChanged(const QUrl &url) +{ + Q_Q(QWebEnginePage); + if (iconUrl == url) + return; + iconUrl = url; + Q_EMIT q->iconUrlChanged(iconUrl); + Q_EMIT q->iconChanged(adapter->faviconManager()->getIcon()); +} + +void QWebEnginePagePrivate::loadProgressChanged(int progress) +{ + Q_Q(QWebEnginePage); + QTimer::singleShot(0, q, [q, progress] () { Q_EMIT q->loadProgress(progress); }); +} + +void QWebEnginePagePrivate::didUpdateTargetURL(const QUrl &hoveredUrl) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->linkHovered(hoveredUrl.toString()); +} + +void QWebEnginePagePrivate::selectionChanged() +{ + Q_Q(QWebEnginePage); + QTimer::singleShot(0, q, [this, q]() { + updateEditActions(); + Q_EMIT q->selectionChanged(); + }); +} + +void QWebEnginePagePrivate::recentlyAudibleChanged(bool recentlyAudible) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->recentlyAudibleChanged(recentlyAudible); +} + +void QWebEnginePagePrivate::renderProcessPidChanged(qint64 pid) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->renderProcessPidChanged(pid); +} + +QRectF QWebEnginePagePrivate::viewportRect() const +{ + return view ? view->viewportRect() : QRectF(); +} + +QColor QWebEnginePagePrivate::backgroundColor() const +{ + return m_backgroundColor; +} + +void QWebEnginePagePrivate::loadStarted(const QUrl &provisionalUrl, bool isErrorPage) +{ + Q_UNUSED(provisionalUrl); + Q_Q(QWebEnginePage); + + if (isErrorPage) + return; + + isLoading = true; + + QTimer::singleShot(0, q, &QWebEnginePage::loadStarted); +} + +void QWebEnginePagePrivate::loadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, + const QString &errorDescription, bool triggersErrorPage) +{ + Q_Q(QWebEnginePage); + Q_UNUSED(url); + Q_UNUSED(errorCode); + Q_UNUSED(errorDescription); + + if (isErrorPage) { + QTimer::singleShot(0, q, [q](){ + emit q->loadFinished(false); + }); + return; + } + + isLoading = false; + Q_ASSERT((success && !triggersErrorPage) || !success); + if (!triggersErrorPage) { + QTimer::singleShot(0, q, [q, success](){ + emit q->loadFinished(success); + }); + } +} + +void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool success) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->pdfPrintingFinished(filePath, success); +} + +void QWebEnginePagePrivate::focusContainer() +{ + if (view) { + view->focusContainer(); + } +} + +void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) +{ + if (view) { + view->unhandledKeyEvent(event); + } +} + +QSharedPointer<WebContentsAdapter> +QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, + WindowOpenDisposition disposition, bool userGesture, + const QRect &initialGeometry, const QUrl &targetUrl) +{ + Q_Q(QWebEnginePage); + Q_UNUSED(userGesture); + Q_UNUSED(targetUrl); + + QWebEnginePage *newPage = q->createWindow(toWindowType(disposition)); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (!newPage) + return nullptr; +#else + if (!newPage) + return adapter; +#endif + + if (!newWebContents->webContents()) + return newPage->d_func()->adapter; // Reuse existing adapter + + // 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 + // Chromium does not get a mouse move acknowledgment message between the two events, and + // InputRouterImpl::ProcessMouseAck is not executed, thus all subsequent mouse move events + // get coalesced together, and don't get processed at all. + // The mouse move events are actually sent as a result of show() being called on + // RenderWidgetHostViewQtDelegateWidget, both when creating the window and when initialize is + // called. + newPage->d_func()->m_isBeingAdopted = true; + + // Overwrite the new page's WebContents with ours. + newPage->d_func()->adapter = newWebContents; + newWebContents->setClient(newPage->d_func()); + + if (!initialGeometry.isEmpty()) + emit newPage->geometryChangeRequested(initialGeometry); + + return newWebContents; +} + +bool QWebEnginePagePrivate::isBeingAdopted() +{ + return m_isBeingAdopted; +} + +void QWebEnginePagePrivate::close() +{ + Q_Q(QWebEnginePage); + Q_EMIT q->windowCloseRequested(); +} + +void QWebEnginePagePrivate::windowCloseRejected() +{ + // Do nothing for now. +} + +void QWebEnginePagePrivate::didRunJavaScript(quint64 requestId, const QVariant& result) +{ + m_callbacks.invoke(requestId, result); +} + +void QWebEnginePagePrivate::didFetchDocumentMarkup(quint64 requestId, const QString& result) +{ + m_callbacks.invoke(requestId, result); +} + +void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const QString& result) +{ + m_callbacks.invoke(requestId, result); +} + +void QWebEnginePagePrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) +{ +#if QT_CONFIG(webengine_printing_and_pdf) + Q_Q(QWebEnginePage); + + // If no currentPrinter is set that means that were printing to PDF only. + if (!currentPrinter) { + if (!result.data()) + return; + m_callbacks.invoke(requestId, *(result.data())); + return; + } + + QThread *printerThread = new QThread; + QObject::connect(printerThread, &QThread::finished, printerThread, &QThread::deleteLater); + printerThread->start(); + + PrinterWorker *printerWorker = new PrinterWorker(result, currentPrinter); + QObject::connect(printerWorker, &PrinterWorker::resultReady, q, [requestId, this](bool success) { + currentPrinter = nullptr; + m_callbacks.invoke(requestId, success); + }); + + QObject::connect(printerWorker, &PrinterWorker::resultReady, printerThread, &QThread::quit); + QObject::connect(printerThread, &QThread::finished, printerWorker, &PrinterWorker::deleteLater); + + printerWorker->moveToThread(printerThread); + QMetaObject::invokeMethod(printerWorker, "print"); + +#else + // we should never enter this branch, but just for safe-keeping... + Q_UNUSED(result); + m_callbacks.invoke(requestId, QByteArray()); +#endif +} + +bool QWebEnginePagePrivate::passOnFocus(bool reverse) +{ + return view ? view->passOnFocus(reverse) : false; +} + +void QWebEnginePagePrivate::authenticationRequired(QSharedPointer<AuthenticationDialogController> controller) +{ + Q_Q(QWebEnginePage); + QAuthenticator networkAuth; + networkAuth.setRealm(controller->realm()); + + if (controller->isProxy()) + Q_EMIT q->proxyAuthenticationRequired(controller->url(), &networkAuth, controller->host()); + else + Q_EMIT q->authenticationRequired(controller->url(), &networkAuth); + + // Authentication has been cancelled + if (networkAuth.isNull()) { + controller->reject(); + return; + } + + controller->accept(networkAuth.user(), networkAuth.password()); +} + +void QWebEnginePagePrivate::releaseProfile() +{ + qWarning("Release of profile requested but WebEnginePage still not deleted. Expect troubles !"); + // this is not the way to go, but might avoid the crash if user code does not make any calls to page. + delete q_ptr->d_ptr.take(); +} + +void QWebEnginePagePrivate::showColorDialog(QSharedPointer<ColorChooserController> controller) +{ + if (view) + view->showColorDialog(controller); +} + +void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags requestFlags) +{ + Q_Q(QWebEnginePage); + QWebEnginePage::Feature feature; + if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && + requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + feature = QWebEnginePage::MediaAudioVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) + feature = QWebEnginePage::MediaAudioCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + feature = QWebEnginePage::MediaVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) && + requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + feature = QWebEnginePage::DesktopAudioVideoCapture; + else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + feature = QWebEnginePage::DesktopVideoCapture; + Q_EMIT q->featurePermissionRequested(securityOrigin, feature); +} + +static QWebEnginePage::Feature toFeature(QtWebEngineCore::ProfileAdapter::PermissionType type) +{ + switch (type) { + case QtWebEngineCore::ProfileAdapter::NotificationPermission: + return QWebEnginePage::Notifications; + case QtWebEngineCore::ProfileAdapter::GeolocationPermission: + return QWebEnginePage::Geolocation; + default: + break; + } + Q_UNREACHABLE(); + return QWebEnginePage::Feature(-1); +} + +void QWebEnginePagePrivate::runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, toFeature(permission)); +} + +void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock); +} + +void QWebEnginePagePrivate::runQuotaRequest(QWebEngineQuotaRequest request) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->quotaRequested(request); +} + +void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest request) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->registerProtocolHandlerRequested(request); +} + +QObject *QWebEnginePagePrivate::accessibilityParentObject() +{ + return view ? view->accessibilityParentObject() : nullptr; +} + +void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const +{ +#ifdef QT_NO_ACTION + Q_UNUSED(action); +#else + QAction *a = actions[action]; + if (!a) + return; + + bool enabled = true; + + switch (action) { + case QWebEnginePage::Back: + enabled = adapter->canGoToOffset(-1); + break; + case QWebEnginePage::Forward: + enabled = adapter->canGoToOffset(1); + break; + case QWebEnginePage::Stop: + enabled = isLoading; + break; + case QWebEnginePage::Reload: + case QWebEnginePage::ReloadAndBypassCache: + enabled = !isLoading; + break; + case QWebEnginePage::ViewSource: + enabled = adapter->canViewSource(); + break; + case QWebEnginePage::Cut: + case QWebEnginePage::Copy: + case QWebEnginePage::Unselect: + enabled = adapter->hasFocusedFrame() && !adapter->selectedText().isEmpty(); + break; + case QWebEnginePage::Paste: + case QWebEnginePage::Undo: + case QWebEnginePage::Redo: + case QWebEnginePage::SelectAll: + case QWebEnginePage::PasteAndMatchStyle: + enabled = adapter->hasFocusedFrame(); + break; + default: + break; + } + + a->setEnabled(enabled); +#endif // QT_NO_ACTION +} + +void QWebEnginePagePrivate::updateNavigationActions() +{ + updateAction(QWebEnginePage::Back); + updateAction(QWebEnginePage::Forward); + updateAction(QWebEnginePage::Stop); + updateAction(QWebEnginePage::Reload); + updateAction(QWebEnginePage::ReloadAndBypassCache); + updateAction(QWebEnginePage::ViewSource); +} + +void QWebEnginePagePrivate::updateEditActions() +{ + updateAction(QWebEnginePage::Cut); + updateAction(QWebEnginePage::Copy); + updateAction(QWebEnginePage::Paste); + updateAction(QWebEnginePage::Undo); + updateAction(QWebEnginePage::Redo); + updateAction(QWebEnginePage::SelectAll); + updateAction(QWebEnginePage::PasteAndMatchStyle); + updateAction(QWebEnginePage::Unselect); +} + +#ifndef QT_NO_ACTION +void QWebEnginePagePrivate::_q_webActionTriggered(bool checked) +{ + Q_Q(QWebEnginePage); + QAction *a = qobject_cast<QAction *>(q->sender()); + if (!a) + return; + QWebEnginePage::WebAction action = static_cast<QWebEnginePage::WebAction>(a->data().toInt()); + q->triggerAction(action, checked); +} +#endif // QT_NO_ACTION + +void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) +{ + QSharedPointer<WebContentsAdapter> newWebContents = WebContentsAdapter::createFromSerializedNavigationHistory(input, this); + if (newWebContents) { + adapter = std::move(newWebContents); + adapter->setClient(this); + adapter->loadDefault(); + } +} + +void QWebEnginePagePrivate::updateScrollPosition(const QPointF &position) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->scrollPositionChanged(position); +} + +void QWebEnginePagePrivate::updateContentsSize(const QSizeF &size) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->contentsSizeChanged(size); +} + +void QWebEnginePagePrivate::setFullScreenMode(bool fullscreen) +{ + if (fullscreenMode != fullscreen) { + fullscreenMode = fullscreen; + adapter->changedFullScreen(); + } +} + +ProfileAdapter* QWebEnginePagePrivate::profileAdapter() +{ + return profile->d_ptr->profileAdapter(); +} + +WebContentsAdapter *QWebEnginePagePrivate::webContentsAdapter() +{ + ensureInitialized(); + return adapter.data(); +} + +const QObject *QWebEnginePagePrivate::holdingQObject() const +{ + Q_Q(const QWebEnginePage); + return q; +} + +void QWebEnginePagePrivate::findTextFinished(const QWebEngineFindTextResult &result) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->findTextFinished(result); +} + +void QWebEnginePagePrivate::ensureInitialized() const +{ + if (!adapter->isInitialized()) + adapter->loadDefault(); +} + +QWebEnginePage::QWebEnginePage(QObject* parent) + : QObject(parent) + , d_ptr(new QWebEnginePagePrivate()) +{ + Q_D(QWebEnginePage); + d->q_ptr = this; + d->adapter->setClient(d); +} + +/*! + \fn void QWebEnginePage::findTextFinished(const QWebEngineFindTextResult &result) + \since 5.14 + + This signal is emitted when a search string search on a page is completed. \a result is + the result of the string search. + + \sa findText() +*/ + +/*! + \fn void QWebEnginePage::printRequested() + \since 5.12 + + This signal is emitted when the JavaScript \c{window.print()} method is called. + Typically, the signal handler can simply call printToPdf(). + + \sa printToPdf() +*/ + +/*! + \enum QWebEnginePage::RenderProcessTerminationStatus + \since 5.6 + + This enum describes the status with which the render process terminated: + + \value NormalTerminationStatus + The render process terminated normally. + \value AbnormalTerminationStatus + The render process terminated with with a non-zero exit status. + \value CrashedTerminationStatus + The render process crashed, for example because of a segmentation fault. + \value KilledTerminationStatus + The render process was killed, for example by \c SIGKILL or task manager kill. +*/ + +/*! + \fn QWebEnginePage::renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) + \since 5.6 + + This signal is emitted when the render process is terminated with a non-zero exit status. + \a terminationStatus is the termination status of the process and \a exitCode is the status code + with which the process terminated. +*/ + +/*! + \fn QWebEnginePage::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) + + This signal is emitted when the web page issues the request to enter fullscreen mode for + a web-element, usually a video element. + + The request object \a fullScreenRequest can be used to accept or reject the request. + + If the request is accepted the element requesting fullscreen will fill the viewport, + but it is up to the application to make the view fullscreen or move the page to a view + that is fullscreen. + + \sa QWebEngineSettings::FullScreenSupportEnabled +*/ + +/*! + \fn QWebEnginePage::quotaRequested(QWebEngineQuotaRequest quotaRequest) + \since 5.11 + + This signal is emitted when the web page requests larger persistent storage + than the application's current allocation in File System API. The default quota + is 0 bytes. + + The request object \a quotaRequest can be used to accept or reject the request. +*/ + +/*! + \fn QWebEnginePage::registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest + request) \since 5.11 + + This signal is emitted when the web page tries to register a custom protocol + using the \l registerProtocolHandler API. + + The request object \a request can be used to accept or reject the request: + + \snippet webenginewidgets/simplebrowser/webview.cpp registerProtocolHandlerRequested +*/ + +/*! + \fn void QWebEnginePage::pdfPrintingFinished(const QString &filePath, bool success) + \since 5.9 + + This signal is emitted when printing the web page into a PDF file has + finished. + \a filePath will contain the path the file was requested to be created + at, and \a success will be \c true if the file was successfully created and + \c false otherwise. + + \sa printToPdf() +*/ + +/*! + \property QWebEnginePage::scrollPosition + \since 5.7 + + \brief The scroll position of the page contents. +*/ + +/*! + \property QWebEnginePage::contentsSize + \since 5.7 + + \brief The size of the page contents. +*/ + +/*! + \fn void QWebEnginePage::audioMutedChanged(bool muted) + \since 5.7 + + This signal is emitted when the page's \a muted state changes. + \note Not to be confused with a specific HTML5 audio or video element being muted. +*/ + +/*! + \fn void QWebEnginePage::recentlyAudibleChanged(bool recentlyAudible); + \since 5.7 + + This signal is emitted when the page's audible state, \a recentlyAudible, changes, because + the audio is played or stopped. + + \note The signal is also emitted when calling the setAudioMuted() method. + Also, if the audio is paused, this signal is emitted with an approximate \b{two-second + delay}, from the moment the audio is paused. +*/ + +/*! + \fn void QWebEnginePage::renderProcessPidChanged(qint64 pid); + \since 5.15 + + This signal is emitted when the underlying render process PID, \a renderProcessPid, changes. +*/ + +/*! + \fn void QWebEnginePage::iconUrlChanged(const QUrl &url) + + This signal is emitted when the URL of the icon ("favicon") associated with the + page is changed. The new URL is specified by \a url. + + \sa iconUrl(), icon(), iconChanged() +*/ + +/*! + \fn void QWebEnginePage::iconChanged(const QIcon &icon) + \since 5.7 + + This signal is emitted when the icon ("favicon") associated with the + page is changed. The new icon is specified by \a icon. + + \sa icon(), iconUrl(), iconUrlChanged() +*/ + +/*! + Constructs an empty web engine page in the web engine profile \a profile with the parent + \a parent. + + If the profile is not the default profile, the caller must ensure that the profile stays alive + for as long as the page does. + + \since 5.5 +*/ +QWebEnginePage::QWebEnginePage(QWebEngineProfile *profile, QObject* parent) + : QObject(parent) + , d_ptr(new QWebEnginePagePrivate(profile)) +{ + Q_D(QWebEnginePage); + d->q_ptr = this; + d->adapter->setClient(d); +} + +QWebEnginePage::~QWebEnginePage() +{ + if (d_ptr) { + // d_ptr might be exceptionally null if profile adapter got deleted first + setDevToolsPage(nullptr); + emit _q_aboutToDelete(); + } +} + +QWebEngineHistory *QWebEnginePage::history() const +{ + Q_D(const QWebEnginePage); + return d->history; +} + +QWebEngineSettings *QWebEnginePage::settings() const +{ + Q_D(const QWebEnginePage); + return d->settings; +} + +/*! + * Returns a pointer to the web channel instance used by this page or a null pointer if none was set. + * This channel automatically uses the internal web engine transport mechanism over Chromium IPC + * that is exposed in the JavaScript context of this page as \c qt.webChannelTransport. + * + * \since 5.5 + * \sa setWebChannel() + */ +QWebChannel *QWebEnginePage::webChannel() const +{ +#if QT_CONFIG(webengine_webchannel) + Q_D(const QWebEnginePage); + return d->webChannel; +#endif + qWarning("WebEngine compiled without webchannel support"); + return nullptr; +} + +/*! + * \overload + * + * Sets the web channel instance to be used by this page to \a channel and installs + * it in the main JavaScript world. + * + * With this method the web channel can be accessed by web page content. If the content + * is not under your control and might be hostile, this could be a security issue and + * you should consider installing it in a private JavaScript world. + * + * \since 5.5 + * \sa QWebEngineScript::MainWorld + */ + +void QWebEnginePage::setWebChannel(QWebChannel *channel) +{ + setWebChannel(channel, QWebEngineScript::MainWorld); +} + +/*! + * Sets the web channel instance to be used by this page to \a channel and connects it to + * web engine's transport using Chromium IPC messages. The transport is exposed in the JavaScript + * world \a worldId as + * \c qt.webChannelTransport, which should be used when using the \l{Qt WebChannel JavaScript API}. + * + * \note The page does not take ownership of the channel object. + * \note Only one web channel can be installed per page, setting one even in another JavaScript + * world uninstalls any already installed web channel. + * + * \since 5.7 + * \sa QWebEngineScript::ScriptWorldId + */ +void QWebEnginePage::setWebChannel(QWebChannel *channel, uint worldId) +{ +#if QT_CONFIG(webengine_webchannel) + Q_D(QWebEnginePage); + if (d->webChannel != channel || d->webChannelWorldId != worldId) { + d->webChannel = channel; + d->webChannelWorldId = worldId; + d->adapter->setWebChannel(channel, worldId); + } +#else + Q_UNUSED(channel); + Q_UNUSED(worldId); + qWarning("WebEngine compiled without webchannel support"); +#endif +} + +/*! + \property QWebEnginePage::backgroundColor + \brief The page's background color behind the document's body. + \since 5.6 + + You can set the background color to Qt::transparent or to a translucent + color to see through the document, or you can set it to match your + web content in a hybrid application to prevent the white flashes that may appear + during loading. + + The default value is white. +*/ +QColor QWebEnginePage::backgroundColor() const +{ + Q_D(const QWebEnginePage); + return d->m_backgroundColor; +} + +void QWebEnginePage::setBackgroundColor(const QColor &color) +{ + Q_D(QWebEnginePage); + if (d->m_backgroundColor == color) + return; + d->m_backgroundColor = color; + d->adapter->setBackgroundColor(color); +} + +/*! + * Save the currently loaded web page to disk. + * + * The web page is saved to \a filePath in the specified \a{format}. + * + * This is a short cut for the following actions: + * \list + * \li Trigger the Save web action. + * \li Accept the next download item and set the specified file path and save format. + * \endlist + * + * This function issues an asynchronous download request for the web page and returns immediately. + * + * \sa QWebEngineDownloadRequest::SavePageFormat + * \since 5.8 + */ +void QWebEnginePage::save(const QString &filePath, + QWebEngineDownloadRequest::SavePageFormat format) const +{ + Q_D(const QWebEnginePage); + d->ensureInitialized(); + d->adapter->save(filePath, format); +} + +/*! + \property QWebEnginePage::audioMuted + \brief Whether the current page audio is muted. + \since 5.7 + + The default value is \c false. + \sa recentlyAudible +*/ +bool QWebEnginePage::isAudioMuted() const { + Q_D(const QWebEnginePage); + if (d->adapter->isInitialized()) + return d->adapter->isAudioMuted(); + return d->defaultAudioMuted; +} + +void QWebEnginePage::setAudioMuted(bool muted) { + Q_D(QWebEnginePage); + bool wasAudioMuted = isAudioMuted(); + d->defaultAudioMuted = muted; + d->adapter->setAudioMuted(muted); + if (wasAudioMuted != isAudioMuted()) + Q_EMIT audioMutedChanged(muted); +} + +/*! + \property QWebEnginePage::recentlyAudible + \brief The current page's \e {audible state}, that is, whether audio was recently played + or not. + \since 5.7 + + The default value is \c false. + \sa audioMuted +*/ +bool QWebEnginePage::recentlyAudible() const +{ + Q_D(const QWebEnginePage); + return d->adapter->isInitialized() && d->adapter->recentlyAudible(); +} + +/*! + \property QWebEnginePage::renderProcessPid + \brief The process ID (PID) of the render process assigned to the current + page's main frame. + \since 5.15 + + If no render process is available yet, \c 0 is returned. +*/ +qint64 QWebEnginePage::renderProcessPid() const +{ + Q_D(const QWebEnginePage); + return d->adapter->renderProcessPid(); +} + +/*! + Returns the web engine profile the page belongs to. + \since 5.5 +*/ +QWebEngineProfile *QWebEnginePage::profile() const +{ + Q_D(const QWebEnginePage); + return d->profile; +} + +bool QWebEnginePage::hasSelection() const +{ + return !selectedText().isEmpty(); +} + +QString QWebEnginePage::selectedText() const +{ + Q_D(const QWebEnginePage); + return d->adapter->selectedText(); +} + +#ifndef QT_NO_ACTION +QAction *QWebEnginePage::action(WebAction action) const +{ + Q_D(const QWebEnginePage); + if (action == QWebEnginePage::NoWebAction) + return 0; + if (d->actions[action]) + return d->actions[action]; + + QString text; + switch (action) { + case Back: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Back); + break; + case Forward: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Forward); + break; + case Stop: + text = tr("Stop"); + break; + case Reload: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Reload); + break; + case ReloadAndBypassCache: + text = tr("Reload and Bypass Cache"); + break; + case Cut: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Cut); + break; + case Copy: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Copy); + break; + case Paste: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Paste); + break; + case Undo: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Undo); + break; + case Redo: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Redo); + break; + case SelectAll: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SelectAll); + break; + case PasteAndMatchStyle: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::PasteAndMatchStyle); + break; + case OpenLinkInThisWindow: + text = tr("Open link in this window"); + break; + case OpenLinkInNewWindow: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewWindow); + break; + case OpenLinkInNewTab: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewTab); + break; + case OpenLinkInNewBackgroundTab: + text = tr("Open link in new background tab"); + break; + case CopyLinkToClipboard: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyLinkToClipboard); + break; + case DownloadLinkToDisk: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadLinkToDisk); + break; + case CopyImageToClipboard: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageToClipboard); + break; + case CopyImageUrlToClipboard: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageUrlToClipboard); + break; + case DownloadImageToDisk: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadImageToDisk); + break; + case CopyMediaUrlToClipboard: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyMediaUrlToClipboard); + break; + case ToggleMediaControls: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaControls); + break; + case ToggleMediaLoop: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaLoop); + break; + case ToggleMediaPlayPause: + text = tr("Toggle Play/Pause"); + break; + case ToggleMediaMute: + text = tr("Toggle Mute"); + break; + case DownloadMediaToDisk: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadMediaToDisk); + break; + case InspectElement: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::InspectElement); + break; + case ExitFullScreen: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ExitFullScreen); + break; + case RequestClose: + text = tr("Close Page"); + break; + case Unselect: + text = tr("Unselect"); + break; + case SavePage: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SavePage); + break; + case ViewSource: + text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ViewSource); + break; + case ToggleBold: + text = tr("&Bold"); + break; + case ToggleItalic: + text = tr("&Italic"); + break; + case ToggleUnderline: + text = tr("&Underline"); + break; + case ToggleStrikethrough: + text = tr("&Strikethrough"); + break; + case AlignLeft: + text = tr("Align &Left"); + break; + case AlignCenter: + text = tr("Align &Center"); + break; + case AlignRight: + text = tr("Align &Right"); + break; + case AlignJustified: + text = tr("Align &Justified"); + break; + case Indent: + text = tr("&Indent"); + break; + case Outdent: + text = tr("&Outdent"); + break; + case InsertOrderedList: + text = tr("Insert &Ordered List"); + break; + case InsertUnorderedList: + text = tr("Insert &Unordered List"); + break; + case NoWebAction: + case WebActionCount: + Q_UNREACHABLE(); + break; + } + + QAction *a = new QAction(const_cast<QWebEnginePage*>(this)); + a->setText(text); + a->setData(action); + + connect(a, SIGNAL(triggered(bool)), this, SLOT(_q_webActionTriggered(bool))); + + d->actions[action] = a; + d->updateAction(action); + return a; +} +#endif // QT_NO_ACTION + +void QWebEnginePage::triggerAction(WebAction action, bool) +{ + Q_D(QWebEnginePage); + d->ensureInitialized(); + switch (action) { + case Back: + d->adapter->navigateBack(); + break; + case Forward: + d->adapter->navigateForward(); + break; + case Stop: + d->adapter->stop(); + break; + case Reload: + d->adapter->reload(); + break; + case ReloadAndBypassCache: + d->adapter->reloadAndBypassCache(); + break; + case Cut: + d->adapter->cut(); + break; + case Copy: + d->adapter->copy(); + break; + case Paste: + d->adapter->paste(); + break; + case Undo: + d->adapter->undo(); + break; + case Redo: + d->adapter->redo(); + break; + case SelectAll: + d->adapter->selectAll(); + break; + case PasteAndMatchStyle: + d->adapter->pasteAndMatchStyle(); + break; + case Unselect: + d->adapter->unselect(); + break; + case OpenLinkInThisWindow: + if (d->view && d->view->lastContextMenuRequest()->filteredLinkUrl().isValid()) + setUrl(d->view->lastContextMenuRequest()->filteredLinkUrl()); + break; + case OpenLinkInNewWindow: + if (d->view && d->view->lastContextMenuRequest()->filteredLinkUrl().isValid()) { + QWebEnginePage *newPage = createWindow(WebBrowserWindow); + if (newPage) + newPage->setUrl(d->view->lastContextMenuRequest()->filteredLinkUrl()); + } + break; + case OpenLinkInNewTab: + if (d->view && d->view->lastContextMenuRequest()->filteredLinkUrl().isValid()) { + QWebEnginePage *newPage = createWindow(WebBrowserTab); + if (newPage) + newPage->setUrl(d->view->lastContextMenuRequest()->filteredLinkUrl()); + } + break; + case OpenLinkInNewBackgroundTab: + if (d->view && d->view->lastContextMenuRequest()->filteredLinkUrl().isValid()) { + QWebEnginePage *newPage = createWindow(WebBrowserBackgroundTab); + if (newPage) + newPage->setUrl(d->view->lastContextMenuRequest()->filteredLinkUrl()); + } + break; + case CopyLinkToClipboard: + if (d->view && !d->view->lastContextMenuRequest()->linkUrl().isEmpty()) { + QString urlString = d->view->lastContextMenuRequest()->linkUrl().toString( + QUrl::FullyEncoded); + QString linkText = d->view->lastContextMenuRequest()->linkText().toHtmlEscaped(); + QString title = d->view->lastContextMenuRequest()->titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); + QMimeData *data = new QMimeData(); + data->setText(urlString); + QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral(">") + + linkText + QStringLiteral("</a>"); + data->setHtml(html); + data->setUrls(QList<QUrl>() << d->view->lastContextMenuRequest()->linkUrl()); + QGuiApplication::clipboard()->setMimeData(data); + } + break; + case DownloadLinkToDisk: + if (d->view && d->view->lastContextMenuRequest()->filteredLinkUrl().isValid()) + d->adapter->download(d->view->lastContextMenuRequest()->filteredLinkUrl(), + d->view->lastContextMenuRequest()->suggestedFileName(), + d->view->lastContextMenuRequest()->referrerUrl(), + d->view->lastContextMenuRequest()->referrerPolicy()); + + break; + case CopyImageToClipboard: + if (d->view && d->view->lastContextMenuRequest()->hasImageContent() + && (d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeImage + || d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeCanvas)) { + d->adapter->copyImageAt(d->view->lastContextMenuRequest()->position()); + } + break; + case CopyImageUrlToClipboard: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid() + && d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeImage) { + QString urlString = + d->view->lastContextMenuRequest()->mediaUrl().toString(QUrl::FullyEncoded); + QString alt = d->view->lastContextMenuRequest()->altText(); + if (!alt.isEmpty()) + alt = QStringLiteral(" alt=\"%1\"").arg(alt.toHtmlEscaped()); + QString title = d->view->lastContextMenuRequest()->titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); + QMimeData *data = new QMimeData(); + data->setText(urlString); + QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + alt + QStringLiteral("></img>"); + data->setHtml(html); + data->setUrls(QList<QUrl>() << d->view->lastContextMenuRequest()->mediaUrl()); + QGuiApplication::clipboard()->setMimeData(data); + } + break; + case DownloadImageToDisk: + case DownloadMediaToDisk: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid()) + d->adapter->download(d->view->lastContextMenuRequest()->mediaUrl(), + d->view->lastContextMenuRequest()->suggestedFileName(), + d->view->lastContextMenuRequest()->referrerUrl(), + d->view->lastContextMenuRequest()->referrerPolicy()); + break; + case CopyMediaUrlToClipboard: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid() + && (d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeAudio + || d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeVideo)) { + QString urlString = + d->view->lastContextMenuRequest()->mediaUrl().toString(QUrl::FullyEncoded); + QString title = d->view->lastContextMenuRequest()->titleText(); + if (!title.isEmpty()) + title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); + QMimeData *data = new QMimeData(); + data->setText(urlString); + if (d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeAudio) + data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"") + title + + QStringLiteral("></audio>")); + else + data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"") + title + + QStringLiteral("></video>")); + data->setUrls(QList<QUrl>() << d->view->lastContextMenuRequest()->mediaUrl()); + QGuiApplication::clipboard()->setMimeData(data); + } + break; + case ToggleMediaControls: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid() + && d->view->lastContextMenuRequest()->mediaFlags() + & QWebEngineContextMenuRequest::MediaCanToggleControls) { + bool enable = !(d->view->lastContextMenuRequest()->mediaFlags() + & QWebEngineContextMenuRequest::MediaControls); + d->adapter->executeMediaPlayerActionAt(d->view->lastContextMenuRequest()->position(), + WebContentsAdapter::MediaPlayerControls, enable); + } + break; + case ToggleMediaLoop: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid() + && (d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeAudio + || d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeVideo)) { + bool enable = !(d->view->lastContextMenuRequest()->mediaFlags() + & QWebEngineContextMenuRequest::MediaLoop); + d->adapter->executeMediaPlayerActionAt(d->view->lastContextMenuRequest()->position(), + WebContentsAdapter::MediaPlayerLoop, enable); + } + break; + case ToggleMediaPlayPause: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid() + && (d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeAudio + || d->view->lastContextMenuRequest()->mediaType() + == QWebEngineContextMenuRequest::MediaTypeVideo)) { + bool enable = (d->view->lastContextMenuRequest()->mediaFlags() + & QWebEngineContextMenuRequest::MediaPaused); + d->adapter->executeMediaPlayerActionAt(d->view->lastContextMenuRequest()->position(), + WebContentsAdapter::MediaPlayerPlay, enable); + } + break; + case ToggleMediaMute: + if (d->view && d->view->lastContextMenuRequest()->mediaUrl().isValid() + && d->view->lastContextMenuRequest()->mediaFlags() + & QWebEngineContextMenuRequest::MediaHasAudio) { + // Make sure to negate the value, so that toggling actually works. + bool enable = !(d->view->lastContextMenuRequest()->mediaFlags() + & QWebEngineContextMenuRequest::MediaMuted); + d->adapter->executeMediaPlayerActionAt(d->view->lastContextMenuRequest()->position(), + WebContentsAdapter::MediaPlayerMute, enable); + } + break; + case InspectElement: + if (d->view) + d->adapter->inspectElementAt(d->view->lastContextMenuRequest()->position()); + break; + case ExitFullScreen: + // See under ViewSource, anything that can trigger a delete of the current view is dangerous to call directly here. + QTimer::singleShot(0, this, [d](){ d->adapter->exitFullScreen(); }); + break; + case RequestClose: + d->adapter->requestClose(); + break; + case SavePage: + d->adapter->save(); + break; + case ViewSource: + // This is a workaround to make the ViewSource action working in a context menu. + // The WebContentsAdapter::viewSource() method deletes a + // RenderWidgetHostViewQtDelegateWidget instance which passes the control to the event + // loop. If the QMenu::aboutToHide() signal is connected to the QObject::deleteLater() + // slot the QMenu is deleted by the event handler while the ViewSource action is still not + // completed. This may lead to a crash. To avoid this the WebContentsAdapter::viewSource() + // method is called indirectly via the QTimer::singleShot() function which schedules the + // the viewSource() call after the QMenu's destruction. + QTimer::singleShot(0, this, [d](){ d->adapter->viewSource(); }); + break; + case ToggleBold: + runJavaScript(QStringLiteral("document.execCommand('bold');"), QWebEngineScript::ApplicationWorld); + break; + case ToggleItalic: + runJavaScript(QStringLiteral("document.execCommand('italic');"), QWebEngineScript::ApplicationWorld); + break; + case ToggleUnderline: + runJavaScript(QStringLiteral("document.execCommand('underline');"), QWebEngineScript::ApplicationWorld); + break; + case ToggleStrikethrough: + runJavaScript(QStringLiteral("document.execCommand('strikethrough');"), QWebEngineScript::ApplicationWorld); + break; + case AlignLeft: + runJavaScript(QStringLiteral("document.execCommand('justifyLeft');"), QWebEngineScript::ApplicationWorld); + break; + case AlignCenter: + runJavaScript(QStringLiteral("document.execCommand('justifyCenter');"), QWebEngineScript::ApplicationWorld); + break; + case AlignRight: + runJavaScript(QStringLiteral("document.execCommand('justifyRight');"), QWebEngineScript::ApplicationWorld); + break; + case AlignJustified: + runJavaScript(QStringLiteral("document.execCommand('justifyFull');"), QWebEngineScript::ApplicationWorld); + break; + case Indent: + runJavaScript(QStringLiteral("document.execCommand('indent');"), QWebEngineScript::ApplicationWorld); + break; + case Outdent: + runJavaScript(QStringLiteral("document.execCommand('outdent');"), QWebEngineScript::ApplicationWorld); + break; + case InsertOrderedList: + runJavaScript(QStringLiteral("document.execCommand('insertOrderedList');"), QWebEngineScript::ApplicationWorld); + break; + case InsertUnorderedList: + runJavaScript(QStringLiteral("document.execCommand('insertUnorderedList');"), QWebEngineScript::ApplicationWorld); + break; + case NoWebAction: + break; + case WebActionCount: + Q_UNREACHABLE(); + break; + } +} + +/*! + * \since 5.8 + * Replace the current misspelled word with \a replacement. + * + * The current misspelled word can be found in QWebEngineContextMenuRequest::misspelledWord(), + * and suggested replacements in QWebEngineContextMenuRequest::spellCheckerSuggestions(). + * + * \sa contextMenuData(), + */ + +void QWebEnginePage::replaceMisspelledWord(const QString &replacement) +{ + Q_D(QWebEnginePage); + d->adapter->replaceMisspelling(replacement); +} + +void QWebEnginePage::findText(const QString &subString, FindFlags options, const QWebEngineCallback<bool> &resultCallback) +{ + Q_D(QWebEnginePage); + if (!d->adapter->isInitialized()) { + QtWebEngineCore::CallbackDirectory().invokeEmpty(resultCallback); + return; + } + + d->adapter->findTextHelper()->startFinding(subString, options & FindCaseSensitively, options & FindBackward, resultCallback); +} + +/*! + * \reimp + */ +bool QWebEnginePage::event(QEvent *e) +{ + return QObject::event(e); +} + +void QWebEnginePagePrivate::contextMenuRequested(QWebEngineContextMenuRequest *data) +{ + if (view) + view->contextMenuRequested(data); +} + +void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) +{ + Q_Q(QWebEnginePage); + bool accepted = q->acceptNavigationRequest(url, static_cast<QWebEnginePage::NavigationType>(navigationType), isMainFrame); + if (accepted && adapter->findTextHelper()->isFindTextInProgress()) + adapter->findTextHelper()->stopFinding(); + navigationRequestAction = accepted ? WebContentsAdapterClient::AcceptRequest : WebContentsAdapterClient::IgnoreRequest; +} + +void QWebEnginePagePrivate::requestFullScreenMode(const QUrl &origin, bool fullscreen) +{ + Q_Q(QWebEnginePage); + QWebEngineFullScreenRequest request(origin, fullscreen, [q = QPointer(q)] (bool toggleOn) { if (q) q->d_ptr->setFullScreenMode(toggleOn); }); + Q_EMIT q->fullScreenRequested(std::move(request)); +} + +bool QWebEnginePagePrivate::isFullScreenMode() const +{ + return fullscreenMode; +} + +void QWebEnginePagePrivate::javascriptDialog(QSharedPointer<JavaScriptDialogController> controller) +{ + Q_Q(QWebEnginePage); + bool accepted = false; + QString promptResult; + switch (controller->type()) { + case AlertDialog: + q->javaScriptAlert(controller->securityOrigin(), controller->message()); + accepted = true; + break; + case ConfirmDialog: + accepted = q->javaScriptConfirm(controller->securityOrigin(), controller->message()); + break; + case PromptDialog: + accepted = q->javaScriptPrompt(controller->securityOrigin(), controller->message(), controller->defaultPrompt(), &promptResult); + if (accepted) + controller->textProvided(promptResult); + break; + case UnloadDialog: + accepted = q->javaScriptConfirm(controller->securityOrigin(), QCoreApplication::translate("QWebEnginePage", "Are you sure you want to leave this page? Changes that you made may not be saved.")); + break; + case InternalAuthorizationDialog: + accepted = view ? view->showAuthorizationDialog(controller->title(), controller->message()) + : false; + break; + } + if (accepted) + controller->accept(); + else + controller->reject(); +} + +void QWebEnginePagePrivate::allowCertificateError(const QWebEngineCertificateError &error) +{ + Q_Q(QWebEnginePage); + q->certificateError(error); +} + +void QWebEnginePagePrivate::selectClientCert(const QSharedPointer<ClientCertSelectController> &controller) +{ + Q_Q(QWebEnginePage); + QWebEngineClientCertificateSelection certSelection(controller); + + Q_EMIT q->selectClientCertificate(certSelection); +} + +/*! + \fn void QWebEnginePage::selectClientCertificate(QWebEngineClientCertificateSelection clientCertificateSelection) + \since 5.12 + + This signal is emitted when a web site requests an SSL client certificate, and one or more were + found in system's client certificate store. + + Handling the signal is asynchronous, and loading will be waiting until a certificate is selected, + or the last copy of \a clientCertificateSelection is destroyed. + + If the signal is not handled, \a clientCertificateSelection is automatically destroyed, and loading + will continue without a client certificate. + + \sa QWebEngineClientCertificateSelection +*/ + +void QWebEnginePagePrivate::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) +{ + Q_Q(QWebEnginePage); + q->javaScriptConsoleMessage(static_cast<QWebEnginePage::JavaScriptConsoleMessageLevel>(level), message, lineNumber, sourceID); +} + +void QWebEnginePagePrivate::renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, + int exitCode) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->renderProcessTerminated(static_cast<QWebEnginePage::RenderProcessTerminationStatus>( + terminationStatus), exitCode); +} + +void QWebEnginePagePrivate::requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) +{ + Q_UNUSED(geometry); + Q_Q(QWebEnginePage); + Q_EMIT q->geometryChangeRequested(frameGeometry); +} + +QObject *QWebEnginePagePrivate::dragSource() const +{ +#if !QT_CONFIG(draganddrop) + return view; +#else + return nullptr; +#endif // QT_CONFIG(draganddrop) +} + +bool QWebEnginePagePrivate::isEnabled() const +{ + if (view) + return view->isEnabled(); + return true; +} + +void QWebEnginePagePrivate::setToolTip(const QString &toolTipText) +{ + if (view) + view->setToolTip(toolTipText); +} + +void QWebEnginePagePrivate::printRequested() +{ + Q_Q(QWebEnginePage); + QTimer::singleShot(0, q, [q](){ + Q_EMIT q->printRequested(); + }); +} + +void QWebEnginePagePrivate::lifecycleStateChanged(LifecycleState state) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->lifecycleStateChanged(static_cast<QWebEnginePage::LifecycleState>(state)); +} + +void QWebEnginePagePrivate::recommendedStateChanged(LifecycleState state) +{ + Q_Q(QWebEnginePage); + QTimer::singleShot(0, q, [q, state]() { + Q_EMIT q->recommendedStateChanged(static_cast<QWebEnginePage::LifecycleState>(state)); + }); +} + +void QWebEnginePagePrivate::visibleChanged(bool visible) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->visibleChanged(visible); +} + +/*! + \since 5.13 + + Registers the request interceptor \a interceptor to intercept URL requests. + + The page does not take ownership of the pointer. This interceptor is called + after any interceptors on the profile, and unlike profile interceptors, only + URL requests from this page are intercepted. + + To unset the request interceptor, set a \c nullptr. + + \sa QWebEngineUrlRequestInfo, QWebEngineProfile::setUrlRequestInterceptor() +*/ + +void QWebEnginePage::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + Q_D(QWebEnginePage); + d->adapter->setRequestInterceptor(interceptor); +} + +void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy) +{ + Q_D(QWebEnginePage); + if (policy == PermissionUnknown) { + switch (feature) { + case MediaAudioVideoCapture: + case MediaAudioCapture: + case MediaVideoCapture: + case DesktopAudioVideoCapture: + case DesktopVideoCapture: + case MouseLock: + break; + case Geolocation: + d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AskPermission); + break; + case Notifications: + d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AskPermission); + break; + } + return; + } + + const WebContentsAdapterClient::MediaRequestFlags audioVideoCaptureFlags( + WebContentsAdapterClient::MediaVideoCapture | + WebContentsAdapterClient::MediaAudioCapture); + const WebContentsAdapterClient::MediaRequestFlags desktopAudioVideoCaptureFlags( + WebContentsAdapterClient::MediaDesktopVideoCapture | + WebContentsAdapterClient::MediaDesktopAudioCapture); + + if (policy == PermissionGrantedByUser) { + switch (feature) { + case MediaAudioVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, audioVideoCaptureFlags); + break; + case MediaAudioCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaAudioCapture); + break; + case MediaVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaVideoCapture); + break; + case DesktopAudioVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, desktopAudioVideoCaptureFlags); + break; + case DesktopVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaDesktopVideoCapture); + break; + case MouseLock: + d->adapter->grantMouseLockPermission(securityOrigin, true); + break; + case Geolocation: + d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AllowedPermission); + break; + case Notifications: + d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AllowedPermission); + break; + } + } else { // if (policy == PermissionDeniedByUser) + switch (feature) { + case MediaAudioVideoCapture: + case MediaAudioCapture: + case MediaVideoCapture: + case DesktopAudioVideoCapture: + case DesktopVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone); + break; + case Geolocation: + d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::DeniedPermission); + break; + case MouseLock: + d->adapter->grantMouseLockPermission(securityOrigin, false); + break; + case Notifications: + d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::DeniedPermission); + break; + } + } +} + +static inline QWebEnginePage::FileSelectionMode toPublic(FilePickerController::FileChooserMode mode) +{ + // Should the underlying values change, we'll need a switch here. + return static_cast<QWebEnginePage::FileSelectionMode>(mode); +} + +void QWebEnginePagePrivate::runFileChooser(QSharedPointer<FilePickerController> controller) +{ + Q_Q(QWebEnginePage); + + QStringList selectedFileNames = q->chooseFiles(toPublic(controller->mode()), (QStringList() << controller->defaultFileName()), controller->acceptedMimeTypes()); + + if (!selectedFileNames.empty()) + controller->accepted(selectedFileNames); + else + controller->rejected(); +} + +QWebEngineSettings *QWebEnginePagePrivate::webEngineSettings() const +{ + return settings; +} + +/*! + \since 5.10 + Downloads the resource from the location given by \a url to a local file. + + If \a filename is given, it is used as the suggested file name. + If it is relative, the file is saved in the standard download location with + the given name. + If it is a null or empty QString, the default file name is used. + + This will emit QWebEngineProfile::downloadRequested() after the download + has started. +*/ + +void QWebEnginePage::download(const QUrl& url, const QString& filename) +{ + Q_D(QWebEnginePage); + d->ensureInitialized(); + d->adapter->download(url, filename); +} + +void QWebEnginePage::load(const QUrl& url) +{ + Q_D(QWebEnginePage); + d->adapter->load(url); +} + +/*! + \since 5.9 + Issues the specified \a request and loads the response. + + \sa load(), setUrl(), url(), urlChanged(), QUrl::fromUserInput() +*/ +void QWebEnginePage::load(const QWebEngineHttpRequest& request) +{ + Q_D(QWebEnginePage); + d->adapter->load(request); +} + +void QWebEnginePage::toHtml(const QWebEngineCallback<const QString &> &resultCallback) const +{ + Q_D(const QWebEnginePage); + d->ensureInitialized(); + quint64 requestId = d->adapter->fetchDocumentMarkup(); + d->m_callbacks.registerCallback(requestId, resultCallback); +} + +void QWebEnginePage::toPlainText(const QWebEngineCallback<const QString &> &resultCallback) const +{ + Q_D(const QWebEnginePage); + d->ensureInitialized(); + quint64 requestId = d->adapter->fetchDocumentInnerText(); + d->m_callbacks.registerCallback(requestId, resultCallback); +} + +void QWebEnginePage::setHtml(const QString &html, const QUrl &baseUrl) +{ + setContent(html.toUtf8(), QStringLiteral("text/html;charset=UTF-8"), baseUrl); +} + +void QWebEnginePage::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl) +{ + Q_D(QWebEnginePage); + d->adapter->setContent(data, mimeType, baseUrl); +} + +QString QWebEnginePage::title() const +{ + Q_D(const QWebEnginePage); + return d->adapter->pageTitle(); +} + +void QWebEnginePage::setUrl(const QUrl &url) +{ + Q_D(QWebEnginePage); + if (d->url != url) { + d->url = url; + emit urlChanged(url); + } + load(url); +} + +QUrl QWebEnginePage::url() const +{ + Q_D(const QWebEnginePage); + return d->url; +} + +QUrl QWebEnginePage::requestedUrl() const +{ + Q_D(const QWebEnginePage); + return d->adapter->requestedUrl(); +} + +/*! + \property QWebEnginePage::iconUrl + \brief The URL of the icon associated with the page currently viewed. + + By default, this property contains an empty URL. + + \sa iconUrlChanged(), icon(), iconChanged() +*/ +QUrl QWebEnginePage::iconUrl() const +{ + Q_D(const QWebEnginePage); + return d->iconUrl; +} + +/*! + \property QWebEnginePage::icon + \brief The icon associated with the page currently viewed. + \since 5.7 + + By default, this property contains a null icon. If the web page specifies more than one icon, + the \c{icon} property encapsulates the available candidate icons in a single, + scalable \c{QIcon}. + + \sa iconChanged(), iconUrl(), iconUrlChanged() +*/ +QIcon QWebEnginePage::icon() const +{ + Q_D(const QWebEnginePage); + + if (d->iconUrl.isEmpty() || !d->adapter->isInitialized()) + return QIcon(); + + return d->adapter->faviconManager()->getIcon(); +} + +qreal QWebEnginePage::zoomFactor() const +{ + Q_D(const QWebEnginePage); + if (d->adapter->isInitialized()) + return d->adapter->currentZoomFactor(); + return d->defaultZoomFactor; +} + +void QWebEnginePage::setZoomFactor(qreal factor) +{ + Q_D(QWebEnginePage); + d->defaultZoomFactor = factor; + if (d->adapter->isInitialized()) + d->adapter->setZoomFactor(factor); +} + +void QWebEnginePage::runJavaScript(const QString &scriptSource) +{ + Q_D(QWebEnginePage); + d->ensureInitialized(); + if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { + qWarning("runJavaScript: disabled in Discarded state"); + return; + } + d->adapter->runJavaScript(scriptSource, QWebEngineScript::MainWorld); +} + +void QWebEnginePage::runJavaScript(const QString& scriptSource, const QWebEngineCallback<const QVariant &> &resultCallback) +{ + Q_D(QWebEnginePage); + d->ensureInitialized(); + if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { + qWarning("runJavaScript: disabled in Discarded state"); + d->m_callbacks.invokeEmpty(resultCallback); + return; + } + quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, QWebEngineScript::MainWorld); + d->m_callbacks.registerCallback(requestId, resultCallback); +} + +void QWebEnginePage::runJavaScript(const QString &scriptSource, quint32 worldId) +{ + Q_D(QWebEnginePage); + d->ensureInitialized(); + d->adapter->runJavaScript(scriptSource, worldId); +} + +void QWebEnginePage::runJavaScript(const QString& scriptSource, quint32 worldId, const QWebEngineCallback<const QVariant &> &resultCallback) +{ + Q_D(QWebEnginePage); + d->ensureInitialized(); + quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, worldId); + d->m_callbacks.registerCallback(requestId, resultCallback); +} + +/*! + Returns the collection of scripts that are injected into the page. + + In addition, a page might also execute scripts + added through QWebEngineProfile::scripts(). + + \sa QWebEngineScriptCollection, QWebEngineScript, {Script Injection} +*/ + +QWebEngineScriptCollection &QWebEnginePage::scripts() +{ + Q_D(QWebEnginePage); + return d->scriptCollection; +} + +QWebEnginePage *QWebEnginePage::createWindow(WebWindowType type) +{ + Q_D(QWebEnginePage); + return d->view ? d->view->createPageForWindow(type) : nullptr; +} + +/*! + \since 5.11 + Returns the page this page is inspecting, if any. + + Returns \c nullptr if this page is not a developer tools page. + + \sa setInspectedPage(), devToolsPage() +*/ + +QWebEnginePage *QWebEnginePage::inspectedPage() const +{ + Q_D(const QWebEnginePage); + return d->inspectedPage; +} + +/*! + \since 5.11 + Navigates this page to an internal URL that is the developer + tools of \a page. + + This is the same as calling setDevToolsPage() on \a page + with \c this as argument. + + \sa inspectedPage(), setDevToolsPage() +*/ + +void QWebEnginePage::setInspectedPage(QWebEnginePage *page) +{ + Q_D(QWebEnginePage); + if (d->inspectedPage == page) + return; + QWebEnginePage *oldPage = d->inspectedPage; + d->inspectedPage = nullptr; + if (oldPage) + oldPage->setDevToolsPage(nullptr); + d->inspectedPage = page; + if (page) + page->setDevToolsPage(this); +} + +/*! + \since 5.11 + Returns the page that is hosting the developer tools + of this page, if any. + + Returns \c nullptr if no developer tools page is set. + + \sa setDevToolsPage(), inspectedPage() +*/ + +QWebEnginePage *QWebEnginePage::devToolsPage() const +{ + Q_D(const QWebEnginePage); + return d->devToolsPage; +} + +/*! + \since 5.11 + Binds \a devToolsPage to be the developer tools of this page. + Triggers \a devToolsPage to navigate to an internal URL + with the developer tools. + + This is the same as calling setInspectedPage() on \a devToolsPage + with \c this as argument. + + \sa devToolsPage(), setInspectedPage() +*/ + +void QWebEnginePage::setDevToolsPage(QWebEnginePage *devToolsPage) +{ + Q_D(QWebEnginePage); + if (d->devToolsPage == devToolsPage) + return; + d->ensureInitialized(); + QWebEnginePage *oldDevTools = d->devToolsPage; + d->devToolsPage = nullptr; + if (oldDevTools) + oldDevTools->setInspectedPage(nullptr); + d->devToolsPage = devToolsPage; + if (devToolsPage) + devToolsPage->setInspectedPage(this); + if (d->adapter) { + if (devToolsPage) + d->adapter->openDevToolsFrontend(devToolsPage->d_ptr->adapter); + else + d->adapter->closeDevToolsFrontend(); + } +} + +ASSERT_ENUMS_MATCH(FilePickerController::Open, QWebEnginePage::FileSelectOpen) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, QWebEnginePage::FileSelectOpenMultiple) + +// TODO: remove virtuals +QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) +{ + Q_D(const QWebEnginePage); + return d->view ? d->view->chooseFiles(mode, oldFiles, acceptedMimeTypes) : QStringList(); +} + +void QWebEnginePage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg) +{ + Q_UNUSED(securityOrigin); + Q_D(const QWebEnginePage); + if (d->view) + d->view->javaScriptAlert(url(), msg); +} + +bool QWebEnginePage::javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) +{ + Q_UNUSED(securityOrigin); + Q_D(const QWebEnginePage); + return d->view ? d->view->javaScriptConfirm(url(), msg) : false; +} + +bool QWebEnginePage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString *result) +{ + Q_UNUSED(securityOrigin); + Q_D(const QWebEnginePage); + return d->view ? d->view->javaScriptPrompt(url(), msg, defaultValue, result) : false; +} + +void QWebEnginePage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) +{ + static QLoggingCategory loggingCategory("js", QtWarningMsg); + static QByteArray file = sourceID.toUtf8(); + QMessageLogger logger(file.constData(), lineNumber, nullptr, loggingCategory.categoryName()); + + switch (level) { + case JavaScriptConsoleMessageLevel::InfoMessageLevel: + if (loggingCategory.isInfoEnabled()) + logger.info().noquote() << message; + break; + case JavaScriptConsoleMessageLevel::WarningMessageLevel: + if (loggingCategory.isWarningEnabled()) + logger.warning().noquote() << message; + break; + case JavaScriptConsoleMessageLevel::ErrorMessageLevel: + if (loggingCategory.isCriticalEnabled()) + logger.critical().noquote() << message; + break; + } +} + +void QWebEnginePage::certificateError(QWebEngineCertificateError) { } + +bool QWebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) +{ + Q_UNUSED(url); + Q_UNUSED(type); + Q_UNUSED(isMainFrame); + return true; +} + +QPointF QWebEnginePage::scrollPosition() const +{ + Q_D(const QWebEnginePage); + return d->adapter->lastScrollOffset(); +} + +QSizeF QWebEnginePage::contentsSize() const +{ + Q_D(const QWebEnginePage); + return d->adapter->lastContentsSize(); +} + +/*! + Renders the current content of the page into a PDF document and saves it + in the location specified in \a filePath. + The page size and orientation of the produced PDF document are taken from + the values specified in \a pageLayout. + + This method issues an asynchronous request for printing the web page into + a PDF and returns immediately. + To be informed about the result of the request, connect to the signal + pdfPrintingFinished(). + + If a file already exists at the provided file path, it will be overwritten. + \since 5.7 + \sa pdfPrintingFinished() +*/ +void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &pageLayout) +{ +#if QT_CONFIG(webengine_printing_and_pdf) + Q_D(const QWebEnginePage); + if (d->currentPrinter) { + qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); + return; + } + d->ensureInitialized(); + d->adapter->printToPDF(pageLayout, filePath); +#else + Q_UNUSED(filePath); + Q_UNUSED(pageLayout); +#endif +} + + +/*! + Renders the current content of the page into a PDF document and returns a byte array containing the PDF data + as parameter to \a resultCallback. + The page size and orientation of the produced PDF document are taken from the values specified in \a pageLayout. + + The \a resultCallback must take a const reference to a QByteArray as parameter. If printing was successful, this byte array + will contain the PDF data, otherwise, the byte array will be empty. + + \warning We guarantee that the callback (\a resultCallback) is always called, but it might be done + during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid + value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it. + + \since 5.7 +*/ +void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &pageLayout) +{ + Q_D(QWebEnginePage); +#if QT_CONFIG(webengine_printing_and_pdf) + if (d->currentPrinter) { + qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); + d->m_callbacks.invokeEmpty(resultCallback); + return; + } + d->ensureInitialized(); + quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout); + d->m_callbacks.registerCallback(requestId, resultCallback); +#else + Q_UNUSED(pageLayout); + d->m_callbacks.invokeEmpty(resultCallback); +#endif +} + +/*! + Renders the current content of the page into a temporary PDF document, then prints it using \a printer. + + The settings for creating and printing the PDF document will be retrieved from the \a printer + object. + It is the users responsibility to ensure the \a printer remains valid until \a resultCallback + has been called. + + \note Printing runs on the browser process, which is by default not sandboxed. + + The \a resultCallback must take a boolean as parameter. If printing was successful, this + boolean will have the value \c true, otherwise, its value will be \c false. + + \warning We guarantee that the callback (\a resultCallback) is always called, but it might be done + during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid + value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it. + + \since 5.8 +*/ +void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback) +{ + Q_D(QWebEnginePage); +#if QT_CONFIG(webengine_printing_and_pdf) + if (d->currentPrinter) { + qWarning("Cannot print page on printer %ls: Already printing on %ls.", qUtf16Printable(printer->printerName()), qUtf16Printable(d->currentPrinter->printerName())); + d->m_callbacks.invokeDirectly(resultCallback, false); + return; + } + d->currentPrinter = printer; + d->ensureInitialized(); + quint64 requestId = d->adapter->printToPDFCallbackResult(printer->pageLayout(), + printer->colorMode() == QPrinter::Color, + false); + d->m_callbacks.registerCallback(requestId, resultCallback); +#else + Q_UNUSED(printer); + d->m_callbacks.invokeDirectly(resultCallback, false); +#endif +} + + +/*! + \enum QWebEnginePage::LifecycleState + \since 5.14 + + This enum describes the lifecycle state of the page: + + \value Active + Normal state. + \value Frozen + Low CPU usage state where most HTML task sources are suspended. + \value Discarded + Very low resource usage state where the entire browsing context is discarded. + + \sa lifecycleState, {Page Lifecycle API}, {WebEngine Lifecycle Example} +*/ + +/*! + \property QWebEnginePage::lifecycleState + \since 5.14 + + \brief The current lifecycle state of the page. + + The following restrictions are enforced by the setter: + + \list + \li A \l{visible} page must remain in the \c{Active} state. + \li If the page is being inspected by a \l{devToolsPage} then both pages must + remain in the \c{Active} states. + \li A page in the \c{Discarded} state can only transition to the \c{Active} + state. This will cause a reload of the page. + \endlist + + These are the only hard limits on the lifecycle state, but see also + \l{recommendedState} for the recommended soft limits. + + \sa recommendedState, {Page Lifecycle API}, {WebEngine Lifecycle Example} +*/ + +QWebEnginePage::LifecycleState QWebEnginePage::lifecycleState() const +{ + Q_D(const QWebEnginePage); + return static_cast<LifecycleState>(d->adapter->lifecycleState()); +} + +void QWebEnginePage::setLifecycleState(LifecycleState state) +{ + Q_D(QWebEnginePage); + d->adapter->setLifecycleState(static_cast<WebContentsAdapterClient::LifecycleState>(state)); +} + +/*! + \property QWebEnginePage::recommendedState + \since 5.14 + + \brief The recommended limit for the lifecycle state of the page. + + Setting the lifecycle state to a lower resource usage state than the + recommended state may cause side-effects such as stopping background audio + playback or loss of HTML form input. Setting the lifecycle state to a higher + resource state is however completely safe. + + \sa lifecycleState, {Page Lifecycle API}, {WebEngine Lifecycle Example} +*/ + +QWebEnginePage::LifecycleState QWebEnginePage::recommendedState() const +{ + Q_D(const QWebEnginePage); + return static_cast<LifecycleState>(d->adapter->recommendedState()); +} + +/*! + \property QWebEnginePage::visible + \since 5.14 + + \brief Whether the page is considered visible in the Page Visibility API. + + Setting this property changes the \c{Document.hidden} and the + \c{Document.visibilityState} properties in JavaScript which web sites can use + to voluntarily reduce their resource usage if they are not visible to the + user. + + If the page is connected to a \l{view} then this property will be managed + automatically by the view according to it's own visibility. + + \sa lifecycleState +*/ + +bool QWebEnginePage::isVisible() const +{ + Q_D(const QWebEnginePage); + return d->adapter->isVisible(); +} + +void QWebEnginePage::setVisible(bool visible) +{ + Q_D(QWebEnginePage); + + if (!d->adapter->isInitialized()) { + // On the one hand, it is too early to initialize here. The application + // may call show() before load(), or it may call show() from + // createWindow(), and then we would create an unnecessary blank + // WebContents here. On the other hand, if the application calls show() + // then it expects something to be shown, so we have to initialize. + // Therefore we have to delay the initialization via the event loop. + if (visible) + d->wasShownTimer.start(); + else + d->wasShownTimer.stop(); + return; + } + + d->adapter->setVisible(visible); +} + +QWebEnginePage* QWebEnginePage::fromDownloadRequest(QWebEngineDownloadRequest *request) { + return static_cast<QWebEnginePagePrivate *>(request->d_ptr->m_adapterClient)->q_ptr; +} + +QDataStream &operator<<(QDataStream &stream, const QWebEngineHistory &history) +{ + QtWebEngineCore::WebContentsAdapter *adapter = + history.d_func()->m_adapter->webContentsAdapter(); + if (!adapter->isInitialized()) + adapter->loadDefault(); + adapter->serializeNavigationHistory(stream); + return stream; +} + +QDataStream &operator>>(QDataStream &stream, QWebEngineHistory &history) +{ + static_cast<QWebEnginePagePrivate *>(history.d_func()->m_adapter) + ->recreateFromSerializedHistory(stream); + return stream; +} + +QT_END_NAMESPACE + +#include "moc_qwebenginepage.cpp" diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h new file mode 100644 index 000000000..09b7b54df --- /dev/null +++ b/src/core/api/qwebenginepage.h @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEPAGE_H +#define QWEBENGINEPAGE_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtWebEngineCore/qwebengineclientcertificateselection.h> +#include <QtWebEngineCore/qwebenginedownloadrequest.h> +#include <QtWebEngineCore/qwebenginecallback.h> +#include <QtWebEngineCore/qwebenginehttprequest.h> + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtCore/qvariant.h> +#include <QtGui/qpagelayout.h> +#include <QtGui/qaction.h> +#include <QtNetwork/qnetworkaccessmanager.h> + +QT_BEGIN_NAMESPACE +class QMenu; +class QPrinter; + +class QContextMenuBuilder; +class QWebChannel; +class QWebEngineCertificateError; +class QWebEngineClientCertificateSelection; +class QWebEngineFindTextResult; +class QWebEngineFullScreenRequest; +class QWebEngineHistory; +class QWebEnginePage; +class QWebEnginePagePrivate; +class QWebEngineProfile; +class QWebEngineQuotaRequest; +class QWebEngineRegisterProtocolHandlerRequest; +class QWebEngineScriptCollection; +class QWebEngineSettings; +class QWebEngineUrlRequestInterceptor; + +class Q_WEBENGINECORE_EXPORT QWebEnginePage : public QObject { + Q_OBJECT + Q_PROPERTY(QString selectedText READ selectedText) + Q_PROPERTY(bool hasSelection READ hasSelection) + Q_PROPERTY(QUrl requestedUrl READ requestedUrl) + Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor) + Q_PROPERTY(QString title READ title) + Q_PROPERTY(QUrl url READ url WRITE setUrl) + Q_PROPERTY(QUrl iconUrl READ iconUrl NOTIFY iconUrlChanged) + Q_PROPERTY(QIcon icon READ icon NOTIFY iconChanged) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor) + Q_PROPERTY(QSizeF contentsSize READ contentsSize NOTIFY contentsSizeChanged) + Q_PROPERTY(QPointF scrollPosition READ scrollPosition NOTIFY scrollPositionChanged) + Q_PROPERTY(bool audioMuted READ isAudioMuted WRITE setAudioMuted NOTIFY audioMutedChanged) + Q_PROPERTY(bool recentlyAudible READ recentlyAudible NOTIFY recentlyAudibleChanged) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(LifecycleState lifecycleState READ lifecycleState WRITE setLifecycleState NOTIFY lifecycleStateChanged) + Q_PROPERTY(LifecycleState recommendedState READ recommendedState NOTIFY recommendedStateChanged) + Q_PROPERTY(qint64 renderProcessPid READ renderProcessPid NOTIFY renderProcessPidChanged) + +public: + enum WebAction { + NoWebAction = - 1, + Back, + Forward, + Stop, + Reload, + + Cut, + Copy, + Paste, + + Undo, + Redo, + SelectAll, + ReloadAndBypassCache, + + PasteAndMatchStyle, + + OpenLinkInThisWindow, + OpenLinkInNewWindow, + OpenLinkInNewTab, + CopyLinkToClipboard, + DownloadLinkToDisk, + + CopyImageToClipboard, + CopyImageUrlToClipboard, + DownloadImageToDisk, + + CopyMediaUrlToClipboard, + ToggleMediaControls, + ToggleMediaLoop, + ToggleMediaPlayPause, + ToggleMediaMute, + DownloadMediaToDisk, + + InspectElement, + ExitFullScreen, + RequestClose, + Unselect, + SavePage, + OpenLinkInNewBackgroundTab, + ViewSource, + + ToggleBold, + ToggleItalic, + ToggleUnderline, + ToggleStrikethrough, + + AlignLeft, + AlignCenter, + AlignRight, + AlignJustified, + Indent, + Outdent, + + InsertOrderedList, + InsertUnorderedList, + + WebActionCount + }; + Q_ENUM(WebAction) + + enum FindFlag { + FindBackward = 1, + FindCaseSensitively = 2, + }; + Q_DECLARE_FLAGS(FindFlags, FindFlag) + + enum WebWindowType { + WebBrowserWindow, + WebBrowserTab, + WebDialog, + WebBrowserBackgroundTab + }; + Q_ENUM(WebWindowType) + + enum PermissionPolicy { + PermissionUnknown, + PermissionGrantedByUser, + PermissionDeniedByUser + }; + Q_ENUM(PermissionPolicy) + + // must match WebContentsAdapterClient::NavigationType + enum NavigationType { + NavigationTypeLinkClicked, + NavigationTypeTyped, + NavigationTypeFormSubmitted, + NavigationTypeBackForward, + NavigationTypeReload, + NavigationTypeOther, + NavigationTypeRedirect, + }; + Q_ENUM(NavigationType) + + enum Feature { + Notifications = 0, + Geolocation = 1, + MediaAudioCapture = 2, + MediaVideoCapture, + MediaAudioVideoCapture, + MouseLock, + DesktopVideoCapture, + DesktopAudioVideoCapture + }; + Q_ENUM(Feature) + + // Ex-QWebFrame enum + + enum FileSelectionMode { + FileSelectOpen, + FileSelectOpenMultiple, + }; + Q_ENUM(FileSelectionMode) + + // must match WebContentsAdapterClient::JavaScriptConsoleMessageLevel + enum JavaScriptConsoleMessageLevel { + InfoMessageLevel = 0, + WarningMessageLevel, + ErrorMessageLevel + }; + Q_ENUM(JavaScriptConsoleMessageLevel) + + // must match WebContentsAdapterClient::RenderProcessTerminationStatus + enum RenderProcessTerminationStatus { + NormalTerminationStatus = 0, + AbnormalTerminationStatus, + CrashedTerminationStatus, + KilledTerminationStatus + }; + Q_ENUM(RenderProcessTerminationStatus) + + // must match WebContentsAdapterClient::LifecycleState + enum class LifecycleState { + Active, + Frozen, + Discarded, + }; + Q_ENUM(LifecycleState) + + explicit QWebEnginePage(QObject *parent = Q_NULLPTR); + QWebEnginePage(QWebEngineProfile *profile, QObject *parent = Q_NULLPTR); + ~QWebEnginePage(); + QWebEngineHistory *history() const; + + bool hasSelection() const; + QString selectedText() const; + + QWebEngineProfile *profile() const; + +#ifndef QT_NO_ACTION + QAction *action(WebAction action) const; +#endif + virtual void triggerAction(WebAction action, bool checked = false); + + void replaceMisspelledWord(const QString &replacement); + + bool event(QEvent*) override; + + void findText(const QString &subString, FindFlags options = FindFlags(), const QWebEngineCallback<bool> &resultCallback = QWebEngineCallback<bool>()); + + void setFeaturePermission(const QUrl &securityOrigin, Feature feature, PermissionPolicy policy); + + void load(const QUrl &url); + void load(const QWebEngineHttpRequest &request); + void download(const QUrl &url, const QString &filename = QString()); + void setHtml(const QString &html, const QUrl &baseUrl = QUrl()); + void setContent(const QByteArray &data, const QString &mimeType = QString(), const QUrl &baseUrl = QUrl()); + + void toHtml(const QWebEngineCallback<const QString &> &resultCallback) const; + void toPlainText(const QWebEngineCallback<const QString &> &resultCallback) const; + + QString title() const; + void setUrl(const QUrl &url); + QUrl url() const; + QUrl requestedUrl() const; + QUrl iconUrl() const; + QIcon icon() const; + + qreal zoomFactor() const; + void setZoomFactor(qreal factor); + + QPointF scrollPosition() const; + QSizeF contentsSize() const; + + void runJavaScript(const QString& scriptSource); + void runJavaScript(const QString& scriptSource, quint32 worldId); + void runJavaScript(const QString& scriptSource, const QWebEngineCallback<const QVariant &> &resultCallback); + void runJavaScript(const QString& scriptSource, quint32 worldId, const QWebEngineCallback<const QVariant &> &resultCallback); + QWebEngineScriptCollection &scripts(); + QWebEngineSettings *settings() const; + + QWebChannel *webChannel() const; + void setWebChannel(QWebChannel *); + void setWebChannel(QWebChannel *, uint worldId); + QColor backgroundColor() const; + void setBackgroundColor(const QColor &color); + + void save(const QString &filePath, QWebEngineDownloadRequest::SavePageFormat format + = QWebEngineDownloadRequest::MimeHtmlSaveFormat) const; + + bool isAudioMuted() const; + void setAudioMuted(bool muted); + bool recentlyAudible() const; + qint64 renderProcessPid() const; + + void printToPdf(const QString &filePath, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); + void printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); + void print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback); + + void setInspectedPage(QWebEnginePage *page); + QWebEnginePage *inspectedPage() const; + void setDevToolsPage(QWebEnginePage *page); + QWebEnginePage *devToolsPage() const; + + void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); + + LifecycleState lifecycleState() const; + void setLifecycleState(LifecycleState state); + + LifecycleState recommendedState() const; + + bool isVisible() const; + void setVisible(bool visible); + + static QWebEnginePage* fromDownloadRequest(QWebEngineDownloadRequest * request); + +Q_SIGNALS: + void loadStarted(); + void loadProgress(int progress); + void loadFinished(bool ok); + + void linkHovered(const QString &url); + void selectionChanged(); + void geometryChangeRequested(const QRect& geom); + void windowCloseRequested(); + + void featurePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature); + void featurePermissionRequestCanceled(const QUrl &securityOrigin, QWebEnginePage::Feature feature); + void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); + void quotaRequested(QWebEngineQuotaRequest quotaRequest); + void registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request); + void selectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection); + void authenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator); + void proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator, const QString &proxyHost); + + void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode); + + // Ex-QWebFrame signals + void titleChanged(const QString &title); + void urlChanged(const QUrl &url); + void iconUrlChanged(const QUrl &url); + void iconChanged(const QIcon &icon); + + void scrollPositionChanged(const QPointF &position); + void contentsSizeChanged(const QSizeF &size); + void audioMutedChanged(bool muted); + void recentlyAudibleChanged(bool recentlyAudible); + void renderProcessPidChanged(qint64 pid); + + void pdfPrintingFinished(const QString &filePath, bool success); + void printRequested(); + + void visibleChanged(bool visible); + + void lifecycleStateChanged(LifecycleState state); + void recommendedStateChanged(LifecycleState state); + + void findTextFinished(const QWebEngineFindTextResult &result); + + // TODO: fixme / rewrite bindPageToView + void _q_aboutToDelete(); + +protected: + virtual QWebEnginePage *createWindow(WebWindowType type); + virtual QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes); + virtual void javaScriptAlert(const QUrl &securityOrigin, const QString& msg); + virtual bool javaScriptConfirm(const QUrl &securityOrigin, const QString& msg); + virtual bool javaScriptPrompt(const QUrl &securityOrigin, const QString& msg, const QString& defaultValue, QString* result); + virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID); + virtual void certificateError(QWebEngineCertificateError certificateError); + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); +private: + Q_DISABLE_COPY(QWebEnginePage) + Q_DECLARE_PRIVATE(QWebEnginePage) + QScopedPointer<QWebEnginePagePrivate> d_ptr; +#ifndef QT_NO_ACTION + Q_PRIVATE_SLOT(d_func(), void _q_webActionTriggered(bool checked)) +#endif + + friend class QContextMenuBuilder; + friend class QWebEngineFullScreenRequest; + friend class QWebEngineView; + friend class QWebEngineViewPrivate; +#ifndef QT_NO_ACCESSIBILITY + friend class QWebEngineViewAccessible; +#endif // QT_NO_ACCESSIBILITY +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QWebEnginePage::FindFlags) + +Q_WEBENGINECORE_EXPORT QDataStream &operator<<(QDataStream &stream, + const QWebEngineHistory &history); +Q_WEBENGINECORE_EXPORT QDataStream &operator>>(QDataStream &stream, QWebEngineHistory &history); + +QT_END_NAMESPACE + +#endif // QWEBENGINEPAGE_H diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h new file mode 100644 index 000000000..c0652ccc6 --- /dev/null +++ b/src/core/api/qwebenginepage_p.h @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEPAGE_P_H +#define QWEBENGINEPAGE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qwebenginepage.h" + +#include "qwebenginecallback_p.h" +#include "qwebenginescriptcollection.h" +#include "web_contents_adapter_client.h" + +#include <QtCore/qcompilerdetection.h> +#include <QtCore/QPointer> +#include <QtCore/QTimer> + +namespace QtWebEngineCore { +class RenderWidgetHostViewQtDelegate; +class RenderWidgetHostViewQtDelegateWidget; +class RenderWidgetHostViewQtDelegateClient; +class TouchHandleDrawableClient; +class TouchSelectionMenuController; +class WebContentsAdapter; +} + +QT_BEGIN_NAMESPACE +class QWebEngineFindTextResult; +class QWebEngineHistory; +class QWebEnginePage; +class QWebEngineProfile; +class QWebEngineSettings; +class QWebEngineView; + +class PageView +{ +public: + virtual void contextMenuRequested(QWebEngineContextMenuRequest *request) = 0; + virtual QStringList chooseFiles(QWebEnginePage::FileSelectionMode mode, + const QStringList &oldFiles, + const QStringList &acceptedMimeTypes) = 0; + virtual void + showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController> controller) = 0; + virtual bool showAuthorizationDialog(const QString &title, const QString &message) = 0; + virtual void javaScriptAlert(const QUrl &url, const QString &msg) = 0; + virtual bool javaScriptConfirm(const QUrl &url, const QString &msg) = 0; + virtual bool javaScriptPrompt(const QUrl &url, const QString &msg, const QString &defaultValue, + QString *result) = 0; + virtual void setToolTip(const QString &toolTipText) = 0; + virtual QtWebEngineCore::RenderWidgetHostViewQtDelegate *CreateRenderWidgetHostViewQtDelegate( + QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) = 0; + virtual QWebEngineContextMenuRequest *lastContextMenuRequest() const = 0; + virtual QWebEnginePage *createPageForWindow(QWebEnginePage::WebWindowType type) = 0; + virtual bool isEnabled() const = 0; + virtual bool isVisible() const = 0; + virtual QRect viewportRect() const = 0; + virtual void focusContainer() = 0; + virtual void unhandledKeyEvent(QKeyEvent *event) = 0; + virtual bool passOnFocus(bool reverse) = 0; + virtual QObject *accessibilityParentObject() = 0; +}; + +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient +{ +public: + Q_DECLARE_PUBLIC(QWebEnginePage) + QWebEnginePage *q_ptr; + + QWebEnginePagePrivate(QWebEngineProfile *profile = 0); + ~QWebEnginePagePrivate(); + + QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override; + QtWebEngineCore::RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegateForPopup(QtWebEngineCore::RenderWidgetHostViewQtDelegateClient *client) override { return CreateRenderWidgetHostViewQtDelegate(client); } + void initializationFinished() override; + void lifecycleStateChanged(LifecycleState state) override; + void recommendedStateChanged(LifecycleState state) override; + void visibleChanged(bool visible) override; + void titleChanged(const QString&) override; + void urlChanged() override; + void iconChanged(const QUrl&) override; + void loadProgressChanged(int progress) override; + void didUpdateTargetURL(const QUrl&) override; + void selectionChanged() override; + void recentlyAudibleChanged(bool recentlyAudible) override; + void renderProcessPidChanged(qint64 pid) override; + QRectF viewportRect() const override; + QColor backgroundColor() const override; + void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override; + void loadCommitted() override { } + void didFirstVisuallyNonEmptyPaint() override { } + void loadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, + const QString &errorDescription, bool triggersErrorPage) override; + void focusContainer() override; + void unhandledKeyEvent(QKeyEvent *event) override; + 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; + void contextMenuRequested(QWebEngineContextMenuRequest *request) override; + void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) override; + void requestFullScreenMode(const QUrl &origin, bool fullscreen) override; + bool isFullScreenMode() const override; + void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) override; + void runFileChooser(QSharedPointer<QtWebEngineCore::FilePickerController>) override; + void showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController>) override; + void didRunJavaScript(quint64 requestId, const QVariant& result) override; + void didFetchDocumentMarkup(quint64 requestId, const QString& result) override; + void didFetchDocumentInnerText(quint64 requestId, const QString& result) override; + void didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) override; + void didPrintPageToPdf(const QString &filePath, bool success) override; + bool passOnFocus(bool reverse) override; + void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override; + void authenticationRequired(QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) override; + void releaseProfile() override; + void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) override; + void runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &securityOrigin) override; + void runMouseLockPermissionRequest(const QUrl &securityOrigin) override; + void runQuotaRequest(QWebEngineQuotaRequest) override; + void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override; + QObject *accessibilityParentObject() override; + QWebEngineSettings *webEngineSettings() const override; + void allowCertificateError(const QWebEngineCertificateError &error) override; + void selectClientCert( + const QSharedPointer<QtWebEngineCore::ClientCertSelectController> &controller) override; + void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) override; + void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) override; + void updateScrollPosition(const QPointF &position) override; + void updateContentsSize(const QSizeF &size) override; + void updateNavigationActions() override; + void updateEditActions() override; + QObject *dragSource() const override; + bool isEnabled() const override; + void setToolTip(const QString &toolTipText) override; + void printRequested() override; + QtWebEngineCore::TouchHandleDrawableClient *createTouchHandle(const QMap<int, QImage> &) override { return nullptr; } + void showTouchSelectionMenu(QtWebEngineCore::TouchSelectionMenuController *, const QRect &, const QSize &) override { } + void hideTouchSelectionMenu() override { } + const QObject *holdingQObject() const override; + ClientType clientType() override { return QtWebEngineCore::WebContentsAdapterClient::WidgetsClient; } + void findTextFinished(const QWebEngineFindTextResult &result) override; + + QtWebEngineCore::ProfileAdapter *profileAdapter() override; + QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override; + + void updateAction(QWebEnginePage::WebAction) const; + void _q_webActionTriggered(bool checked); + + QtWebEngineCore::WebContentsAdapter *webContents() { return adapter.data(); } + void recreateFromSerializedHistory(QDataStream &input); + + void setFullScreenMode(bool); + void ensureInitialized() const; + + QSharedPointer<QtWebEngineCore::WebContentsAdapter> adapter; + QWebEngineHistory *history; + QWebEngineProfile *profile; + QWebEngineSettings *settings; + PageView *view; + QUrl url; + bool isLoading; + QWebEngineScriptCollection scriptCollection; + bool m_isBeingAdopted; + QColor m_backgroundColor; + bool fullscreenMode; + QWebChannel *webChannel; + unsigned int webChannelWorldId; + QUrl iconUrl; + bool m_navigationActionTriggered; + QPointer<QWebEnginePage> inspectedPage; + QPointer<QWebEnginePage> devToolsPage; + bool defaultAudioMuted; + qreal defaultZoomFactor; + QTimer wasShownTimer; + QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget *widget = nullptr; + + mutable QtWebEngineCore::CallbackDirectory m_callbacks; + mutable QAction *actions[QWebEnginePage::WebActionCount]; +#if QT_CONFIG(webengine_printing_and_pdf) + QPrinter *currentPrinter; +#endif +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPAGE_P_H diff --git a/src/core/api/qwebengineprofile.cpp b/src/core/api/qwebengineprofile.cpp new file mode 100644 index 000000000..6f0e9d82c --- /dev/null +++ b/src/core/api/qwebengineprofile.cpp @@ -0,0 +1,876 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebengineprofile.h" +#include "qwebengineprofile_p.h" +#include "qwebenginenotification.h" +#include "qwebenginecookiestore.h" +#include "qwebenginedownloadrequest.h" +#include "qwebenginedownloadrequest_p.h" +#include "qwebenginenotification.h" +#include "qwebenginesettings.h" +#include "qwebenginescriptcollection_p.h" +#include "qtwebenginecoreglobal.h" +#include "profile_adapter.h" +#include "visited_links_manager_qt.h" +#include "web_engine_settings.h" + +#include <QDir> +#include <QtWebEngineCore/qwebengineurlscheme.h> + +QT_BEGIN_NAMESPACE + +ASSERT_ENUMS_MATCH(QWebEngineDownloadRequest::UnknownSaveFormat, QtWebEngineCore::ProfileAdapterClient::UnknownSavePageFormat) +ASSERT_ENUMS_MATCH(QWebEngineDownloadRequest::SingleHtmlSaveFormat, QtWebEngineCore::ProfileAdapterClient::SingleHtmlSaveFormat) +ASSERT_ENUMS_MATCH(QWebEngineDownloadRequest::CompleteHtmlSaveFormat, QtWebEngineCore::ProfileAdapterClient::CompleteHtmlSaveFormat) +ASSERT_ENUMS_MATCH(QWebEngineDownloadRequest::MimeHtmlSaveFormat, QtWebEngineCore::ProfileAdapterClient::MimeHtmlSaveFormat) + +using QtWebEngineCore::ProfileAdapter; + +/*! + \class QWebEngineProfile + \brief The QWebEngineProfile class provides a web engine profile shared by multiple pages. + \since 5.5 + + \inmodule QtWebEngineWidgets + + A web engine profile contains settings, scripts, persistent cookie policy, and the list of + visited links shared by all web engine pages that belong to the profile. + + All pages that belong to the profile share a common QWebEngineSettings instance, which can + be accessed with the settings() method. Likewise, the scripts() method provides access + to a common QWebEngineScriptCollection instance. + + Information about visited links is stored together with persistent cookies and other persistent + data in a storage returned by storageName(). Persistent data is stored in a subdirectory set by + calling setPersistentStoragePath(), and the cache is located in a subdirectory set by calling + setCachePath(). The cache type can be set to \e in-memory or \e on-disk by calling + setHttpCacheType(). If only the storage name is set, the subdirectories are created and named + automatically. If you set any of the values manually, you should do it before creating any + pages that belong to the profile. + + The cache can be cleared of links by calling + clearVisitedLinks() or clearAllVisitedLinks(). PersistentCookiesPolicy describes whether + session and persistent cookies are saved to and restored from memory or disk. + + Profiles can be used to isolate pages from each other. A typical use case is a dedicated + \e {off-the-record profile} for a \e {private browsing} mode. Using QWebEngineProfile() without + defining a storage name constructs a new off-the-record profile that leaves no record on the + local machine, and has no persistent data or cache. The isOffTheRecord() method can be used + to check whether a profile is off-the-record. + + The default profile can be accessed by defaultProfile(). It is a built-in profile that all + web pages not specifically created with another profile belong to. + + Implementing the QWebEngineUrlRequestInterceptor interface and registering the interceptor on a + profile by setUrlRequestInterceptor() enables intercepting, blocking, and modifying URL + requests (QWebEngineUrlRequestInfo) before they reach the networking stack of Chromium. + + A QWebEngineUrlSchemeHandler can be registered for a profile by installUrlSchemeHandler() + to add support for custom URL schemes. Requests for the scheme are then issued to + QWebEngineUrlSchemeHandler::requestStarted() as QWebEngineUrlRequestJob objects. + + Spellchecking HTML form fields can be enabled per profile by using the setSpellCheckEnabled() + method and the current languages used for spellchecking can be set by using the + setSpellCheckLanguages() method. + +*/ + +/*! + \enum QWebEngineProfile::HttpCacheType + + This enum describes the HTTP cache type: + + \value MemoryHttpCache Use an in-memory cache. This is the default if + \c off-the-record is set. + \value DiskHttpCache Use a disk cache. This is the default if the profile + is not \c off-the-record. If set on an \c off-the-record profile will instead + set \c MemoryHttpCache. + \value NoCache Disable both in-memory and disk caching. (Added in Qt 5.7) +*/ + +/*! + \enum QWebEngineProfile::PersistentCookiesPolicy + + This enum describes policy for cookie persistency: + + \value NoPersistentCookies + Both session and persistent cookies are stored in memory. This is the only setting + possible if \c off-the-record is set or no persistent data path is available. + \value AllowPersistentCookies + Cookies marked persistent are saved to and restored from disk, whereas session cookies + are only stored to disk for crash recovery. This is the default setting. + \value ForcePersistentCookies + Both session and persistent cookies are saved to and restored from disk. +*/ + +void QWebEngineProfilePrivate::showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &controller) +{ + if (m_notificationPresenter) { + std::unique_ptr<QWebEngineNotification> notification(new QWebEngineNotification(controller)); + m_notificationPresenter(std::move(notification)); + } +} + +/*! + \fn QWebEngineProfile::downloadRequested(QWebEngineDownloadRequest *download) + + \since 5.5 + + This signal is emitted whenever a download has been triggered. + The \a download argument holds the state of the download. + The download has to be explicitly accepted with QWebEngineDownloadRequest::accept() or it will be + cancelled by default. + The download item is parented by the profile. If it is not accepted, it + will be deleted immediately after the signal emission. + This signal cannot be used with a queued connection. + + \sa QWebEngineDownloadRequest, QWebEnginePage::download() +*/ + +QWebEngineProfilePrivate::QWebEngineProfilePrivate(ProfileAdapter* profileAdapter) + : m_settings(new QWebEngineSettings()) + , m_profileAdapter(profileAdapter) + , m_scriptCollection(new QWebEngineScriptCollection( + new QWebEngineScriptCollectionPrivate(profileAdapter->userResourceController()))) +{ + m_profileAdapter->addClient(this); +} + +QWebEngineProfilePrivate::~QWebEngineProfilePrivate() +{ + if (m_profileAdapter) { + // In the case the user sets this profile as the parent of the interceptor + // it can be deleted before the browser-context still referencing it is. + m_profileAdapter->setRequestInterceptor(nullptr); + m_profileAdapter->removeClient(this); + } + + if (m_profileAdapter != QtWebEngineCore::ProfileAdapter::defaultProfileAdapter()) + delete m_profileAdapter; + + delete m_settings; +} + +ProfileAdapter* QWebEngineProfilePrivate::profileAdapter() const +{ + return m_profileAdapter; +} + +void QWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) +{ + m_ongoingDownloads.remove(downloadId); + if (m_profileAdapter) + m_profileAdapter->removeDownload(downloadId); +} + +void QWebEngineProfilePrivate::cleanDownloads() +{ + for (auto download : m_ongoingDownloads.values()) { + if (!download) + continue; + + if (!download->isFinished()) + download->cancel(); + + if (m_profileAdapter) + m_profileAdapter->removeDownload(download->id()); + } + m_ongoingDownloads.clear(); +} + +void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info) +{ + Q_Q(QWebEngineProfile); + + Q_ASSERT(!m_ongoingDownloads.contains(info.id)); + QWebEngineDownloadRequestPrivate *itemPrivate = new QWebEngineDownloadRequestPrivate(m_profileAdapter, info.url); + itemPrivate->downloadId = info.id; + itemPrivate->downloadState = info.accepted ? QWebEngineDownloadRequest::DownloadInProgress + : QWebEngineDownloadRequest::DownloadRequested; + itemPrivate->startTime = info.startTime; + itemPrivate->downloadDirectory = QFileInfo(info.path).path(); + itemPrivate->downloadFileName = QFileInfo(info.path).fileName(); + itemPrivate->suggestedFileName = info.suggestedFileName; + itemPrivate->mimeType = info.mimeType; + itemPrivate->savePageFormat = static_cast<QWebEngineDownloadRequest::SavePageFormat>(info.savePageFormat); + itemPrivate->isSavePageDownload = info.isSavePageDownload; + if (info.page && info.page->clientType() == QtWebEngineCore::WebContentsAdapterClient::WidgetsClient) + itemPrivate->m_adapterClient = info.page; + else + itemPrivate->m_adapterClient = nullptr; + + QWebEngineDownloadRequest *download = new QWebEngineDownloadRequest(itemPrivate, q); + + m_ongoingDownloads.insert(info.id, download); + QObject::connect(download, &QWebEngineDownloadRequest::destroyed, q, [id = info.id, this] () { downloadDestroyed(id); }); + + Q_EMIT q->downloadRequested(download); + + QWebEngineDownloadRequest::DownloadState state = download->state(); + + info.path = QDir(download->downloadDirectory()).filePath(download->downloadFileName()); + info.savePageFormat = static_cast<QtWebEngineCore::ProfileAdapterClient::SavePageFormat>( + download->savePageFormat()); + info.accepted = state != QWebEngineDownloadRequest::DownloadCancelled; + + if (state == QWebEngineDownloadRequest::DownloadRequested) { + // Delete unaccepted downloads. + info.accepted = false; + delete download; + } +} + +void QWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info) +{ + if (!m_ongoingDownloads.contains(info.id)) + return; + + QWebEngineDownloadRequest* download = m_ongoingDownloads.value(info.id).data(); + + if (!download) { + downloadDestroyed(info.id); + return; + } + + download->d_func()->update(info); +} + +void QWebEngineProfilePrivate::addWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) +{ + Q_ASSERT(m_profileAdapter); + m_profileAdapter->addWebContentsAdapterClient(adapter); +} + +void QWebEngineProfilePrivate::removeWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) +{ + Q_ASSERT(m_profileAdapter); + m_profileAdapter->removeWebContentsAdapterClient(adapter); +} + +/*! + Constructs a new off-the-record profile with the parent \a parent. + + An off-the-record profile leaves no record on the local machine, and has no persistent data or cache. + Thus, the HTTP cache can only be in memory and the cookies can only be non-persistent. Trying to change + these settings will have no effect. + + \sa isOffTheRecord() +*/ +QWebEngineProfile::QWebEngineProfile(QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineProfilePrivate(new QtWebEngineCore::ProfileAdapter())) +{ + d_ptr->q_ptr = this; +} + +/*! + Constructs a new profile with the storage name \a storageName and parent \a parent. + + The storage name must be unique. + + A disk-based QWebEngineProfile should be destroyed on or before application exit, otherwise the cache + and persistent data may not be fully flushed to disk. + + \sa storageName() +*/ +QWebEngineProfile::QWebEngineProfile(const QString &storageName, QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineProfilePrivate(new QtWebEngineCore::ProfileAdapter(storageName))) +{ + d_ptr->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineProfile::QWebEngineProfile(QWebEngineProfilePrivate *privatePtr, QObject *parent) + : QObject(parent) + , d_ptr(privatePtr) +{ + d_ptr->q_ptr = this; +} + +/*! \internal +*/ +QWebEngineProfile::~QWebEngineProfile() +{ + d_ptr->cleanDownloads(); +} + +/*! + Returns the storage name for the profile. + + The storage name is used to give each profile that uses the disk separate subdirectories for persistent data and cache. +*/ +QString QWebEngineProfile::storageName() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->storageName(); +} + +/*! + Returns \c true if this is an off-the-record profile that leaves no record on the computer. + + This will force cookies and HTTP cache to be in memory, but also force all other normally + persistent data to be stored in memory. +*/ +bool QWebEngineProfile::isOffTheRecord() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->isOffTheRecord(); +} + +/*! + Returns the path used to store persistent data for the browser and web content. + + Persistent data includes persistent cookies, HTML5 local storage, and visited links. + + By default, this is below QStandardPaths::DataLocation in a QtWebengine/StorageName specific + subdirectory. + + \note Use QStandardPaths::writableLocation(QStandardPaths::DataLocation) + to obtain the QStandardPaths::DataLocation path. + + \sa setPersistentStoragePath(), storageName(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::persistentStoragePath() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->dataPath(); +} + +/*! + Overrides the default path used to store persistent web engine data. + + If \a path is set to the null string, the default path is restored. + + \sa persistentStoragePath() +*/ +void QWebEngineProfile::setPersistentStoragePath(const QString &path) +{ + const Q_D(QWebEngineProfile); + d->profileAdapter()->setDataPath(path); +} + +/*! + \since 5.13 + + The path to the location where the downloaded files are stored. + + \note By default, the download path is QStandardPaths::DownloadLocation. + + \sa setDownloadPath(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::downloadPath() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->downloadPath(); +} + +/*! + \since 5.13 + + Overrides the default path used for download location, setting it to \a path. + + If set to the null string, the default path is restored. + + \sa downloadPath() +*/ +void QWebEngineProfile::setDownloadPath(const QString &path) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setDownloadPath(path); +} + +/*! + Returns the path used for caches. + + By default, this is below StandardPaths::CacheLocation in a QtWebengine/StorageName specific + subdirectory. + + \note Use QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + to obtain the QStandardPaths::CacheLocation path. + + \sa setCachePath(), storageName(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::cachePath() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->cachePath(); +} + +/*! + Overrides the default path used for disk caches, setting it to \a path. + + If set to the null string, the default path is restored. + + \sa cachePath() +*/ +void QWebEngineProfile::setCachePath(const QString &path) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setCachePath(path); +} + +/*! + Returns the user-agent string sent with HTTP to identify the browser. + + \note On Windows 8.1 and newer, the default user agent will always report + "Windows NT 6.2" (Windows 8), unless the application does contain a manifest + that declares newer Windows versions as supported. + + \sa setHttpUserAgent() +*/ +QString QWebEngineProfile::httpUserAgent() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->httpUserAgent(); +} + +/*! + Overrides the default user-agent string, setting it to \a userAgent. + + \sa httpUserAgent() +*/ +void QWebEngineProfile::setHttpUserAgent(const QString &userAgent) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setHttpUserAgent(userAgent); +} + +/*! + Returns the type of HTTP cache used. + + If the profile is off-the-record, MemoryHttpCache is returned. + + \sa setHttpCacheType(), cachePath() +*/ +QWebEngineProfile::HttpCacheType QWebEngineProfile::httpCacheType() const +{ + const Q_D(QWebEngineProfile); + return QWebEngineProfile::HttpCacheType(d->profileAdapter()->httpCacheType()); +} + +/*! + Sets the HTTP cache type to \a httpCacheType. + + \sa httpCacheType(), setCachePath() +*/ +void QWebEngineProfile::setHttpCacheType(QWebEngineProfile::HttpCacheType httpCacheType) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setHttpCacheType(ProfileAdapter::HttpCacheType(httpCacheType)); +} + +/*! + Sets the value of the Accept-Language HTTP request-header field to \a httpAcceptLanguage. + + \since 5.6 + */ +void QWebEngineProfile::setHttpAcceptLanguage(const QString &httpAcceptLanguage) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setHttpAcceptLanguage(httpAcceptLanguage); +} + +/*! + Returns the value of the Accept-Language HTTP request-header field. + + \since 5.6 + */ +QString QWebEngineProfile::httpAcceptLanguage() const +{ + Q_D(const QWebEngineProfile); + return d->profileAdapter()->httpAcceptLanguage(); +} + +/*! + Returns the current policy for persistent cookies. + + If the profile is off-the-record, NoPersistentCookies is returned. + + \sa setPersistentCookiesPolicy() +*/ +QWebEngineProfile::PersistentCookiesPolicy QWebEngineProfile::persistentCookiesPolicy() const +{ + const Q_D(QWebEngineProfile); + return QWebEngineProfile::PersistentCookiesPolicy(d->profileAdapter()->persistentCookiesPolicy()); +} + +/*! + Sets the policy for persistent cookies to \a newPersistentCookiesPolicy. + + \sa persistentCookiesPolicy() +*/ +void QWebEngineProfile::setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setPersistentCookiesPolicy(ProfileAdapter::PersistentCookiesPolicy(newPersistentCookiesPolicy)); +} + +/*! + Returns the maximum size of the HTTP cache in bytes. + + Will return \c 0 if the size is automatically controlled by QtWebEngine. + + \sa setHttpCacheMaximumSize(), httpCacheType() +*/ +int QWebEngineProfile::httpCacheMaximumSize() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->httpCacheMaxSize(); +} + +/*! + Sets the maximum size of the HTTP cache to \a maxSize bytes. + + Setting it to \c 0 means the size will be controlled automatically by QtWebEngine. + + \sa httpCacheMaximumSize(), setHttpCacheType() +*/ +void QWebEngineProfile::setHttpCacheMaximumSize(int maxSize) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setHttpCacheMaxSize(maxSize); +} + +/*! + Returns the cookie store for this profile. + + \since 5.6 +*/ + +QWebEngineCookieStore* QWebEngineProfile::cookieStore() +{ + Q_D(QWebEngineProfile); + return d->profileAdapter()->cookieStore(); +} + +/*! + Registers a request interceptor singleton \a interceptor to intercept URL requests. + + The profile does not take ownership of the pointer. + + \since 5.13 + \sa QWebEngineUrlRequestInfo QWebEngineUrlRequestInterceptor +*/ + +void QWebEngineProfile::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setRequestInterceptor(interceptor); +} + +/*! + Clears all links from the visited links database. + + \sa clearVisitedLinks() +*/ +void QWebEngineProfile::clearAllVisitedLinks() +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->visitedLinksManager()->deleteAllVisitedLinkData(); +} + +/*! + Clears the links in \a urls from the visited links database. + + \sa clearAllVisitedLinks() +*/ +void QWebEngineProfile::clearVisitedLinks(const QList<QUrl> &urls) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->visitedLinksManager()->deleteVisitedLinkDataForUrls(urls); +} + +/*! + Returns \c true if \a url is considered a visited link by this profile. +*/ +bool QWebEngineProfile::visitedLinksContainsUrl(const QUrl &url) const +{ + Q_D(const QWebEngineProfile); + return d->profileAdapter()->visitedLinksManager()->containsUrl(url); +} + +/*! + Returns the collection of scripts that are injected into all pages that share + this profile. + + \sa QWebEngineScriptCollection, QWebEngineScript, QWebEnginePage::scripts(), + {Script Injection} +*/ +QWebEngineScriptCollection *QWebEngineProfile::scripts() const +{ + Q_D(const QWebEngineProfile); + return d->m_scriptCollection.data(); +} + +/*! + Sets the function \a notificationPresenter as responsible for presenting sent notifications. + + \since 5.13 + \sa QWebEngineNotification +*/ +void QWebEngineProfile::setNotificationPresenter(std::function<void(std::unique_ptr<QWebEngineNotification>)> notificationPresenter) +{ + Q_D(QWebEngineProfile); + d->m_notificationPresenter = std::move(notificationPresenter); +} + +/*! + Returns presenter responsible for presenting sent notifications + \since 6.0 + */ +std::function<void(std::unique_ptr<QWebEngineNotification>)> QWebEngineProfile::notificationPresenter() +{ + Q_D(QWebEngineProfile); + return d->m_notificationPresenter; +} + +/*! + Returns the default profile. + + The default profile uses the storage name "Default". + + \sa storageName() +*/ +QWebEngineProfile *QWebEngineProfile::defaultProfile() +{ + static QWebEngineProfile* profile = new QWebEngineProfile( + new QWebEngineProfilePrivate(ProfileAdapter::createDefaultProfileAdapter()), + ProfileAdapter::globalQObjectRoot()); + return profile; +} + +/*! + \since 5.8 + + Sets the current list of \a languages for the spell checker. + Each language should match the name of the \c .bdic dictionary. + For example, the language \c en-US will load the \c en-US.bdic + dictionary file. + + See the \l {Spellchecker}{Spellchecker feature documentation} for how + dictionary files are searched. + + For more information about how to compile \c .bdic dictionaries, see the + \l{WebEngine Widgets Spellchecker Example}{Spellchecker Example}. + +*/ +void QWebEngineProfile::setSpellCheckLanguages(const QStringList &languages) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setSpellCheckLanguages(languages); +} + +/*! + \since 5.8 + + Returns the list of languages used by the spell checker. +*/ +QStringList QWebEngineProfile::spellCheckLanguages() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->spellCheckLanguages(); +} + +/*! + \since 5.8 + + Enables spell checker if \a enable is \c true, otherwise disables it. + \sa isSpellCheckEnabled() + */ +void QWebEngineProfile::setSpellCheckEnabled(bool enable) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setSpellCheckEnabled(enable); +} +/*! + \since 5.8 + + Returns \c true if the spell checker is enabled; otherwise returns \c false. + \sa setSpellCheckEnabled() + */ +bool QWebEngineProfile::isSpellCheckEnabled() const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->isSpellCheckEnabled(); +} + +/*! + Returns the default settings for all pages in this profile. +*/ +QWebEngineSettings *QWebEngineProfile::settings() const +{ + const Q_D(QWebEngineProfile); + return d->settings(); +} + +/*! + \since 5.6 + + Returns the custom URL scheme handler register for the URL scheme \a scheme. +*/ +const QWebEngineUrlSchemeHandler *QWebEngineProfile::urlSchemeHandler(const QByteArray &scheme) const +{ + const Q_D(QWebEngineProfile); + return d->profileAdapter()->urlSchemeHandler(scheme); +} + +/*! + \since 5.6 + + Registers a handler \a handler for custom URL scheme \a scheme in the profile. + + It is necessary to first register the scheme with \l + QWebEngineUrlScheme::registerScheme at application startup. +*/ +void QWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->installUrlSchemeHandler(scheme, handler); +} + +/*! + \since 5.6 + + Removes the custom URL scheme handler \a handler from the profile. + + \sa removeUrlScheme() +*/ +void QWebEngineProfile::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->removeUrlSchemeHandler(handler); +} + +/*! + \since 5.6 + + Removes the custom URL scheme \a scheme from the profile. + + \sa removeUrlSchemeHandler() +*/ +void QWebEngineProfile::removeUrlScheme(const QByteArray &scheme) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->removeUrlScheme(scheme); +} + +/*! + \since 5.6 + + Removes all custom URL scheme handlers installed in the profile. +*/ +void QWebEngineProfile::removeAllUrlSchemeHandlers() +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->removeAllUrlSchemeHandlers(); +} + +/*! + \since 5.13 + + \obsolete + + Sets if this profile is to be used for downloading and caching when needed + during certificate verification, for instance for OCSP, CRLs, and AIA. + + Only one QWebEngineProfile can do this at a time, and it is recommended + that the profile fullfilling this role has a disk HTTP cache to avoid + needlessly re-downloading. If you set the option on a second profile, + it will be disabled on the profile it is currently set. + + As long as one profile has \a enabled set to \c true, all other profiles + will be able to use it for their certificate verification. + + Originally only affected Linux/NSS installations where it enabled OCSP. + + Since 5.15.3, no longer does anything. Certificate verification is done + using AIO on the requesting profile. + + \sa isUsedForGlobalCertificateVerification(), httpCacheType() +*/ +void QWebEngineProfile::setUseForGlobalCertificateVerification(bool enabled) +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->setUseForGlobalCertificateVerification(enabled); +} + +/*! + \since 5.13 + + \obsolete + + Returns \c true if this profile is currently being used for global + certificate verification. +*/ +bool QWebEngineProfile::isUsedForGlobalCertificateVerification() const +{ + Q_D(const QWebEngineProfile); + return d->profileAdapter()->isUsedForGlobalCertificateVerification(); +} + +/*! + \since 5.7 + + Removes the profile's cache entries. +*/ +void QWebEngineProfile::clearHttpCache() +{ + Q_D(QWebEngineProfile); + d->profileAdapter()->clearHttpCache(); +} + +/*! + \since 5.13 + + Returns the profile's client certificate store. +*/ +QWebEngineClientCertificateStore *QWebEngineProfile::clientCertificateStore() +{ +#if QT_CONFIG(ssl) + Q_D(QWebEngineProfile); + return d->profileAdapter()->clientCertificateStore(); +#else + return nullptr; +#endif +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebengineprofile.h b/src/core/api/qwebengineprofile.h new file mode 100644 index 000000000..b2088cf5d --- /dev/null +++ b/src/core/api/qwebengineprofile.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEPROFILE_H +#define QWEBENGINEPROFILE_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qobject.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qstring.h> + +#include <functional> +#include <memory> + +QT_BEGIN_NAMESPACE + +class QObject; +class QUrl; +class QWebEngineClientCertificateStore; +class QWebEngineCookieStore; +class QWebEngineDownloadRequest; +class QWebEngineNotification; +class QWebEngineProfilePrivate; +class QWebEngineSettings; +class QWebEngineScriptCollection; +class QWebEngineUrlRequestInterceptor; +class QWebEngineUrlSchemeHandler; + +class Q_WEBENGINECORE_EXPORT QWebEngineProfile : public QObject { + Q_OBJECT +public: + explicit QWebEngineProfile(QObject *parent = Q_NULLPTR); + explicit QWebEngineProfile(const QString &name, QObject *parent = Q_NULLPTR); + virtual ~QWebEngineProfile(); + + enum HttpCacheType { + MemoryHttpCache, + DiskHttpCache, + NoCache + }; + Q_ENUM(HttpCacheType) + + enum PersistentCookiesPolicy { + NoPersistentCookies, + AllowPersistentCookies, + ForcePersistentCookies + }; + Q_ENUM(PersistentCookiesPolicy) + + QString storageName() const; + bool isOffTheRecord() const; + + QString persistentStoragePath() const; + void setPersistentStoragePath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + HttpCacheType httpCacheType() const; + void setHttpCacheType(QWebEngineProfile::HttpCacheType); + + void setHttpAcceptLanguage(const QString &httpAcceptLanguage); + QString httpAcceptLanguage() const; + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy); + + int httpCacheMaximumSize() const; + void setHttpCacheMaximumSize(int maxSize); + + QWebEngineCookieStore* cookieStore(); +#if QT_DEPRECATED_SINCE(5, 13) + void setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); +#endif + void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor); + + void clearAllVisitedLinks(); + void clearVisitedLinks(const QList<QUrl> &urls); + bool visitedLinksContainsUrl(const QUrl &url) const; + + QWebEngineSettings *settings() const; + QWebEngineScriptCollection *scripts() const; + + const QWebEngineUrlSchemeHandler *urlSchemeHandler(const QByteArray &) const; + void installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *); + void removeUrlScheme(const QByteArray &scheme); + void removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *); + void removeAllUrlSchemeHandlers(); + + void clearHttpCache(); + + void setSpellCheckLanguages(const QStringList &languages); + QStringList spellCheckLanguages() const; + void setSpellCheckEnabled(bool enabled); + bool isSpellCheckEnabled() const; + + void setUseForGlobalCertificateVerification(bool enabled = true); + bool isUsedForGlobalCertificateVerification() const; + + QString downloadPath() const; + void setDownloadPath(const QString &path); + + void setNotificationPresenter(std::function<void(std::unique_ptr<QWebEngineNotification>)> notificationPresenter); + std::function<void(std::unique_ptr<QWebEngineNotification>)> notificationPresenter(); + + QWebEngineClientCertificateStore *clientCertificateStore(); + + static QWebEngineProfile *defaultProfile(); + +Q_SIGNALS: + void downloadRequested(QWebEngineDownloadRequest *download); + +private: + Q_DISABLE_COPY(QWebEngineProfile) + Q_DECLARE_PRIVATE(QWebEngineProfile) + QWebEngineProfile(QWebEngineProfilePrivate *, QObject *parent = Q_NULLPTR); + + friend class QWebEnginePage; + friend class QWebEnginePagePrivate; + friend class QWebEngineUrlSchemeHandler; + QScopedPointer<QWebEngineProfilePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPROFILE_H diff --git a/src/core/api/qwebengineprofile_p.h b/src/core/api/qwebengineprofile_p.h new file mode 100644 index 000000000..4bec7d6dc --- /dev/null +++ b/src/core/api/qwebengineprofile_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEPROFILE_P_H +#define QWEBENGINEPROFILE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "profile_adapter_client.h" +#include "qwebengineprofile.h" +#include "qwebenginescriptcollection.h" + +#include <QMap> +#include <QPointer> +#include <QScopedPointer> +#include <QSharedPointer> + +#include <functional> + +namespace QtWebEngineCore { +class ProfileAdapter; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineBrowserContext; +class QWebEngineProfilePrivate; +class QWebEngineNotification; +class QWebEngineSettings; + +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineProfilePrivate : public QtWebEngineCore::ProfileAdapterClient { +public: + Q_DECLARE_PUBLIC(QWebEngineProfile) + QWebEngineProfilePrivate(QtWebEngineCore::ProfileAdapter *profileAdapter); + ~QWebEngineProfilePrivate(); + + QtWebEngineCore::ProfileAdapter* profileAdapter() const; + QWebEngineSettings *settings() const { return m_settings; } + + void downloadDestroyed(quint32 downloadId); + + void cleanDownloads(); + + void downloadRequested(DownloadItemInfo &info) override; + void downloadUpdated(const DownloadItemInfo &info) override; + + void showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &) override; + + void addWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) override; + void removeWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) override; + +private: + QWebEngineProfile *q_ptr; + QWebEngineSettings *m_settings; + QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter; + QScopedPointer<QWebEngineScriptCollection> m_scriptCollection; + QMap<quint32, QPointer<QWebEngineDownloadRequest> > m_ongoingDownloads; + std::function<void(std::unique_ptr<QWebEngineNotification>)> m_notificationPresenter; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPROFILE_P_H diff --git a/src/core/api/qwebenginescript.cpp b/src/core/api/qwebenginescript.cpp new file mode 100644 index 000000000..650ad5c53 --- /dev/null +++ b/src/core/api/qwebenginescript.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginescript.h" + +#include "user_script.h" +#include <QtCore/QDebug> +#include <QtCore/QFile> + +using QtWebEngineCore::UserScript; + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineScript + \inmodule QtWebEngineCore + \since 5.5 + \brief The QWebEngineScript class encapsulates a JavaScript program. + + + QWebEngineScript enables the programmatic injection of so called \e {user scripts} in the + JavaScript engine at different points, determined by injectionPoint(), during the loading of web + contents. + + Scripts can be executed either in the main JavaScript \e world, along with the rest of the + JavaScript coming from the web contents, or in their own isolated world. While the DOM of the + page can be accessed from any world, JavaScript variables of a function defined in one world are + not accessible from a different one. ScriptWorldId provides some predefined IDs for this + purpose. + + The following \l Greasemonkey attributes are supported since Qt 5.8: + \c @exclude, \c @include, \c @name, \c @match, and \c @run-at. + + Use QWebEnginePage::scripts() and QWebEngineProfile::scripts() to access + the collection of scripts associated with a single page or a + number of pages sharing the same profile. + + \sa {Script Injection} +*/ +/*! + \enum QWebEngineScript::InjectionPoint + + This enum describes the timing of the script injection: + + \value DocumentCreation The script will be executed as soon as the document is created. This is not suitable for + any DOM operation. + \value DocumentReady The script will run as soon as the DOM is ready. This is equivalent to the + \c DOMContentLoaded event firing in JavaScript. + \value Deferred The script will run when the page load finishes, or 500ms after the document is ready, whichever + comes first. + +*/ +/*! + \enum QWebEngineScript::ScriptWorldId + + This enum provides pre-defined world IDs for isolating user scripts into different worlds: + + \value MainWorld The world used by the page's web contents. It can be useful in order to expose custom functionality + to web contents in certain scenarios. + \value ApplicationWorld The default isolated world used for application level functionality implemented in JavaScript. + \value UserWorld The first isolated world to be used by scripts set by users if the application is not making use + of more worlds. As a rule of thumb, if that functionality is exposed to the application users, each individual script + should probably get its own isolated world. + +*/ + +/*! + \fn QWebEngineScript::operator!=(const QWebEngineScript &other) const + + Returns \c true if the script is not equal to \a other, otherwise returns \c false. +*/ + +/*! + \fn QWebEngineScript::swap(QWebEngineScript &other) + + Swaps the contents of the script with the contents of \a other. +*/ + +/*! + * Constructs a null script. + */ + +QWebEngineScript::QWebEngineScript() + : d(new UserScript) +{ +} + +/*! + * Constructs a user script using the contents of \a other. + */ +QWebEngineScript::QWebEngineScript(const QWebEngineScript &other) + : d(other.d) +{ +} + +/*! + Destroys a script. +*/ +QWebEngineScript::~QWebEngineScript() +{ +} + +/*! + Assigns \a other to the script. +*/ +QWebEngineScript &QWebEngineScript::operator=(const QWebEngineScript &other) +{ + d = other.d; + return *this; +} + +/*! + * Returns the name of the script. Can be useful to retrieve a particular script from a + * QWebEngineScriptCollection. + * + * \sa QWebEngineScriptCollection::findScript(), QWebEngineScriptCollection::findScripts() + */ + +QString QWebEngineScript::name() const +{ + return d->name(); +} + +/*! + * Sets the script name to \a scriptName. + */ +void QWebEngineScript::setName(const QString &scriptName) +{ + if (scriptName == name()) + return; + d->setName(scriptName); +} + + +QUrl QWebEngineScript::sourceUrl() const +{ + return d->sourceUrl(); +} + +void QWebEngineScript::setSourceUrl(const QUrl &url) +{ + if (url == sourceUrl()) + return; + + d->setSourceUrl(url); + + QFile file; + if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) { + if (url.authority().isEmpty()) + file.setFileName(QLatin1Char(':') + url.path()); + return; + } else { + file.setFileName(url.toLocalFile()); + } + + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Can't open user script " << url; + return; + } + + QString source = QString::fromUtf8(file.readAll()); + setSourceCode(source); +} + +/*! + Returns the source of the script. + */ +QString QWebEngineScript::sourceCode() const +{ + return d->sourceCode(); +} + +/*! + * Sets the script source to \a scriptSource. + */ +void QWebEngineScript::setSourceCode(const QString &scriptSource) +{ + if (scriptSource == sourceCode()) + return; + d->setSourceCode(scriptSource); +} + +ASSERT_ENUMS_MATCH(QWebEngineScript::Deferred, UserScript::AfterLoad) +ASSERT_ENUMS_MATCH(QWebEngineScript::DocumentReady, UserScript::DocumentLoadFinished) +ASSERT_ENUMS_MATCH(QWebEngineScript::DocumentCreation, UserScript::DocumentElementCreation) + +/*! + * Returns the point in the loading process at which the script will be executed. + * The default value is QWebEngineScript::Deferred. + * + * \sa setInjectionPoint() + */ +QWebEngineScript::InjectionPoint QWebEngineScript::injectionPoint() const +{ + return static_cast<QWebEngineScript::InjectionPoint>(d->injectionPoint()); +} +/*! + * Sets the point at which to execute the script to be \a p. + * + * \sa InjectionPoint + */ +void QWebEngineScript::setInjectionPoint(QWebEngineScript::InjectionPoint p) +{ + if (p == injectionPoint()) + return; + d->setInjectionPoint(static_cast<UserScript::InjectionPoint>(p)); +} + +/*! + Returns the world ID defining which world the script is executed in. + */ +quint32 QWebEngineScript::worldId() const +{ + return d->worldId(); +} + +/*! + Sets the world ID of the isolated world to \a id when running this script. + + Must be between \c 0 and \c 256. + */ +void QWebEngineScript::setWorldId(quint32 id) +{ + if (id == d->worldId()) + return; + d->setWorldId(id); +} + +/*! + Returns \c true if the script is executed on every frame in the page, or \c false if it is only + ran for the main frame. + */ +bool QWebEngineScript::runsOnSubFrames() const +{ + return d->runsOnSubFrames(); +} + +/*! + * Executes the script on sub frames in addition to the main frame if \a on returns \c true. + */ +void QWebEngineScript::setRunsOnSubFrames(bool on) +{ + if (runsOnSubFrames() == on) + return; + d->setRunsOnSubFrames(on); +} + +/*! + Returns \c true if the script is equal to \a other, otherwise returns \c false. + */ +bool QWebEngineScript::operator==(const QWebEngineScript &other) const +{ + return d == other.d || *d == *(other.d); +} + +QWebEngineScript::QWebEngineScript(const UserScript &coreScript) + : d(new UserScript(coreScript)) +{ +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const QWebEngineScript &script) +{ + d.nospace() << "QWebEngineScript(" << script.name() << ", "; + switch (script.injectionPoint()) { + case QWebEngineScript::DocumentCreation: + d << "QWebEngineScript::DocumentCreation" << ", "; + break; + case QWebEngineScript::DocumentReady: + d << "QWebEngineScript::DocumentReady" << ", "; + break; + case QWebEngineScript::Deferred: + d << "QWebEngineScript::Deferred" << ", "; + break; + } + d << script.worldId() << ", " + << script.runsOnSubFrames() << ", " << script.sourceCode() << ")"; + return d.space(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginescript.h b/src/core/api/qwebenginescript.h new file mode 100644 index 000000000..0c1849dac --- /dev/null +++ b/src/core/api/qwebenginescript.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINESCRIPT_H +#define QWEBENGINESCRIPT_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/QUrl> +#include <QtCore/QObject> +#include <QtCore/QSharedDataPointer> + +namespace QtWebEngineCore { +class UserScript; +} // namespace + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINECORE_EXPORT QWebEngineScript { + + Q_GADGET + Q_PROPERTY(QString name READ name WRITE setName FINAL) + Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl FINAL) + Q_PROPERTY(QString sourceCode READ sourceCode WRITE setSourceCode FINAL) + Q_PROPERTY(InjectionPoint injectionPoint READ injectionPoint WRITE setInjectionPoint FINAL) + Q_PROPERTY(quint32 worldId READ worldId WRITE setWorldId FINAL) + Q_PROPERTY(bool runsOnSubFrames READ runsOnSubFrames WRITE setRunsOnSubFrames FINAL) + +public: + + enum InjectionPoint { + Deferred, + DocumentReady, + DocumentCreation + }; + + Q_ENUM(InjectionPoint) + + enum ScriptWorldId { + MainWorld = 0, + ApplicationWorld, + UserWorld + }; + + Q_ENUM(ScriptWorldId) + + QWebEngineScript(); + QWebEngineScript(const QWebEngineScript &other); + ~QWebEngineScript(); + + QWebEngineScript &operator=(const QWebEngineScript &other); + + QString name() const; + void setName(const QString &); + + QUrl sourceUrl() const; + void setSourceUrl(const QUrl &url); + + QString sourceCode() const; + void setSourceCode(const QString &); + + InjectionPoint injectionPoint() const; + void setInjectionPoint(InjectionPoint); + + quint32 worldId() const; + void setWorldId(quint32); + + bool runsOnSubFrames() const; + void setRunsOnSubFrames(bool on); + + bool operator==(const QWebEngineScript &other) const; + inline bool operator!=(const QWebEngineScript &other) const + { return !operator==(other); } + void swap(QWebEngineScript &other) { qSwap(d, other.d); } + +private: + friend class QQuickWebEngineScriptCollectionPrivate; + friend class QWebEngineScriptCollectionPrivate; + friend class QWebEngineScriptCollection; + QWebEngineScript(const QtWebEngineCore::UserScript &); + + QSharedDataPointer<QtWebEngineCore::UserScript> d; +}; + +Q_DECLARE_TYPEINFO(QWebEngineScript, Q_MOVABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_WEBENGINECORE_EXPORT QDebug operator<<(QDebug, const QWebEngineScript &); +#endif + +QT_END_NAMESPACE + +#endif // QWEBENGINESCRIPT_H diff --git a/src/core/api/qwebenginescriptcollection.cpp b/src/core/api/qwebenginescriptcollection.cpp new file mode 100644 index 000000000..6dfa12c46 --- /dev/null +++ b/src/core/api/qwebenginescriptcollection.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginescriptcollection.h" +#include "qwebenginescriptcollection_p.h" + +#include "renderer_host/user_resource_controller_host.h" + +using QtWebEngineCore::UserScript; + +/*! + \class QWebEngineScriptCollection + \inmodule QtWebEngineCore + \since 5.5 + \brief The QWebEngineScriptCollection class represents a collection of user scripts. + + QWebEngineScriptCollection manages a set of user scripts. + + Use QWebEnginePage::scripts() and QWebEngineProfile::scripts() to access + the collection of scripts associated with a single page or a + number of pages sharing the same profile. + + \sa {Script Injection} +*/ + +/*! + \fn QWebEngineScriptCollection::isEmpty() const + + Returns \c true if the collection is empty; otherwise returns \c false. +*/ + +/*! + \fn QWebEngineScriptCollection::size() const + + Returns the number of elements in the collection. +*/ + +QWebEngineScriptCollection::QWebEngineScriptCollection(QWebEngineScriptCollectionPrivate *collectionPrivate) + :d(collectionPrivate) +{ +} + +/*! + Destroys the collection. +*/ +QWebEngineScriptCollection::~QWebEngineScriptCollection() +{ +} + +/*! + Returns the number of elements in the collection. + */ + +int QWebEngineScriptCollection::count() const +{ + return d->count(); +} + +/*! + Returns \c true if the collection contains an occurrence of \a value; otherwise returns + \c false. + */ + +bool QWebEngineScriptCollection::contains(const QWebEngineScript &value) const +{ + return d->contains(value); +} + +/*! + Returns the list of scripts in the collection with the name \a name, or an empty list if none + was found. + */ + +QList<QWebEngineScript> QWebEngineScriptCollection::find(const QString &name) const +{ + return d->toList(name); +} +/*! + Inserts the script \a s into the collection. + */ +void QWebEngineScriptCollection::insert(const QWebEngineScript &s) +{ + d->insert(s); +} +/*! + Inserts scripts from the list \a list into the collection. + */ +void QWebEngineScriptCollection::insert(const QList<QWebEngineScript> &list) +{ + d->reserve(list.size()); + for (const QWebEngineScript &s : list) + d->insert(s); +} + +/*! + Removes \a script from the collection. + + Returns \c true if the script was found and successfully removed from the collection; otherwise + returns \c false. + */ +bool QWebEngineScriptCollection::remove(const QWebEngineScript &script) +{ + return d->remove(script); +} + +/*! + * Removes all scripts from this collection. + */ +void QWebEngineScriptCollection::clear() +{ + d->clear(); +} + +/*! + Returns a list with the values of the scripts used in this collection. + */ +QList<QWebEngineScript> QWebEngineScriptCollection::toList() const +{ + return d->toList(); +} + + +QWebEngineScriptCollectionPrivate::QWebEngineScriptCollectionPrivate(QtWebEngineCore::UserResourceControllerHost *controller, QSharedPointer<QtWebEngineCore::WebContentsAdapter> webContents) + : m_scriptController(controller) + , m_contents(webContents) +{ +} + +int QWebEngineScriptCollectionPrivate::count() const +{ + return m_scripts.count(); +} + +bool QWebEngineScriptCollectionPrivate::contains(const QWebEngineScript &s) const +{ + return m_scripts.contains(s); +} + +void QWebEngineScriptCollectionPrivate::insert(const QWebEngineScript &script) +{ + m_scripts.append(script); + if (!m_contents || m_contents->isInitialized()) + m_scriptController->addUserScript(*script.d, m_contents.data()); +} + +bool QWebEngineScriptCollectionPrivate::remove(const QWebEngineScript &script) +{ + if (!m_contents || m_contents->isInitialized()) + m_scriptController->removeUserScript(*script.d, m_contents.data()); + return m_scripts.removeAll(script); +} + +QList<QWebEngineScript> QWebEngineScriptCollectionPrivate::toList(const QString &scriptName) const +{ + if (scriptName.isNull()) + return m_scripts; + + QList<QWebEngineScript> ret; + for (const QWebEngineScript &script : qAsConst(m_scripts)) + if (scriptName == script.name()) + ret.append(script); + return ret; +} + +void QWebEngineScriptCollectionPrivate::clear() +{ + m_scripts.clear(); + if (!m_contents || m_contents->isInitialized()) + m_scriptController->clearAllScripts(m_contents.data()); +} + +void QWebEngineScriptCollectionPrivate::reserve(int capacity) +{ + m_scripts.reserve(capacity); + if (!m_contents || m_contents->isInitialized()) + m_scriptController->reserve(m_contents.data(), capacity); +} + +void QWebEngineScriptCollectionPrivate::initializationFinished(QSharedPointer<QtWebEngineCore::WebContentsAdapter> contents) +{ + Q_ASSERT(m_contents); + Q_ASSERT(contents); + + for (const QWebEngineScript &script : qAsConst(m_scripts)) + m_scriptController->addUserScript(*script.d, contents.data()); + m_contents = contents; +} diff --git a/src/core/compositor/display_frame_sink.h b/src/core/api/qwebenginescriptcollection.h index f620dc4f2..2a1ab7dbf 100644 --- a/src/core/compositor/display_frame_sink.h +++ b/src/core/api/qwebenginescriptcollection.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,41 +37,43 @@ ** ****************************************************************************/ -#ifndef DISPLAY_FRAME_SINK_H -#define DISPLAY_FRAME_SINK_H +#ifndef QWEBENGINESCRIPTCOLLECTION_H +#define QWEBENGINESCRIPTCOLLECTION_H -#include "display_consumer.h" -#include "display_producer.h" +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtWebEngineCore/qwebenginescript.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qlist.h> +#include <QtCore/qset.h> -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_refptr.h" -#include "components/viz/common/surfaces/frame_sink_id.h" +QT_BEGIN_NAMESPACE +class QWebEngineScriptCollectionPrivate; -#include <QMutex> +class Q_WEBENGINECORE_EXPORT QWebEngineScriptCollection { +public: + ~QWebEngineScriptCollection(); -namespace QtWebEngineCore { + bool isEmpty() const { return !count(); } + int count() const; + bool contains(const QWebEngineScript &value) const; + QList<QWebEngineScript> find(const QString &name) const; + void insert(const QWebEngineScript &); + void insert(const QList<QWebEngineScript> &list); + bool remove(const QWebEngineScript &); + void clear(); -// Connects a DisplayConsumer with a DisplayProducer. -class DisplayFrameSink final : public base::RefCountedThreadSafe<DisplayFrameSink> -{ -public: - static scoped_refptr<DisplayFrameSink> findOrCreate(viz::FrameSinkId frameSinkId); - DisplayFrameSink(viz::FrameSinkId frameSinkId); - ~DisplayFrameSink(); - void connect(DisplayConsumer *consumer); - void connect(DisplayProducer *producer); - void disconnect(DisplayConsumer *consumer); - void disconnect(DisplayProducer *producer); - void scheduleUpdate(); - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate); + QList<QWebEngineScript> toList() const; private: - const viz::FrameSinkId m_frameSinkId; - mutable QMutex m_mutex; - DisplayProducer *m_producer = nullptr; - DisplayConsumer *m_consumer = nullptr; -}; + Q_DISABLE_COPY(QWebEngineScriptCollection) + friend class QWebEnginePagePrivate; + friend class QWebEngineProfilePrivate; + friend class QQuickWebEngineProfilePrivate; + friend class QQuickWebEngineViewPrivate; + QWebEngineScriptCollection(QWebEngineScriptCollectionPrivate *); -} // namespace QtWebEngineCore + QScopedPointer<QWebEngineScriptCollectionPrivate> d; +}; -#endif // !DISPLAY_FRAME_SINK_H +QT_END_NAMESPACE +#endif // QWEBENGINESCRIPTCOLLECTION_H diff --git a/src/core/api/qwebenginescriptcollection_p.h b/src/core/api/qwebenginescriptcollection_p.h new file mode 100644 index 000000000..442f8fe3d --- /dev/null +++ b/src/core/api/qwebenginescriptcollection_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINESCRIPTCOLLECTION_P_H +#define QWEBENGINESCRIPTCOLLECTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtwebenginecoreglobal.h" +#include "qwebenginescript.h" +#include "web_contents_adapter.h" + +#include <QtCore/QSet> +#include <QtCore/QSharedPointer> + +namespace QtWebEngineCore { +class UserResourceControllerHost; +} // namespace + +QT_BEGIN_NAMESPACE +class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineScriptCollectionPrivate { +public: + QWebEngineScriptCollectionPrivate(QtWebEngineCore::UserResourceControllerHost *, QSharedPointer<QtWebEngineCore::WebContentsAdapter> = QSharedPointer<QtWebEngineCore::WebContentsAdapter>()); + int count() const; + bool contains(const QWebEngineScript &) const; + QList<QWebEngineScript> toList(const QString &scriptName = QString()) const; + void initializationFinished(QSharedPointer<QtWebEngineCore::WebContentsAdapter> contents); + void insert(const QWebEngineScript &); + bool remove(const QWebEngineScript &); + void clear(); + void reserve(int); + +private: + QtWebEngineCore::UserResourceControllerHost *m_scriptController; + QSharedPointer<QtWebEngineCore::WebContentsAdapter> m_contents; + QList<QWebEngineScript> m_scripts; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINESCRIPTCOLLECTION__PH diff --git a/src/core/api/qwebenginesettings.cpp b/src/core/api/qwebenginesettings.cpp new file mode 100644 index 000000000..c7c0a47b2 --- /dev/null +++ b/src/core/api/qwebenginesettings.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebenginesettings.h" +#include "web_engine_settings.h" + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::WebEngineSettings; + +QWebEngineSettings::QWebEngineSettings(QWebEngineSettings *parentSettings) + : d_ptr(new WebEngineSettings(parentSettings ? parentSettings->d_ptr.data() : nullptr)) +{ + d_ptr->scheduleApplyRecursively(); +} + +QWebEngineSettings::~QWebEngineSettings() { } + +/*! + Returns the settings for a web engine page that belongs to the default + profile. All web pages not specifically created with another profile belong + to the default profile. + +QWebEngineSettings *QWebEngineSettings::defaultSettings() +{ + return QWebEngineProfile::defaultProfile()->settings(); +} +*/ + +void QWebEngineSettings::setFontFamily(QWebEngineSettings::FontFamily which, const QString &family) +{ + d_ptr->setFontFamily(which, family); +} + +QString QWebEngineSettings::fontFamily(QWebEngineSettings::FontFamily which) const +{ + return d_ptr->fontFamily(which); +} + +void QWebEngineSettings::resetFontFamily(QWebEngineSettings::FontFamily which) +{ + d_ptr->resetFontFamily(which); +} + +void QWebEngineSettings::setFontSize(QWebEngineSettings::FontSize type, int size) +{ + d_ptr->setFontSize(type, size); +} + +int QWebEngineSettings::fontSize(QWebEngineSettings::FontSize type) const +{ + return d_ptr->fontSize(type); +} + +void QWebEngineSettings::resetFontSize(QWebEngineSettings::FontSize type) +{ + d_ptr->resetFontSize(type); +} + +QString QWebEngineSettings::defaultTextEncoding() const +{ + return d_ptr->defaultTextEncoding(); +} + +QWebEngineSettings::UnknownUrlSchemePolicy QWebEngineSettings::unknownUrlSchemePolicy() const +{ + return d_ptr->unknownUrlSchemePolicy(); +} + +void QWebEngineSettings::resetUnknownUrlSchemePolicy() +{ + d_ptr->setUnknownUrlSchemePolicy(QWebEngineSettings::InheritedUnknownUrlSchemePolicy); +} + +void QWebEngineSettings::setAttribute(QWebEngineSettings::WebAttribute attr, bool on) +{ + d_ptr->setAttribute(attr, on); +} + +bool QWebEngineSettings::testAttribute(QWebEngineSettings::WebAttribute attr) const +{ + return d_ptr->testAttribute(attr); +} + +void QWebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) +{ + d_ptr->resetAttribute(attr); +} + +void QWebEngineSettings::setDefaultTextEncoding(const QString &encoding) +{ + d_ptr->setDefaultTextEncoding(encoding); +} + +void QWebEngineSettings::setUnknownUrlSchemePolicy( + QWebEngineSettings::UnknownUrlSchemePolicy policy) +{ + d_ptr->setUnknownUrlSchemePolicy(policy); +} + +void QWebEngineSettings::setParentSettings(QWebEngineSettings *parentSettings) +{ + d_ptr->setParentSettings(parentSettings->d_ptr.data()); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginesettings.h b/src/core/api/qwebenginesettings.h new file mode 100644 index 000000000..f565f8ee2 --- /dev/null +++ b/src/core/api/qwebenginesettings.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINESETTINGS_H +#define QWEBENGINESETTINGS_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/qscopedpointer.h> +#include <QtCore/qstring.h> + +namespace QtWebEngineCore { +class WebEngineSettings; +} + +QT_BEGIN_NAMESPACE + +class QIcon; +class QPixmap; +class QUrl; + +class Q_WEBENGINECORE_EXPORT QWebEngineSettings { +public: + enum FontFamily { + StandardFont, + FixedFont, + SerifFont, + SansSerifFont, + CursiveFont, + FantasyFont, + PictographFont + }; + + enum WebAttribute { + AutoLoadImages, + JavascriptEnabled, + JavascriptCanOpenWindows, + JavascriptCanAccessClipboard, + LinksIncludedInFocusChain, + LocalStorageEnabled, + LocalContentCanAccessRemoteUrls, + XSSAuditingEnabled, + SpatialNavigationEnabled, + LocalContentCanAccessFileUrls, + HyperlinkAuditingEnabled, + ScrollAnimatorEnabled, + ErrorPageEnabled, + PluginsEnabled, + FullScreenSupportEnabled, + ScreenCaptureEnabled, + WebGLEnabled, + Accelerated2dCanvasEnabled, + AutoLoadIconsForPage, + TouchIconsEnabled, + FocusOnNavigationEnabled, + PrintElementBackgrounds, + AllowRunningInsecureContent, + AllowGeolocationOnInsecureOrigins, + AllowWindowActivationFromJavaScript, + ShowScrollBars, + PlaybackRequiresUserGesture, + WebRTCPublicInterfacesOnly, + JavascriptCanPaste, + DnsPrefetchEnabled, + PdfViewerEnabled, + }; + + enum FontSize { + MinimumFontSize, + MinimumLogicalFontSize, + DefaultFontSize, + DefaultFixedFontSize + }; + + enum UnknownUrlSchemePolicy { + InheritedUnknownUrlSchemePolicy = 0, // TODO: hide + DisallowUnknownUrlSchemes = 1, + AllowUnknownUrlSchemesFromUserInteraction, + AllowAllUnknownUrlSchemes + }; + + //TODO: see if we still need it + //static QWebEngineSettings *defaultSettings(); +public: + ~QWebEngineSettings(); + void setFontFamily(FontFamily which, const QString &family); + QString fontFamily(FontFamily which) const; + void resetFontFamily(FontFamily which); + + void setFontSize(FontSize type, int size); + int fontSize(FontSize type) const; + void resetFontSize(FontSize type); + + void setAttribute(WebAttribute attr, bool on); + bool testAttribute(WebAttribute attr) const; + void resetAttribute(WebAttribute attr); + + void setDefaultTextEncoding(const QString &encoding); + QString defaultTextEncoding() const; + + UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; + void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); + void resetUnknownUrlSchemePolicy(); + +private: + explicit QWebEngineSettings(QWebEngineSettings *parentSettings = nullptr); + void setParentSettings(QWebEngineSettings *parentSettings); + Q_DISABLE_COPY(QWebEngineSettings) + typedef ::QtWebEngineCore::WebEngineSettings QWebEngineSettingsPrivate; + QScopedPointer<QWebEngineSettingsPrivate> d_ptr; + friend class QWebEnginePagePrivate; + friend class QWebEngineProfilePrivate; + friend class QQuickWebEngineSettings; + friend class QtWebEngineCore::WebEngineSettings; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINESETTINGS_H diff --git a/src/core/browser_accessibility_manager_qt.h b/src/core/browser_accessibility_manager_qt.h index 600ad673c..2a1d273b9 100644 --- a/src/core/browser_accessibility_manager_qt.h +++ b/src/core/browser_accessibility_manager_qt.h @@ -47,9 +47,7 @@ #if QT_CONFIG(accessibility) -QT_BEGIN_NAMESPACE -class QAccessibleInterface; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QAccessibleInterface) namespace content { diff --git a/src/core/certificate_error_controller.cpp b/src/core/certificate_error_controller.cpp index d9043bf8e..0c0137ca4 100644 --- a/src/core/certificate_error_controller.cpp +++ b/src/core/certificate_error_controller.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "certificate_error_controller.h" -#include "certificate_error_controller_p.h" #include <net/base/net_errors.h> #include <net/cert/x509_certificate.h> @@ -48,94 +47,136 @@ #include "components/strings/grit/components_strings.h" #include "type_conversion.h" -QT_BEGIN_NAMESPACE - -using namespace QtWebEngineCore; - -ASSERT_ENUMS_MATCH(CertificateErrorController::SslPinnedKeyNotInCertificateChain, net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateCommonNameInvalid, net::ERR_CERT_COMMON_NAME_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateDateInvalid, net::ERR_CERT_DATE_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateAuthorityInvalid, net::ERR_CERT_AUTHORITY_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateContainsErrors, net::ERR_CERT_CONTAINS_ERRORS) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateUnableToCheckRevocation, net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateRevoked, net::ERR_CERT_REVOKED) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateInvalid, net::ERR_CERT_INVALID) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateWeakSignatureAlgorithm, net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateNonUniqueName, net::ERR_CERT_NON_UNIQUE_NAME) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateWeakKey, net::ERR_CERT_WEAK_KEY) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateNameConstraintViolation, net::ERR_CERT_NAME_CONSTRAINT_VIOLATION) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateValidityTooLong, net::ERR_CERT_VALIDITY_TOO_LONG) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateTransparencyRequired, net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateSymantecLegacy, net::ERR_CERT_SYMANTEC_LEGACY) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateKnownInterceptionBlocked, net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED) -ASSERT_ENUMS_MATCH(CertificateErrorController::SslObsoleteVersion, net::ERR_SSL_OBSOLETE_VERSION) -ASSERT_ENUMS_MATCH(CertificateErrorController::CertificateErrorEnd, net::ERR_CERT_END) - -void CertificateErrorControllerPrivate::accept(bool accepted) +namespace QtWebEngineCore { + +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::SslPinnedKeyNotInCertificateChain, + net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateCommonNameInvalid, net::ERR_CERT_BEGIN) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateCommonNameInvalid, + net::ERR_CERT_COMMON_NAME_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateDateInvalid, net::ERR_CERT_DATE_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateAuthorityInvalid, + net::ERR_CERT_AUTHORITY_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateContainsErrors, + net::ERR_CERT_CONTAINS_ERRORS) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateUnableToCheckRevocation, + net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateRevoked, net::ERR_CERT_REVOKED) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateInvalid, net::ERR_CERT_INVALID) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateWeakSignatureAlgorithm, + net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateNonUniqueName, + net::ERR_CERT_NON_UNIQUE_NAME) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateWeakKey, net::ERR_CERT_WEAK_KEY) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateNameConstraintViolation, + net::ERR_CERT_NAME_CONSTRAINT_VIOLATION) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateValidityTooLong, + net::ERR_CERT_VALIDITY_TOO_LONG) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateTransparencyRequired, + net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateSymantecLegacy, + net::ERR_CERT_SYMANTEC_LEGACY) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateKnownInterceptionBlocked, + net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED) +ASSERT_ENUMS_MATCH(QWebEngineCertificateError::SslObsoleteVersion, + net::ERR_SSL_OBSOLETE_VERSION) +// ASSERT_ENUMS_MATCH(QWebEngineCertificateError::CertificateErrorEnd, net::ERR_CERT_END) + +// Copied from chrome/browser/ssl/ssl_error_handler.cc: +static int IsCertErrorFatal(int cert_error) { - std::move(callback).Run(accepted ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE : content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY); + switch (cert_error) { + case net::ERR_CERT_COMMON_NAME_INVALID: + case net::ERR_CERT_DATE_INVALID: + case net::ERR_CERT_AUTHORITY_INVALID: + case net::ERR_CERT_NO_REVOCATION_MECHANISM: + case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: + case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: + case net::ERR_CERT_WEAK_KEY: + case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: + case net::ERR_CERT_VALIDITY_TOO_LONG: + case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED: + case net::ERR_CERT_SYMANTEC_LEGACY: + case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED: + case net::ERR_SSL_OBSOLETE_VERSION: + return false; + case net::ERR_CERT_CONTAINS_ERRORS: + case net::ERR_CERT_REVOKED: + case net::ERR_CERT_INVALID: + case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: + return true; + default: + NOTREACHED(); + } + return true; } -CertificateErrorControllerPrivate::CertificateErrorControllerPrivate(int cert_error, - const net::SSLInfo& ssl_info, - const GURL &request_url, - bool main_frame, - bool fatal_error, - bool strict_enforcement, - base::OnceCallback<void(content::CertificateRequestResultType)> cb - ) - : certError(CertificateErrorController::CertificateError(cert_error)) - , requestUrl(toQt(request_url)) - , resourceType(main_frame ? CertificateErrorController::ResourceTypeMainFrame : CertificateErrorController::ResourceTypeOther) - , fatalError(fatal_error) - , strictEnforcement(strict_enforcement) - , callback(std::move(cb)) +CertificateErrorController::CertificateErrorController( + int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url, + bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> cb) + : m_certError(QWebEngineCertificateError::Type(cert_error)) + , m_requestUrl(toQt(request_url)) + , m_overridable(!IsCertErrorFatal(cert_error) && !strict_enforcement) { + if (m_overridable) + m_callback = std::move(cb); if (auto cert = ssl_info.cert.get()) { - validStart = toQt(cert->valid_start()); - validExpiry = toQt(cert->valid_expiry()); - certificateChain = toCertificateChain(cert); + m_validExpiry = toQt(cert->valid_expiry()); + m_certificateChain = toCertificateChain(cert); } } -CertificateErrorController::CertificateErrorController(CertificateErrorControllerPrivate *p) : d(p) -{ -} - CertificateErrorController::~CertificateErrorController() { - delete d; - d = 0; + if (!answered()) + rejectCertificate(); } -CertificateErrorController::CertificateError CertificateErrorController::error() const +QWebEngineCertificateError::Type CertificateErrorController::error() const { - return d->certError; + return m_certError; } QUrl CertificateErrorController::url() const { - return d->requestUrl; + return m_requestUrl; } bool CertificateErrorController::overridable() const { - return !d->fatalError && !d->strictEnforcement; + return m_overridable; +} + +bool CertificateErrorController::deferred() const +{ + return m_deferred; +} + +void CertificateErrorController::defer() +{ + m_deferred = true; } -bool CertificateErrorController::strictEnforcement() const +bool CertificateErrorController::answered() const { - return d->strictEnforcement; + return m_answered; } void CertificateErrorController::accept(bool accepted) { - d->accept(accepted); + if (answered()) + return; + + m_answered = true; + if (m_callback) + std::move(m_callback) + .Run(accepted ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE + : content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY); } -CertificateErrorController::ResourceType CertificateErrorController::resourceType() const +void CertificateErrorController::deactivate() { - return d->resourceType; + m_callback.Reset(); } static QString getQStringForMessageId(int message_id) { @@ -148,43 +189,43 @@ QString CertificateErrorController::errorString() const // Try to use chromiums translation of the error strings, though not all are // consistently described and we need to use versions that does not contain HTML // formatted text. - switch (d->certError) { - case SslPinnedKeyNotInCertificateChain: + switch (m_certError) { + case QWebEngineCertificateError::SslPinnedKeyNotInCertificateChain: return getQStringForMessageId(IDS_CERT_ERROR_SUMMARY_PINNING_FAILURE_DETAILS); - case CertificateCommonNameInvalid: + case QWebEngineCertificateError::CertificateCommonNameInvalid: return getQStringForMessageId(IDS_CERT_ERROR_COMMON_NAME_INVALID_DESCRIPTION); - case CertificateDateInvalid: - if (QDateTime::currentDateTime() > d->validExpiry) + case QWebEngineCertificateError::CertificateDateInvalid: + if (QDateTime::currentDateTime() > m_validExpiry) return getQStringForMessageId(IDS_CERT_ERROR_EXPIRED_DESCRIPTION); else return getQStringForMessageId(IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION); - case CertificateAuthorityInvalid: - case CertificateKnownInterceptionBlocked: - case CertificateSymantecLegacy: + case QWebEngineCertificateError::CertificateAuthorityInvalid: + case QWebEngineCertificateError::CertificateKnownInterceptionBlocked: + case QWebEngineCertificateError::CertificateSymantecLegacy: return getQStringForMessageId(IDS_CERT_ERROR_AUTHORITY_INVALID_DESCRIPTION); - case CertificateContainsErrors: + case QWebEngineCertificateError::CertificateContainsErrors: return getQStringForMessageId(IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION); - case CertificateNoRevocationMechanism: + case QWebEngineCertificateError::CertificateNoRevocationMechanism: return getQStringForMessageId(IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION); - case CertificateRevoked: + case QWebEngineCertificateError::CertificateRevoked: return getQStringForMessageId(IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION); - case CertificateInvalid: + case QWebEngineCertificateError::CertificateInvalid: return getQStringForMessageId(IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION); - case CertificateWeakSignatureAlgorithm: + case QWebEngineCertificateError::CertificateWeakSignatureAlgorithm: return getQStringForMessageId(IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION); - case CertificateNonUniqueName: + case QWebEngineCertificateError::CertificateNonUniqueName: return getQStringForMessageId(IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME); - case CertificateWeakKey: + case QWebEngineCertificateError::CertificateWeakKey: return getQStringForMessageId(IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); - case CertificateNameConstraintViolation: + case QWebEngineCertificateError::CertificateNameConstraintViolation: return getQStringForMessageId(IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION); - case CertificateValidityTooLong: + case QWebEngineCertificateError::CertificateValidityTooLong: return getQStringForMessageId(IDS_CERT_ERROR_VALIDITY_TOO_LONG_DESCRIPTION); - case CertificateTransparencyRequired: + case QWebEngineCertificateError::CertificateTransparencyRequired: return getQStringForMessageId(IDS_CERT_ERROR_CERTIFICATE_TRANSPARENCY_REQUIRED_DESCRIPTION); - case SslObsoleteVersion: + case QWebEngineCertificateError::SslObsoleteVersion: return getQStringForMessageId(IDS_SSL_ERROR_OBSOLETE_VERSION_DESCRIPTION); - case CertificateUnableToCheckRevocation: // Deprecated in Chromium. + case QWebEngineCertificateError::CertificateUnableToCheckRevocation: // Deprecated in Chromium. default: break; } @@ -194,7 +235,7 @@ QString CertificateErrorController::errorString() const QList<QSslCertificate> CertificateErrorController::certificateChain() const { - return d->certificateChain; + return m_certificateChain; } -QT_END_NAMESPACE +} diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h index 740f7a9d4..ec3e26806 100644 --- a/src/core/certificate_error_controller.h +++ b/src/core/certificate_error_controller.h @@ -52,84 +52,59 @@ #define CERTIFICATE_ERROR_CONTROLLER_H #include "qtwebenginecoreglobal_p.h" - +#include "base/callback.h" +#include "content/public/browser/certificate_request_result_type.h" +#include "qwebenginecertificateerror.h" #include <QtCore/QDateTime> +#include <QtCore/QScopedPointer> #include <QtCore/QUrl> #include <QtNetwork/QSslCertificate> -QT_BEGIN_NAMESPACE +namespace net { +class SSLInfo; +} +class GURL; -class CertificateErrorControllerPrivate; +namespace QtWebEngineCore { class Q_WEBENGINECORE_PRIVATE_EXPORT CertificateErrorController { public: - CertificateErrorController(CertificateErrorControllerPrivate *p); + CertificateErrorController( + int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url, + bool strict_enforcement, + base::OnceCallback<void(content::CertificateRequestResultType)> callback); ~CertificateErrorController(); - // We can't use QSslError::SslErrors, because the error categories doesn't map. - // Keep up to date with net/base/net_errors.h and net::IsCertificateError(): - enum CertificateError { - SslPinnedKeyNotInCertificateChain = -150, - CertificateCommonNameInvalid = -200, - CertificateDateInvalid = -201, - CertificateAuthorityInvalid = -202, - CertificateContainsErrors = -203, - CertificateNoRevocationMechanism = -204, - CertificateUnableToCheckRevocation = -205, - CertificateRevoked = -206, - CertificateInvalid = -207, - CertificateWeakSignatureAlgorithm = -208, - CertificateNonUniqueName = -210, - CertificateWeakKey = -211, - CertificateNameConstraintViolation = -212, - CertificateValidityTooLong = -213, - CertificateTransparencyRequired = -214, - CertificateSymantecLegacy = -215, - CertificateKnownInterceptionBlocked = -217, - SslObsoleteVersion = -218, - CertificateErrorEnd = -219 // not an error, just an enum boundary - }; - - CertificateError error() const; + QWebEngineCertificateError::Type error() const; QUrl url() const; bool overridable() const; - bool strictEnforcement() const; QString errorString() const; - QDateTime validStart() const; QDateTime validExpiry() const; QList<QSslCertificate> certificateChain() const; + bool deferred() const; + void defer(); + + bool answered() const; void accept(bool); - // Note: The resource type should probably not be exported, since once accepted the certificate exception - // counts for all resource types. - // Keep up to date with webkit/common/resource_type.h - enum ResourceType { - ResourceTypeMainFrame = 0, // top level page - ResourceTypeSubFrame, // frame or iframe - ResourceTypeStylesheet, // a CSS stylesheet - ResourceTypeScript, // an external script - ResourceTypeImage, // an image (jpg/gif/png/etc) - ResourceTypeFont, // a font - ResourceTypeOther, // an "other" subresource. - ResourceTypeObject, // an object (or embed) tag for a plugin, - // or a resource that a plugin requested. - ResourceTypeMedia, // a media resource. - ResourceTypeWorker, // the main resource of a dedicated worker. - ResourceTypeSharedWorker, // the main resource of a shared worker. - ResourceTypePrefetch, // an explicitly requested prefetch - ResourceTypeFavicon, // a favicon - ResourceTypeXHR, // a XMLHttpRequest - ResourceTypePing, // a ping request for <a ping> - ResourceTypeServiceWorker, // the main resource of a service worker. - }; + void ignoreCertificateError() { accept(true); } + void rejectCertificate() { accept(false); } - ResourceType resourceType() const; + void deactivate(); + + QWebEngineCertificateError::Type m_certError; + const QUrl m_requestUrl; + QDateTime m_validExpiry; + bool m_overridable; + base::OnceCallback<void(content::CertificateRequestResultType)> m_callback; + QList<QSslCertificate> m_certificateChain; + + bool m_answered = false, m_deferred = false; private: - CertificateErrorControllerPrivate* d; + Q_DISABLE_COPY(CertificateErrorController) }; -QT_END_NAMESPACE - +} #endif // CERTIFICATE_ERROR_CONTROLLER_H diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp index 8a385e4a8..6783175fe 100644 --- a/src/core/chromium_overrides.cpp +++ b/src/core/chromium_overrides.cpp @@ -111,8 +111,7 @@ std::unique_ptr<base::ListValue> GetFontList_SlowBlocking() { std::unique_ptr<base::ListValue> font_list(new base::ListValue); - QFontDatabase database; - for (auto family : database.families()){ + for (auto family : QFontDatabase::families()){ std::unique_ptr<base::ListValue> font_item(new base::ListValue()); font_item->AppendString(family.toStdString()); font_item->AppendString(family.toStdString()); // localized name. diff --git a/src/core/client_cert_select_controller.cpp b/src/core/client_cert_select_controller.cpp index 0baaf2bc5..2f2d24716 100644 --- a/src/core/client_cert_select_controller.cpp +++ b/src/core/client_cert_select_controller.cpp @@ -50,9 +50,7 @@ #include <QDebug> -QT_BEGIN_NAMESPACE - -using namespace QtWebEngineCore; +namespace QtWebEngineCore { ClientCertSelectController::ClientCertSelectController(net::SSLCertRequestInfo *certRequestInfo, std::vector<std::unique_ptr<net::ClientCertIdentity>> clientCerts, @@ -73,8 +71,6 @@ ClientCertSelectController::~ClientCertSelectController() m_delegate->ContinueWithCertificate(nullptr, nullptr); } -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) - void ClientCertSelectController::selectNone() { if (m_selected) { @@ -132,7 +128,7 @@ void ClientCertSelectController::select(const QSslCertificate &certificate) << " Selected certificate needs to be one of the offered"; } -QVector<QSslCertificate> ClientCertSelectController::certificates() const +QList<QSslCertificate> ClientCertSelectController::certificates() const { if (!m_certificates.isEmpty()) return m_certificates; @@ -144,6 +140,4 @@ QVector<QSslCertificate> ClientCertSelectController::certificates() const return m_certificates; } -#endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) - -QT_END_NAMESPACE +} diff --git a/src/core/client_cert_select_controller.h b/src/core/client_cert_select_controller.h index f121c1155..3a733f56f 100644 --- a/src/core/client_cert_select_controller.h +++ b/src/core/client_cert_select_controller.h @@ -55,10 +55,8 @@ #include <QtNetwork/qtnetwork-config.h> #include <QtCore/QUrl> -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) -#include <QtCore/QVector> +#include <QtCore/QList> #include <QtNetwork/QSslCertificate> -#endif #include <memory> namespace content { @@ -70,7 +68,7 @@ class ClientCertIdentity; class SSLCertRequestInfo; } -QT_BEGIN_NAMESPACE +namespace QtWebEngineCore { class Q_WEBENGINECORE_PRIVATE_EXPORT ClientCertSelectController { public: @@ -80,22 +78,20 @@ public: ~ClientCertSelectController(); QUrl hostAndPort() const { return m_hostAndPort; } -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) void selectNone(); void select(const QSslCertificate &certificate); void select(int index); - QVector<QSslCertificate> certificates() const; -#endif + QList<QSslCertificate> certificates() const; private: QUrl m_hostAndPort; std::vector<std::unique_ptr<net::ClientCertIdentity>> m_clientCerts; std::unique_ptr<content::ClientCertificateDelegate> m_delegate; - mutable QVector<QSslCertificate> m_certificates; + mutable QList<QSslCertificate> m_certificates; bool m_selected; }; -QT_END_NAMESPACE +} #endif // CLIENT_CERT_SELECT_CONTROLLER_H diff --git a/src/core/compositor/compositor.cpp b/src/core/compositor/compositor.cpp new file mode 100644 index 000000000..655126f20 --- /dev/null +++ b/src/core/compositor/compositor.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "compositor.h" + +#include "base/memory/ref_counted.h" +#include "components/viz/common/surfaces/frame_sink_id.h" + +#include <QHash> +#include <QImage> +#include <QMutex> + +namespace QtWebEngineCore { + +// Compositor::Id + +Compositor::Id::Id(viz::FrameSinkId fid) : client_id(fid.client_id()), sink_id(fid.sink_id()) { } + +static size_t qHash(Compositor::Id id, size_t seed = 0) +{ + QtPrivate::QHashCombine hasher; + seed = hasher(seed, id.client_id); + seed = hasher(seed, id.sink_id); + return seed; +} + +static bool operator==(Compositor::Id id1, Compositor::Id id2) +{ + return id1.client_id == id2.client_id && id1.sink_id == id2.sink_id; +} + +// Compositor::Binding and Compositor::Bindings + +struct Compositor::Binding +{ + const Id id; + Compositor *compositor = nullptr; + Observer *observer = nullptr; + + Binding(Id id) : id(id) { } + ~Binding(); +}; + +class Compositor::BindingMap +{ +public: + void lock() { m_mutex.lock(); } + + void unlock() { m_mutex.unlock(); } + + Binding *findOrCreate(Id id) + { + auto it = m_map.find(id); + if (it == m_map.end()) + it = m_map.insert(id, new Binding(id)); + return *it; + } + + void remove(Id id) { m_map.remove(id); } + +private: + QMutex m_mutex; + QHash<Id, Binding *> m_map; +} static g_bindings; + +Compositor::Binding::~Binding() +{ + g_bindings.remove(id); +} + +// Compositor::Observer + +void Compositor::Observer::bind(Id id) +{ + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->observer); + m_binding->observer = this; + g_bindings.unlock(); +} + +void Compositor::Observer::unbind() +{ + DCHECK(m_binding); + g_bindings.lock(); + m_binding->observer = nullptr; + if (m_binding->compositor == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); +} + +Compositor::Handle<Compositor> Compositor::Observer::compositor() +{ + if (!m_binding) + return nullptr; + g_bindings.lock(); + if (m_binding->compositor) + return m_binding->compositor; // delay unlock + g_bindings.unlock(); + return nullptr; +} + +// Compositor + +void Compositor::bind(Id id) +{ + DCHECK(!m_binding); + g_bindings.lock(); + m_binding = g_bindings.findOrCreate(id); + DCHECK(!m_binding->compositor); + m_binding->compositor = this; + g_bindings.unlock(); +} + +void Compositor::unbind() +{ + DCHECK(m_binding); + g_bindings.lock(); + m_binding->compositor = nullptr; + if (m_binding->observer == nullptr) + delete m_binding; + m_binding = nullptr; + g_bindings.unlock(); +} + +Compositor::Handle<Compositor::Observer> Compositor::observer() +{ + if (!m_binding) + return nullptr; + g_bindings.lock(); + if (m_binding->observer) + return m_binding->observer; // delay unlock + g_bindings.unlock(); + return nullptr; +} + +QImage Compositor::image() +{ + Q_UNREACHABLE(); + return {}; +} + +void Compositor::waitForTexture() +{ + Q_UNREACHABLE(); +} + +int Compositor::textureId() +{ + Q_UNREACHABLE(); + return 0; +} + +// static +void Compositor::unlockBindings() +{ + g_bindings.unlock(); +} +} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor.h b/src/core/compositor/compositor.h new file mode 100644 index 000000000..316178891 --- /dev/null +++ b/src/core/compositor/compositor.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_H +#define COMPOSITOR_H + +#include "qtwebenginecoreglobal_p.h" + +QT_BEGIN_NAMESPACE +class QImage; +class QSize; +QT_END_NAMESPACE + +namespace viz { +class FrameSinkId; +} // namespace viz + +namespace QtWebEngineCore { + +// Produces composited frames for display. +// +// Used by quick/widgets libraries for accessing the frame and +// controlling frame swapping. Must be cast to a subclass to access +// the frame as QImage or OpenGL texture, etc. +class Q_WEBENGINECORE_PRIVATE_EXPORT Compositor +{ + struct Binding; + +public: + // Identifies the implementation type. + enum class Type { + Software, + OpenGL, + }; + + // Identifies a compositor. + // + // The purpose of assigning ids to compositors is to allow the + // corresponding observer to be registered before the compositor + // itself is created, which is necessary since the creation + // happens on a different thread in the depths of viz. + // + // (Maps to viz::FrameSinkId internally). + struct Id + { + quint32 client_id; + quint32 sink_id; + + Id(viz::FrameSinkId); + }; + + // Pointer to Compositor or Observer that holds a lock to prevent + // either from being unbound and destroyed. + template<typename T> + class Handle + { + public: + Handle(std::nullptr_t) : m_data(nullptr) { } + Handle(T *data) : m_data(data) { } + Handle(Handle &&that) : m_data(that.m_data) { that.m_data = nullptr; } + ~Handle() + { + if (m_data) + Compositor::unlockBindings(); + } + T *operator->() const { return m_data; } + T &operator*() const { return *m_data; } + explicit operator bool() const { return m_data; } + + private: + T *m_data; + }; + + // Observes the compositor corresponding to the given id. + // + // Only one observer can exist per compositor. + class Q_WEBENGINECORE_PRIVATE_EXPORT Observer + { + public: + // Binding to compositor + void bind(Id id); + void unbind(); + + // Compositor if bound + Handle<Compositor> compositor(); + + // There's a new frame ready, time to swapFrame(). + virtual void readyToSwap() = 0; + + protected: + Observer() = default; + ~Observer() = default; + + private: + Binding *m_binding = nullptr; + }; + + // Type determines which methods can be called. + Type type() const { return m_type; } + + // Binding to observer. + void bind(Id id); + void unbind(); + + // Observer if bound. + Handle<Observer> observer(); + + // Update to next frame if possible. + virtual void swapFrame() = 0; + + // Ratio of pixels to DIPs. + // + // Don't use the devicePixelRatio of QImage, it's always 1. + virtual float devicePixelRatio() = 0; + + // Size of frame in pixels. + virtual QSize size() = 0; + + // Whether frame needs an alpha channel. + // + // In software mode, the image format can be either + // QImage::Format_ARGB32_Premultiplied or + // QImage::Format_RGBA8888_Premultiplied + // + // In OpenGL mode, the texture format is either GL_RGBA or GL_RGB. + virtual bool hasAlphaChannel() = 0; + + // (Software) QImage of the frame. + // + // This is a big image so we should try not to make copies of it. + // In particular, the client should drop its QImage reference + // before calling swapFrame(), otherwise each swap will cause a + // detach. + virtual QImage image(); + + // (OpenGL) Wait on texture fence in Qt's current OpenGL context. + virtual void waitForTexture(); + + // (OpenGL) Texture of the frame. + virtual int textureId(); + +protected: + Compositor(Type type) : m_type(type) { } + ~Compositor() = default; + +private: + template<typename T> + friend class Handle; + + class BindingMap; + static void unlockBindings(); + + const Type m_type; + Binding *m_binding = nullptr; +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_H diff --git a/src/core/compositor/display_frame_sink.cpp b/src/core/compositor/display_frame_sink.cpp deleted file mode 100644 index 945600299..000000000 --- a/src/core/compositor/display_frame_sink.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "display_frame_sink.h" - -#include <QMap> - -namespace QtWebEngineCore { - -namespace { - -class DisplayFrameSinkMap -{ -public: - static DisplayFrameSinkMap *instance() - { - static DisplayFrameSinkMap map; - return ↦ - } - - scoped_refptr<DisplayFrameSink> findOrCreate(viz::FrameSinkId frameSinkId) - { - QMutexLocker locker(&m_mutex); - auto it = m_map.find(frameSinkId); - if (it == m_map.end()) - it = m_map.insert(frameSinkId, new DisplayFrameSink(frameSinkId)); - return *it; - } - - void remove(viz::FrameSinkId frameSinkId) - { - QMutexLocker locker(&m_mutex); - m_map.remove(frameSinkId); - } - -private: - mutable QMutex m_mutex; - QMap<viz::FrameSinkId, DisplayFrameSink *> m_map; -}; - -} // namespace - -// static -scoped_refptr<DisplayFrameSink> DisplayFrameSink::findOrCreate(viz::FrameSinkId frameSinkId) -{ - return DisplayFrameSinkMap::instance()->findOrCreate(frameSinkId); -} - -DisplayFrameSink::DisplayFrameSink(viz::FrameSinkId frameSinkId) - : m_frameSinkId(frameSinkId) -{ - DCHECK(m_frameSinkId.is_valid()); -} - -DisplayFrameSink::~DisplayFrameSink() -{ - DisplayFrameSinkMap::instance()->remove(m_frameSinkId); -} - -void DisplayFrameSink::connect(DisplayConsumer *consumer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_consumer == nullptr); - m_consumer = consumer; -} - -void DisplayFrameSink::connect(DisplayProducer *producer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_producer == nullptr); - m_producer = producer; -} - -void DisplayFrameSink::disconnect(DisplayConsumer *consumer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_consumer == consumer); - m_consumer = nullptr; -} - -void DisplayFrameSink::disconnect(DisplayProducer *producer) -{ - QMutexLocker locker(&m_mutex); - DCHECK(m_producer == producer); - m_producer = nullptr; -} - -void DisplayFrameSink::scheduleUpdate() -{ - QMutexLocker locker(&m_mutex); - if (m_consumer) - m_consumer->scheduleUpdate(); -} - -QSGNode *DisplayFrameSink::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) -{ - QMutexLocker locker(&m_mutex); - QSGNode *newNode = oldNode; - if (m_producer) - newNode = m_producer->updatePaintNode(oldNode, delegate); - return newNode; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_gl_output_surface.cpp b/src/core/compositor/display_gl_output_surface.cpp index 370eb07e6..16a925bd4 100644 --- a/src/core/compositor/display_gl_output_surface.cpp +++ b/src/core/compositor/display_gl_output_surface.cpp @@ -39,6 +39,8 @@ #include "display_gl_output_surface.h" +#include "type_conversion.h" + #include "base/threading/thread_task_runner_handle.h" #include "components/viz/service/display/display.h" #include "components/viz/service/display/output_surface_frame.h" @@ -51,8 +53,10 @@ namespace QtWebEngineCore { -DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider) +DisplayGLOutputSurface::DisplayGLOutputSurface( + scoped_refptr<viz::VizProcessContextProvider> contextProvider) : OutputSurface(contextProvider) + , Compositor(Compositor::Type::OpenGL) , m_commandBuffer(contextProvider->command_buffer()) , m_gl(contextProvider->ContextGL()) , m_vizContextProvider(contextProvider) @@ -63,18 +67,16 @@ DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessCont DisplayGLOutputSurface::~DisplayGLOutputSurface() { + unbind(); m_vizContextProvider->SetUpdateVSyncParametersCallback(viz::UpdateVSyncParametersCallback()); m_gl->DeleteFramebuffers(1, &m_fboId); - if (m_sink) - m_sink->disconnect(this); } // Called from viz::Display::Initialize. void DisplayGLOutputSurface::BindToClient(viz::OutputSurfaceClient *client) { m_display = static_cast<viz::Display *>(client); - m_sink = DisplayFrameSink::findOrCreate(m_display->frame_sink_id()); - m_sink->connect(this); + bind(m_display->frame_sink_id()); } // Triggered by ui::Compositor::SetVisible(true). @@ -213,7 +215,8 @@ void DisplayGLOutputSurface::swapBuffersOnGpuThread(unsigned int id, std::unique m_readyToUpdate = true; } - m_sink->scheduleUpdate(); + if (auto obs = observer()) + obs->readyToSwap(); } void DisplayGLOutputSurface::swapBuffersOnVizThread() @@ -300,4 +303,45 @@ gfx::OverlayTransform DisplayGLOutputSurface::GetDisplayTransform() return gfx::OVERLAY_TRANSFORM_NONE; } +void DisplayGLOutputSurface::swapFrame() +{ + QMutexLocker locker(&m_mutex); + if (m_readyToUpdate) { + std::swap(m_middleBuffer, m_frontBuffer); + m_taskRunner->PostTask(FROM_HERE, + base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnVizThread, + base::Unretained(this))); + m_taskRunner.reset(); + m_readyToUpdate = false; + } +} + +void DisplayGLOutputSurface::waitForTexture() +{ + if (m_frontBuffer && m_frontBuffer->fence) { + m_frontBuffer->fence->wait(); + m_frontBuffer->fence.reset(); + } +} + +int DisplayGLOutputSurface::textureId() +{ + return m_frontBuffer ? m_frontBuffer->serviceId : 0; +} + +QSize DisplayGLOutputSurface::size() +{ + return m_frontBuffer ? toQt(m_frontBuffer->shape.sizeInPixels) : QSize(); +} + +bool DisplayGLOutputSurface::hasAlphaChannel() +{ + return m_frontBuffer ? m_frontBuffer->shape.hasAlpha : false; +} + +float DisplayGLOutputSurface::devicePixelRatio() +{ + return m_frontBuffer ? m_frontBuffer->shape.devicePixelRatio : 1; +} + } // namespace QtWebEngineCore diff --git a/src/core/compositor/display_gl_output_surface.h b/src/core/compositor/display_gl_output_surface.h index d2e203b4e..5c6b1ab23 100644 --- a/src/core/compositor/display_gl_output_surface.h +++ b/src/core/compositor/display_gl_output_surface.h @@ -41,7 +41,7 @@ #define DISPLAY_GL_OUTPUT_SURFACE_H #include "compositor_resource_fence.h" -#include "display_frame_sink.h" +#include "compositor.h" #include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/service/display/output_surface.h" @@ -49,6 +49,8 @@ #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/sync_token.h" +#include <QMutex> + namespace viz { class Display; class SyntheticBeginFrameSource; @@ -56,9 +58,7 @@ class SyntheticBeginFrameSource; namespace QtWebEngineCore { -// NOTE: Some methods are defined in display_gl_output_surface_qsg.cpp due -// to conflicts between Qt & Chromium OpenGL APIs. -class DisplayGLOutputSurface final : public viz::OutputSurface, public DisplayProducer +class DisplayGLOutputSurface final : public viz::OutputSurface, public Compositor { public: DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider); @@ -88,8 +88,13 @@ public: scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper() override; gpu::MemoryTracker *GetMemoryTracker() override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + void waitForTexture() override; + int textureId() override; + QSize size() override; + bool hasAlphaChannel() override; + float devicePixelRatio() override; private: struct Shape @@ -136,7 +141,6 @@ private: mutable QMutex m_mutex; uint32_t m_fboId = 0; viz::Display *m_display = nullptr; - scoped_refptr<DisplayFrameSink> m_sink; Shape m_currentShape; std::unique_ptr<Buffer> m_backBuffer; std::unique_ptr<Buffer> m_middleBuffer; diff --git a/src/core/compositor/display_gl_output_surface_qsg.cpp b/src/core/compositor/display_gl_output_surface_qsg.cpp deleted file mode 100644 index 0e9fff6e3..000000000 --- a/src/core/compositor/display_gl_output_surface_qsg.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "display_gl_output_surface.h" - -#include "compositor_resource_fence.h" -#include "render_widget_host_view_qt_delegate.h" -#include "type_conversion.h" - -#include <QOpenGLFunctions> -#include <QSGImageNode> -#include <QSGTexture> - -namespace QtWebEngineCore { - -class DisplayGLOutputSurface::Texture final : public QSGTexture -{ -public: - Texture(uint32_t id, QSize sizeInPixels, bool hasAlphaChannel, scoped_refptr<CompositorResourceFence> fence) - : m_id(id) - , m_sizeInPixels(sizeInPixels) - , m_hasAlphaChannel(hasAlphaChannel) - , m_fence(std::move(fence)) - { - } - - // QSGTexture: - int textureId() const override { return m_id; } - QSize textureSize() const override { return m_sizeInPixels; } - bool hasAlphaChannel() const override { return m_hasAlphaChannel; } - bool hasMipmaps() const override { return false; } - void bind() override - { - if (m_fence) { - m_fence->wait(); - m_fence.reset(); - } - - QOpenGLContext *context = QOpenGLContext::currentContext(); - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, m_id); - } - -private: - uint32_t m_id; - QSize m_sizeInPixels; - bool m_hasAlphaChannel; - scoped_refptr<CompositorResourceFence> m_fence; -}; - -QSGNode *DisplayGLOutputSurface::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) -{ - { - QMutexLocker locker(&m_mutex); - if (m_readyToUpdate) { - std::swap(m_middleBuffer, m_frontBuffer); - m_taskRunner->PostTask( - FROM_HERE, - base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnVizThread, base::Unretained(this))); - m_taskRunner.reset(); - m_readyToUpdate = false; - } - } - - if (!m_frontBuffer) - return oldNode; - - auto node = static_cast<QSGImageNode *>(oldNode); - if (!node) - node = delegate->createImageNode(); - - QSize sizeInPixels = toQt(m_frontBuffer->shape.sizeInPixels); - QSizeF sizeInDips = QSizeF(sizeInPixels) / m_frontBuffer->shape.devicePixelRatio; - QRectF rectInDips(QPointF(0, 0), sizeInDips); - node->setRect(rectInDips); - node->setOwnsTexture(true); - node->setTexture(new Texture(m_frontBuffer->serviceId, - sizeInPixels, - m_frontBuffer->shape.hasAlpha, - m_frontBuffer->fence)); - node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically); - - return node; -} - -} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_software_output_surface.cpp b/src/core/compositor/display_software_output_surface.cpp index ba99799f0..218bff94a 100644 --- a/src/core/compositor/display_software_output_surface.cpp +++ b/src/core/compositor/display_software_output_surface.cpp @@ -39,7 +39,7 @@ #include "display_software_output_surface.h" -#include "display_frame_sink.h" +#include "compositor.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" @@ -49,28 +49,29 @@ #include <QMutex> #include <QPainter> -#include <QSGImageNode> namespace QtWebEngineCore { -class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, public DisplayProducer +class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDevice, + public Compositor { public: + Device(); ~Device(); - // Called from DisplaySoftwareOutputSurface. - void bind(viz::FrameSinkId frameSinkId); - // Overridden from viz::SoftwareOutputDevice. void Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) override; void OnSwapBuffers(SwapBuffersCallback swap_ack_callback) override; - // Overridden from DisplayProducer. - QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) override; + // Overridden from Compositor. + void swapFrame() override; + QImage image() override; + float devicePixelRatio() override; + QSize size() override; + bool hasAlphaChannel() override; private: mutable QMutex m_mutex; - scoped_refptr<DisplayFrameSink> m_sink; float m_devicePixelRatio = 1.0; scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; SwapBuffersCallback m_swapCompletionCallback; @@ -78,16 +79,13 @@ private: float m_imageDevicePixelRatio = 1.0; }; -DisplaySoftwareOutputSurface::Device::~Device() -{ - if (m_sink) - m_sink->disconnect(this); -} +DisplaySoftwareOutputSurface::Device::Device() + : Compositor(Type::Software) +{} -void DisplaySoftwareOutputSurface::Device::bind(viz::FrameSinkId frameSinkId) +DisplaySoftwareOutputSurface::Device::~Device() { - m_sink = DisplayFrameSink::findOrCreate(frameSinkId); - m_sink->connect(this); + unbind(); } void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) @@ -104,7 +102,8 @@ void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(SwapBuffersCallback swa QMutexLocker locker(&m_mutex); m_taskRunner = base::ThreadTaskRunnerHandle::Get(); m_swapCompletionCallback = std::move(swap_ack_callback); - m_sink->scheduleUpdate(); + if (auto obs = observer()) + obs->readyToSwap(); } inline QImage::Format imageFormat(SkColorType colorType) @@ -120,41 +119,51 @@ inline QImage::Format imageFormat(SkColorType colorType) } } -QSGNode *DisplaySoftwareOutputSurface::Device::updatePaintNode( - QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) +void DisplaySoftwareOutputSurface::Device::swapFrame() { QMutexLocker locker(&m_mutex); - // Delete old node to make sure refcount of m_image is at most 1. - delete oldNode; - QSGImageNode *node = delegate->createImageNode(); - - if (m_swapCompletionCallback) { - SkPixmap skPixmap; - surface_->peekPixels(&skPixmap); - QImage image(reinterpret_cast<const uchar *>(skPixmap.addr()), - viewport_pixel_size_.width(), viewport_pixel_size_.height(), - skPixmap.rowBytes(), imageFormat(skPixmap.colorType())); - if (m_image.size() == image.size()) { - QRect damageRect = toQt(damage_rect_); - QPainter painter(&m_image); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.drawImage(damageRect, image, damageRect); - } else { - m_image = image; - m_image.detach(); - } - m_imageDevicePixelRatio = m_devicePixelRatio; - m_taskRunner->PostTask(FROM_HERE, base::BindOnce(std::move(m_swapCompletionCallback), toGfx(m_image.size()))); - m_taskRunner.reset(); + if (!m_swapCompletionCallback) + return; + + SkPixmap skPixmap; + surface_->peekPixels(&skPixmap); + QImage image(reinterpret_cast<const uchar *>(skPixmap.addr()), viewport_pixel_size_.width(), + viewport_pixel_size_.height(), skPixmap.rowBytes(), + imageFormat(skPixmap.colorType())); + if (m_image.size() == image.size()) { + QRect damageRect = toQt(damage_rect_); + QPainter painter(&m_image); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(damageRect, image, damageRect); + } else { + m_image = image; + m_image.detach(); } + m_imageDevicePixelRatio = m_devicePixelRatio; + m_taskRunner->PostTask( + FROM_HERE, base::BindOnce(std::move(m_swapCompletionCallback), toGfx(m_image.size()))); + m_taskRunner.reset(); +} - QSizeF sizeInDips = QSizeF(m_image.size()) / m_imageDevicePixelRatio; - node->setRect(QRectF(QPointF(0, 0), sizeInDips)); - node->setOwnsTexture(true); - node->setTexture(delegate->createTextureFromImage(m_image)); +QImage DisplaySoftwareOutputSurface::Device::image() +{ + return m_image; +} + +float DisplaySoftwareOutputSurface::Device::devicePixelRatio() +{ + return m_imageDevicePixelRatio; +} - return node; +QSize DisplaySoftwareOutputSurface::Device::size() +{ + return m_image.size(); +} + +bool DisplaySoftwareOutputSurface::Device::hasAlphaChannel() +{ + return m_image.format() == QImage::Format_ARGB32_Premultiplied; } DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface() diff --git a/src/core/config/common.pri b/src/core/config/common.pri index d9d64e76b..b48d0b496 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -26,9 +26,10 @@ qtConfig(webengine-webrtc) { qtConfig(webengine-proprietary-codecs) { gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\" - qtConfig(webengine-webrtc) { - gn_args += rtc_use_h264=true - } +# Fix after updating 3rdparty in dev to include the right fix +# qtConfig(webengine-webrtc) { +# gn_args += rtc_use_h264=true +# } } else { gn_args += proprietary_codecs=false } diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index c2c78ff8b..fa960c58c 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -77,10 +77,6 @@ #include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_implementation.h" -#include "ui/gl/gl_share_group.h" -#include "ui/gl/gpu_timing.h" #include "url/url_util_qt.h" #include "qtwebengine/browser/qtwebengine_content_browser_overlay_manifest.h" @@ -92,7 +88,6 @@ #include "browser_main_parts_qt.h" #include "browser_message_filter_qt.h" #include "certificate_error_controller.h" -#include "certificate_error_controller_p.h" #include "client_cert_select_controller.h" #include "devtools_manager_delegate_qt.h" #include "login_delegate_qt.h" @@ -102,6 +97,7 @@ #include "net/proxying_restricted_cookie_manager_qt.h" #include "net/proxying_url_loader_factory_qt.h" #include "net/system_network_context_manager.h" +#include "ozone/gl_share_context_qt.h" #include "platform_notification_service_qt.h" #include "profile_qt.h" #include "profile_io_data_qt.h" @@ -222,93 +218,6 @@ bool IsHandledProtocol(base::StringPiece scheme) namespace QtWebEngineCore { -class QtShareGLContext : public gl::GLContext { -public: - QtShareGLContext(QOpenGLContext *qtContext) - : gl::GLContext(0) - , m_handle(0) - { - QString platform = qApp->platformName().toLower(); - QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); - if (platform == QLatin1String("xcb") || platform == QLatin1String("offscreen")) { - if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("glxcontext"), qtContext); - } else if (platform == QLatin1String("cocoa")) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("cglcontextobj"), qtContext); - else if (platform == QLatin1String("qnx")) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else if (platform == QLatin1String("eglfs") || platform == QLatin1String("wayland") - || platform == QLatin1String("wayland-egl")) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else if (platform == QLatin1String("windows")) { - if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglContext"), qtContext); - else - m_handle = pni->nativeResourceForContext(QByteArrayLiteral("renderingcontext"), qtContext); - } else { - qFatal("%s platform not yet supported", platform.toLatin1().constData()); - // Add missing platforms once they work. - Q_UNREACHABLE(); - } - } - - void* GetHandle() override { return m_handle; } - unsigned int CheckStickyGraphicsResetStatusImpl() override - { -#if QT_CONFIG(opengl) - if (QOpenGLContext *context = qt_gl_global_share_context()) { - if (context->format().testOption(QSurfaceFormat::ResetNotification)) - return context->extraFunctions()->glGetGraphicsResetStatus(); - } -#endif - return 0 /*GL_NO_ERROR*/; - } - - // We don't care about the rest, this context shouldn't be used except for its handle. - bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override { Q_UNREACHABLE(); return false; } - bool MakeCurrentImpl(gl::GLSurface *) override { Q_UNREACHABLE(); return false; } - void ReleaseCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); } - bool IsCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); return false; } - scoped_refptr<gl::GPUTimingClient> CreateGPUTimingClient() override - { - return nullptr; - } - const gfx::ExtensionSet& GetExtensions() override - { - static const gfx::ExtensionSet s_emptySet; - return s_emptySet; - } - void ResetExtensions() override - { - } - -private: - void *m_handle; -}; - -class ShareGroupQtQuick : public gl::GLShareGroup { -public: - gl::GLContext* GetContext() override { return m_shareContextQtQuick.get(); } - void AboutToAddFirstContext() override; - -private: - scoped_refptr<QtShareGLContext> m_shareContextQtQuick; -}; - -void ShareGroupQtQuick::AboutToAddFirstContext() -{ -#if QT_CONFIG(opengl) - // This currently has to be setup by ::main in all applications using QQuickWebEngineView with delegated rendering. - QOpenGLContext *shareContext = qt_gl_global_share_context(); - if (!shareContext) { - qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to call QtWebEngine::initialize() in your main() function before QCoreApplication is created."); - } - m_shareContextQtQuick = new QtShareGLContext(shareContext); -#endif -} - ContentBrowserClientQt::ContentBrowserClientQt() { } @@ -357,9 +266,9 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost gl::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup() { - if (!m_shareGroupQtQuick.get()) - m_shareGroupQtQuick = new ShareGroupQtQuick; - return m_shareGroupQtQuick.get(); + if (!m_shareGroupQt.get()) + m_shareGroupQt = new ShareGroupQt; + return m_shareGroupQt.get(); } content::MediaObserver *ContentBrowserClientQt::GetMediaObserver() @@ -389,55 +298,18 @@ scoped_refptr<content::QuotaPermissionContext> ContentBrowserClientQt::CreateQuo return new QuotaPermissionContextQt; } -// Copied from chrome/browser/ssl/ssl_error_handler.cc: -static int IsCertErrorFatal(int cert_error) -{ - switch (cert_error) { - case net::ERR_CERT_COMMON_NAME_INVALID: - case net::ERR_CERT_DATE_INVALID: - case net::ERR_CERT_AUTHORITY_INVALID: - case net::ERR_CERT_NO_REVOCATION_MECHANISM: - case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: - case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: - case net::ERR_CERT_WEAK_KEY: - case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: - case net::ERR_CERT_VALIDITY_TOO_LONG: - case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED: - case net::ERR_CERT_SYMANTEC_LEGACY: - case net::ERR_CERT_KNOWN_INTERCEPTION_BLOCKED: - case net::ERR_SSL_OBSOLETE_VERSION: - return false; - case net::ERR_CERT_CONTAINS_ERRORS: - case net::ERR_CERT_REVOKED: - case net::ERR_CERT_INVALID: - case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: - return true; - default: - NOTREACHED(); - } - return true; -} - void ContentBrowserClientQt::AllowCertificateError(content::WebContents *webContents, int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url, - bool is_main_frame_request, + bool /* is_main_frame_request */, bool strict_enforcement, base::OnceCallback<void(content::CertificateRequestResultType)> callback) { WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); - QSharedPointer<CertificateErrorController> errorController( - new CertificateErrorController( - new CertificateErrorControllerPrivate( - cert_error, - ssl_info, - request_url, - is_main_frame_request, - IsCertErrorFatal(cert_error), - strict_enforcement, - std::move(callback)))); + QSharedPointer<CertificateErrorController> errorController(new CertificateErrorController( + cert_error, ssl_info, request_url, strict_enforcement, std::move(callback))); contentsDelegate->allowCertificateError(errorController); } @@ -1154,7 +1026,7 @@ void ContentBrowserClientQt::ConfigureNetworkContextParams( std::vector<base::FilePath> ContentBrowserClientQt::GetNetworkContextsParentDirectory() { return { - toFilePath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)), + toFilePath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)), toFilePath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) }; } @@ -1234,7 +1106,7 @@ void ContentBrowserClientQt::RegisterNonNetworkSubresourceURLLoaderFactories(int #endif if (!install_file_scheme && web_contents) { const auto *settings = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate())->webEngineSettings(); - if (settings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls)) { + if (settings->testAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls)) { for (const auto &local_scheme : url::GetLocalSchemes()) { if (url.SchemeIs(local_scheme)) { install_file_scheme = true; diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index 1ccd2926d..8b891131f 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -66,7 +66,7 @@ class GLShareGroup; namespace QtWebEngineCore { -class ShareGroupQtQuick; +class ShareGroupQt; class ContentBrowserClientQt : public content::ContentBrowserClient { @@ -268,7 +268,7 @@ public: std::string GetProduct() override; private: - scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick; + scoped_refptr<ShareGroupQt> m_shareGroupQt; std::string m_appLocale; std::string m_cachedQtLocale; }; diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index 108dd3221..a42ee4aff 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -52,8 +52,8 @@ SOURCES = \ color_chooser_controller.cpp \ common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ + compositor/compositor.cpp \ compositor/content_gpu_client_qt.cpp \ - compositor/display_frame_sink.cpp \ compositor/display_overrides.cpp \ compositor/display_software_output_surface.cpp \ content_client_qt.cpp \ @@ -88,6 +88,7 @@ SOURCES = \ net/url_request_custom_job_proxy.cpp \ net/webui_controller_factory_qt.cpp \ ozone/gl_context_qt.cpp \ + ozone/gl_share_context_qt.cpp \ ozone/gl_ozone_egl_qt.cpp \ ozone/gl_surface_qt.cpp \ ozone/gl_surface_egl_qt.cpp \ @@ -107,6 +108,7 @@ SOURCES = \ register_protocol_handler_request_controller_impl.cpp \ render_view_context_menu_qt.cpp \ render_widget_host_view_qt.cpp \ + render_widget_host_view_qt_delegate_client.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/content_settings_observer_qt.cpp \ renderer/render_frame_observer_qt.cpp \ @@ -145,7 +147,6 @@ HEADERS = \ browsing_data_remover_delegate_qt.h \ browser_main_parts_qt.h \ browser_message_filter_qt.h \ - certificate_error_controller_p.h \ certificate_error_controller.h \ client_cert_select_controller.h \ clipboard_change_observer.h \ @@ -154,8 +155,8 @@ HEADERS = \ color_chooser_controller_p.h \ color_chooser_controller.h \ common/qt_messages.h \ + compositor/compositor.h \ compositor/content_gpu_client_qt.h \ - compositor/display_frame_sink.h \ compositor/display_software_output_surface.h \ content_client_qt.h \ content_browser_client_qt.h \ @@ -188,6 +189,7 @@ HEADERS = \ net/url_request_custom_job_proxy.h \ net/webui_controller_factory_qt.h \ ozone/gl_context_qt.h \ + ozone/gl_share_context_qt.h \ ozone/gl_ozone_egl_qt.h \ ozone/gl_surface_qt.h \ ozone/gl_surface_egl_qt.h \ @@ -212,6 +214,7 @@ HEADERS = \ render_view_context_menu_qt.h \ render_widget_host_view_qt.h \ render_widget_host_view_qt_delegate.h \ + render_widget_host_view_qt_delegate_client.h \ renderer/content_renderer_client_qt.h \ renderer/content_settings_observer_qt.h \ renderer/render_frame_observer_qt.h \ @@ -273,12 +276,14 @@ qtConfig(webengine-printing-and-pdf) { printing/printing_message_filter_qt.cpp \ printing/print_view_manager_base_qt.cpp \ printing/print_view_manager_qt.cpp \ + printing/printer_worker.cpp \ renderer/print_web_view_helper_delegate_qt.cpp HEADERS += \ printing/printing_message_filter_qt.h \ printing/print_view_manager_base_qt.h \ printing/print_view_manager_qt.h \ + printing/printer_worker.h \ renderer/print_web_view_helper_delegate_qt.h # pdf sources @@ -289,11 +294,11 @@ qtConfig(webengine-printing-and-pdf) { contains(QT_CONFIG, opengl) { SOURCES += \ compositor/compositor_resource_fence.cpp \ - compositor/display_gl_output_surface.cpp \ - compositor/display_gl_output_surface_qsg.cpp + compositor/display_gl_output_surface.cpp HEADERS += \ compositor/compositor_resource_fence.h \ compositor/display_gl_output_surface.h + macos { HEADERS+=macos_context_type_helper.h SOURCES+=macos_context_type_helper.mm diff --git a/src/core/core_common.pri b/src/core/core_common.pri index e10d14267..ee15a06e8 100644 --- a/src/core/core_common.pri +++ b/src/core/core_common.pri @@ -7,6 +7,7 @@ QT_FOR_CONFIG += buildtools-private webenginecore webenginecore-private TARGET = QtWebEngineCore QT += qml-private quick-private gui-private core-private +qtConfig(webengine-printing-and-pdf): QT += printsupport QT_PRIVATE += webenginecoreheaders-private qtConfig(webengine-geolocation): QT += positioning diff --git a/src/core/doc/src/qwebenginesettings_lgpl.qdoc b/src/core/doc/src/qwebenginesettings_lgpl.qdoc new file mode 100644 index 000000000..a62abfbab --- /dev/null +++ b/src/core/doc/src/qwebenginesettings_lgpl.qdoc @@ -0,0 +1,301 @@ +/* + Copyright (C) 2015 The Qt Company Ltd. + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// The documentation in this file was imported from QtWebKit and is thus constrained +// by its LGPL license. Documentation written from scratch for new methods should be +// placed inline in the code as usual. + +/*! + \class QWebEngineSettings + \since 5.4 + \brief The QWebEngineSettings class provides an object to store the settings used + by QWebEnginePage. + + \inmodule QtWebEngineCore + + QWebEngineSettings allows configuration of browser properties, such as font sizes and + families, the location of a custom style sheet, and generic attributes, such as JavaScript + support. Individual attributes are set using the setAttribute() function. The + \l{QWebEngineSettings::WebAttribute}{WebAttribute} enum further describes each attribute. + + Each QWebEnginePage object has its own QWebEngineSettings object, which configures the + settings for that page. If a setting is not configured for a web engine + page, it is looked up in the settings of the profile the page belongs to. + + \sa QWebEnginePage::settings(), QWebEngineView::settings() +*/ + +/*! + \enum QWebEngineSettings::FontFamily + + This enum describes the generic font families defined by CSS 2. + For more information see the + \l{http://www.w3.org/TR/REC-CSS2/fonts.html#generic-font-families}{CSS standard}. + + \value StandardFont + \value FixedFont + \value SerifFont + \value SansSerifFont + \value CursiveFont + \value FantasyFont + \value PictographFont + (added in Qt 5.7) +*/ + +/*! + \enum QWebEngineSettings::FontSize + + This enum describes the font sizes configurable through QWebEngineSettings: + + \value MinimumFontSize The hard minimum font size. + \value MinimumLogicalFontSize The minimum logical font size that is applied + when zooming out. + \value DefaultFontSize The default font size for regular text. + \value DefaultFixedFontSize The default font size for fixed-pitch text. +*/ + +/*! + \enum QWebEngineSettings::WebAttribute + + This enum type specifies settings for web pages: + + \value AutoLoadImages + Automatically dowloads images for web pages. When this setting is + disabled, images are loaded from the cache. Enabled by default. + \value JavascriptEnabled + Enables the running of JavaScript programs in the + \l{QWebEngineScript::MainWorld}{MainWorld}. Enabled by default. + \value JavascriptCanOpenWindows + Allows JavaScript programs to open popup windows without user + interaction. Enabled by default. + \value JavascriptCanAccessClipboard + Allows JavaScript programs to read from and write to the clipboard. + Writing to the clipboard is always allowed if it is specifically requested by the user. + See JavascriptCanPaste to also allow pasting the content of the clipboard content from + JavaScript. + Disabled by default. + \value LinksIncludedInFocusChain + Includes hyperlinks in the keyboard focus chain. Enabled by default. + \value LocalStorageEnabled + Enables support for the HTML 5 local storage feature. Enabled by default. + \value LocalContentCanAccessRemoteUrls + Allows locally loaded documents to ignore cross-origin rules so that they can access + remote resources that would normally be blocked, because all remote resources are + considered cross-origin for a local file. Remote access that would not be blocked by + cross-origin rules is still possible when this setting is disabled (default). + Note that disabling this setting does not stop XMLHttpRequests or media elements in + local files from accessing remote content. Basically, it only stops some HTML + subresources, such as scripts, and therefore disabling this setting is not a safety + mechanism. + \value XSSAuditingEnabled + Obsolete and has no effect. + \value SpatialNavigationEnabled + Enables the Spatial Navigation feature, which means the ability to navigate between + focusable elements, such as hyperlinks and form controls, on a web page by using the + Left, Right, Up and Down arrow keys. For example, if a user presses the + Right key, heuristics determine whether there is an element they might be + trying to reach towards the right and which element they probably want. + Disabled by default. + \value LocalContentCanAccessFileUrls + Allows locally loaded documents to access other local URLs. Enabled by default. + \value HyperlinkAuditingEnabled + Enables support for the \c ping attribute for hyperlinks. Disabled by default. + \value ScrollAnimatorEnabled + Enables animated scrolling. Disabled by default. + \value ErrorPageEnabled + Enables displaying the built-in error pages of Chromium. Enabled by default. + \value PluginsEnabled + Enables support for Pepper plugins, such as the Flash player. Disabled by default. + See also \l{Pepper Plugin API}. (Added in Qt 5.6) + \value FullScreenSupportEnabled + Enables fullscreen support in an application. Disabled by default. (Added in Qt 5.6) + \value ScreenCaptureEnabled + Enables screen capture in an application. Disabled by default. (Added in Qt 5.7) + \value WebGLEnabled + Enables support for HTML 5 WebGL. Enabled by default if available. (Added in Qt 5.7) + \value Accelerated2dCanvasEnabled + Specifies whether the HTML5 2D canvas should be a OpenGL framebuffer. + This makes many painting operations faster, but slows down pixel access. Enabled by default if available. (Added in Qt 5.7) + \value AutoLoadIconsForPage + Automatically downloads icons for web pages. Enabled by default. (Added in Qt 5.7) + \value TouchIconsEnabled + Enables support for touch icons and precomposed touch icons + Disabled by default. (Added in Qt 5.7) + \value FocusOnNavigationEnabled + Gives focus to the view associated with the page, whenever a navigation operation occurs + (load, stop, reload, reload and bypass cache, forward, backward, set content, and so + on). + Disabled by default. (Added in Qt 5.8) + \value PrintElementBackgrounds + Turns on printing of CSS backgrounds when printing a web page. + Enabled by default. (Added in Qt 5.8) + \value AllowRunningInsecureContent + By default, HTTPS pages cannot run JavaScript, CSS, plugins or + web-sockets from HTTP URLs. This provides an override to get + the old insecure behavior. + Disabled by default. (Added in Qt 5.8) + \value AllowGeolocationOnInsecureOrigins + Since Qt 5.7, only secure origins such as HTTPS have been able to request + Geolocation features. This provides an override to allow non secure + origins to access Geolocation again. + Disabled by default. (Added in Qt 5.9) + \value AllowWindowActivationFromJavaScript + Allows activating windows by using the window.focus() JavaScript + method. Disabled by default. + (Added in Qt 5.10) + \value ShowScrollBars + Shows scroll bars. + Enabled by default. (Added in Qt 5.10) + \value PlaybackRequiresUserGesture + Inhibits playback of media content until the user interacts with + the page. By default, WebEngine uses Chromium settings, as described + in \l {Autoplay Policy Changes}. This is similar to how Chrome on + Android behaves, while the default behavior when it is disabled is + similar to Chrome on desktops. To overwrite the default behavior, + disable this setting. (Added in Qt 5.11) + \value JavascriptCanPaste + Enables JavaScript \c{execCommand("paste")}. This also requires + enabling JavascriptCanAccessClipboard. + Disabled by default. (Added in Qt 5.11) + \value WebRTCPublicInterfacesOnly + Limits WebRTC to public IP addresses only. When disabled WebRTC may also use + local network IP addresses, but remote hosts can also see your local network + IP address. + Disabled by default. (Added in Qt 5.11) + \value DnsPrefetchEnabled Specifies whether WebEngine will try to pre-fetch DNS entries to + speed up browsing. + Disabled by default. (Added in Qt 5.12) + \value PdfViewerEnabled Specifies that PDF documents will be opened in the internal PDF viewer + instead of being downloaded. + Enabled by default. (Added in Qt 5.13) +*/ + +/*! + \enum QWebEngineSettings::UnknownUrlSchemePolicy + \since Qt 5.11 + + This enum describes how navigation requests to URLs with unknown schemes are handled. + + \value DisallowUnknownUrlSchemes + Disallows all navigation requests to URLs with unknown schemes. + \value AllowUnknownUrlSchemesFromUserInteraction + Allows navigation requests to URLs with unknown schemes that are issued from + user-interaction (like a mouse-click), whereas other navigation requests (for example + from JavaScript) are suppressed. + \value AllowAllUnknownUrlSchemes + Allows all navigation requests to URLs with unknown schemes. + + \sa unknownUrlSchemePolicy setUnknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setFontSize(FontSize type, int size) + Sets the font size for \a type to \a size in pixels. +*/ + +/*! + \fn int QWebEngineSettings::fontSize(FontSize type) const + Returns the default font size for \a type in pixels. +*/ + +/*! + \fn void QWebEngineSettings::resetFontSize(FontSize type) + Resets the font size for \a type to the size specified in the profile that + the page belongs to. +*/ + +/*! + \fn void QWebEngineSettings::setDefaultTextEncoding(const QString& encoding) + Specifies the default text encoding system. + + The value of \a encoding must be a string describing an encoding such as "utf-8" or + "iso-8859-1". If left empty, a default value will be used. For a more + extensive list of encoding names see \l{QTextCodec}. + + \sa defaultTextEncoding() +*/ + +/*! + \fn QString QWebEngineSettings::defaultTextEncoding() const + Returns the default text encoding. + + \sa setDefaultTextEncoding() +*/ + +/*! + \fn void QWebEngineSettings::setFontFamily(FontFamily which, const QString& family) + Sets the actual font family to \a family for the specified generic family, + \a which. +*/ + +/*! + \fn QString QWebEngineSettings::fontFamily(FontFamily which) const + Returns the actual font family for the specified generic font family, + \a which. +*/ + +/*! + \fn void QWebEngineSettings::resetFontFamily(FontFamily which) + Resets the actual font family specified by \a which to the one specified + in the profile that the page belongs to. +*/ + +/*! + \fn QWebEngineSettings::UnknownUrlSchemePolicy QWebEngineSettings::unknownUrlSchemePolicy() const + \since Qt 5.11 + Returns the currently selected policy for handling navigation requests to URLs with + unknown schemes. Default is \l{QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction}. + \sa setUnknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy) + \since Qt 5.11 + Sets the policy for handling navigation requests to URLs with unknown schemes to \a policy. + Default is \l{QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction}. + \sa unknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::resetUnknownUrlSchemePolicy() + \since Qt 5.11 + Removes the policy for handling navigation requests to URLs with unknown schemes. + \sa unknownUrlSchemePolicy setUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setAttribute(WebAttribute attribute, bool on) + + Enables or disables the specified \a attribute feature depending on the + value of \a on. +*/ + +/*! + \fn bool QWebEngineSettings::testAttribute(WebAttribute attribute) const + + Returns \c true if \a attribute is enabled; otherwise returns \c false. +*/ + +/*! + \fn void QWebEngineSettings::resetAttribute(WebAttribute attribute) + + Resets the setting of \a attribute to the value specified in the + profile that the page belongs to. +*/ diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index f1ad1e677..b7b744603 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -68,7 +68,6 @@ DownloadManagerDelegateQt::DownloadManagerDelegateQt(ProfileAdapter *profileAdap : m_profileAdapter(profileAdapter) , m_currentId(0) , m_weakPtrFactory(this) - , m_nextDownloadIsUserRequested(false) { Q_ASSERT(m_profileAdapter); } @@ -144,17 +143,6 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem * QString suggestedFilename = toQt(item->GetSuggestedFilename()); QString mimeTypeString = toQt(item->GetMimeType()); - int downloadType = 0; - if (m_nextDownloadIsUserRequested) { - downloadType = ProfileAdapterClient::UserRequested; - m_nextDownloadIsUserRequested = false; - } else { - bool isAttachment = net::HttpContentDisposition(item->GetContentDisposition(), std::string()).is_attachment(); - if (isAttachment) - downloadType = ProfileAdapterClient::Attachment; - else - downloadType = ProfileAdapterClient::DownloadAttribute; - } if (suggestedFilename.isEmpty()) suggestedFilename = toQt(net::HttpContentDisposition(item->GetContentDisposition(), net::kCharsetLatin1).filename()); @@ -200,7 +188,7 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem * false /* accepted */, false /* paused */, false /* done */, - downloadType, + false /* isSavePageDownload */, item->GetLastReason(), adapterClient, suggestedFilename, @@ -303,7 +291,7 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content acceptedByDefault, false, /* paused */ false, /* done */ - ProfileAdapterClient::SavePage, + true, /* isSavePageDownload */ ProfileAdapterClient::NoReason, adapterClient, QFileInfo(suggestedFilePath).fileName(), diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index 7f4f33702..eda1e4f21 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -89,8 +89,6 @@ public: void resumeDownload(quint32 downloadId); void removeDownload(quint32 downloadId); - void markNextDownloadAsUserRequested() { m_nextDownloadIsUserRequested = true; } - // Inherited from content::DownloadItem::Observer void OnDownloadUpdated(download::DownloadItem *download) override; void OnDownloadDestroyed(download::DownloadItem *download) override; @@ -103,7 +101,6 @@ private: uint32_t m_currentId; base::WeakPtrFactory<DownloadManagerDelegateQt> m_weakPtrFactory; - bool m_nextDownloadIsUserRequested; friend class DownloadManagerDelegateInstance; friend class ProfileAdapter; diff --git a/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp b/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp index 89d3d6f20..16a747929 100644 --- a/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp +++ b/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp @@ -49,6 +49,8 @@ #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" #include "profile_adapter.h" +#include "qwebenginecontextmenurequest.h" +#include "qwebenginecontextmenurequest_p.h" #include "render_widget_host_view_qt.h" #include "touch_selection_controller_client_qt.h" #include "web_contents_adapter.h" @@ -59,11 +61,13 @@ namespace extensions { MimeHandlerViewGuestDelegateQt::MimeHandlerViewGuestDelegateQt(MimeHandlerViewGuest *) : MimeHandlerViewGuestDelegate() + , m_contextMenuRequest(new QWebEngineContextMenuRequest(new QWebEngineContextMenuRequestPrivate)) { } MimeHandlerViewGuestDelegateQt::~MimeHandlerViewGuestDelegateQt() { + delete m_contextMenuRequest; } bool MimeHandlerViewGuestDelegateQt::HandleContextMenu(content::WebContents *web_contents, const content::ContextMenuParams ¶ms) @@ -74,9 +78,8 @@ bool MimeHandlerViewGuestDelegateQt::HandleContextMenu(content::WebContents *web return true; QtWebEngineCore::WebContentsAdapterClient *adapterClient = rwhv->adapterClient(); - QtWebEngineCore::WebEngineContextMenuData contextMenuData(QtWebEngineCore::WebContentsViewQt::buildContextMenuData(params)); - contextMenuData.setIsSpellCheckerEnabled(adapterClient->profileAdapter()->isSpellCheckEnabled()); - adapterClient->contextMenuRequested(contextMenuData); + QtWebEngineCore::WebContentsViewQt::update(m_contextMenuRequest, params, adapterClient->profileAdapter()->isSpellCheckEnabled()); + adapterClient->contextMenuRequested(m_contextMenuRequest); return true; } diff --git a/src/core/extensions/mime_handler_view_guest_delegate_qt.h b/src/core/extensions/mime_handler_view_guest_delegate_qt.h index 8b2e29508..c9b822aa1 100644 --- a/src/core/extensions/mime_handler_view_guest_delegate_qt.h +++ b/src/core/extensions/mime_handler_view_guest_delegate_qt.h @@ -48,6 +48,10 @@ #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" #include "api/qtwebenginecoreglobal_p.h" +QT_BEGIN_NAMESPACE +class QWebEngineContextMenuRequest; +QT_END_NAMESPACE + namespace content { struct ContextMenuParams; } @@ -65,6 +69,7 @@ public: const content::ContextMenuParams ¶ms) override; private: + QWebEngineContextMenuRequest *m_contextMenuRequest; DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewGuestDelegateQt); }; diff --git a/src/core/extensions/plugin_service_filter_qt.cpp b/src/core/extensions/plugin_service_filter_qt.cpp index b29dbbeab..94cf5cb27 100644 --- a/src/core/extensions/plugin_service_filter_qt.cpp +++ b/src/core/extensions/plugin_service_filter_qt.cpp @@ -74,8 +74,8 @@ bool PluginServiceFilterQt::IsPluginAvailable(int render_process_id, if (auto *delegate = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate())) { const WebEngineSettings *settings = delegate->webEngineSettings(); - if (!settings->testAttribute(WebEngineSettings::PdfViewerEnabled) - || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) + if (!settings->testAttribute(QWebEngineSettings::PdfViewerEnabled) + || !settings->testAttribute(QWebEngineSettings::PluginsEnabled)) return false; } diff --git a/src/core/favicon_manager.cpp b/src/core/favicon_manager.cpp index 4496606f9..3cb417c4f 100644 --- a/src/core/favicon_manager.cpp +++ b/src/core/favicon_manager.cpp @@ -192,8 +192,8 @@ void FaviconManager::storeIcon(int id, const QIcon &icon) m_inProgressRequests.remove(id); if (m_inProgressRequests.isEmpty()) { - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - bool touchIconsEnabled = settings->testAttribute(WebEngineSettings::TouchIconsEnabled); + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); generateCandidateIcon(touchIconsEnabled); const QUrl &iconUrl = candidateIconUrl(touchIconsEnabled); @@ -248,13 +248,13 @@ void FaviconManager::update(const QList<FaviconInfo> &candidates) { updateCandidates(candidates); - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - if (!settings->testAttribute(WebEngineSettings::AutoLoadIconsForPage)) { + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + if (!settings->testAttribute(QWebEngineSettings::AutoLoadIconsForPage)) { m_viewClient->iconChanged(QUrl()); return; } - bool touchIconsEnabled = settings->testAttribute(WebEngineSettings::TouchIconsEnabled); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index 3d6fda80e..4688ea59d 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -7,11 +7,7 @@ TEMPLATE = aux qtConfig(debug_and_release): CONFIG += debug_and_release qtConfig(build_all): CONFIG += build_all -qtConfig(webengine-system-ninja) { - QT_TOOL.ninja.binary = ninja -} else { - QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath())) -} +QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath())) win32 { # Add the gnuwin32/bin subdir of qt5.git to PATH. Needed for calling bison and friends. diff --git a/src/core/macos_context_type_helper.h b/src/core/macos_context_type_helper.h index d234a2bff..a7b989bc3 100644 --- a/src/core/macos_context_type_helper.h +++ b/src/core/macos_context_type_helper.h @@ -39,4 +39,5 @@ #ifndef MACOS_CONTEXT_TYPE_HELPER_H_ #define MACOS_CONTEXT_TYPE_HELPER_H_ bool isCurrentContextSoftware(); +void* cglContext(NSOpenGLContext*); #endif // MACOS_CONTEXT_TYPE_HELPER_H_ diff --git a/src/core/macos_context_type_helper.mm b/src/core/macos_context_type_helper.mm index c814d2849..4c9302482 100644 --- a/src/core/macos_context_type_helper.mm +++ b/src/core/macos_context_type_helper.mm @@ -47,3 +47,8 @@ bool isCurrentContextSoftware() [NSOpenGLContext.currentContext getValues:&rendererID forParameter:NSOpenGLContextParameterCurrentRendererID]; return (rendererID & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID; } + +void* cglContext(NSOpenGLContext *nsOpenGLContext) +{ + return [nsOpenGLContext CGLContextObj]; +} diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index ef5d65745..cf31b9b59 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -395,8 +395,8 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(content::WebConten WebContentsAdapterClient *adapterClient = delegate->adapterClient(); if (flags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) { - const bool screenCaptureEnabled = - adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::ScreenCaptureEnabled); + const bool screenCaptureEnabled = adapterClient->webEngineSettings()->testAttribute( + QWebEngineSettings::ScreenCaptureEnabled); const bool originIsSecure = blink::network_utils::IsOriginSecure(request.security_origin); if (!screenCaptureEnabled || !originIsSecure) { std::move(callback).Run(blink::MediaStreamDevices(), MediaStreamRequestResult::INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); diff --git a/src/core/native_web_keyboard_event_qt.cpp b/src/core/native_web_keyboard_event_qt.cpp index b2e857aaf..edd27ccec 100644 --- a/src/core/native_web_keyboard_event_qt.cpp +++ b/src/core/native_web_keyboard_event_qt.cpp @@ -52,7 +52,11 @@ namespace { // event is destroyed. gfx::NativeEvent CopyEvent(gfx::NativeEvent event) { - return event ? reinterpret_cast<gfx::NativeEvent>(new QKeyEvent(*reinterpret_cast<QKeyEvent*>(event))) : 0; + if (!event) + return nullptr; + + QKeyEvent *keyEvent = reinterpret_cast<QKeyEvent *>(event); + return reinterpret_cast<gfx::NativeEvent>(keyEvent->clone()); } void DestroyEvent(gfx::NativeEvent event) diff --git a/src/core/net/client_cert_store_data.h b/src/core/net/client_cert_store_data.h index e47a909e4..4976ac936 100644 --- a/src/core/net/client_cert_store_data.h +++ b/src/core/net/client_cert_store_data.h @@ -46,7 +46,7 @@ #if QT_CONFIG(ssl) #include "base/memory/ref_counted.h" -#include <QtCore/qvector.h> +#include <QtCore/qlist.h> #include <QtNetwork/qsslcertificate.h> #include <QtNetwork/qsslkey.h> @@ -71,7 +71,7 @@ struct ClientCertificateStoreData void remove(const QSslCertificate &certificate); void clear(); - QVector<Entry *> extraCerts; + QList<Entry *> extraCerts; }; } // namespace QtWebEngineCore diff --git a/src/core/net/cookie_monster_delegate_qt.h b/src/core/net/cookie_monster_delegate_qt.h index fe1ed5be6..9078bcd58 100644 --- a/src/core/net/cookie_monster_delegate_qt.h +++ b/src/core/net/cookie_monster_delegate_qt.h @@ -53,11 +53,6 @@ #include "qtwebenginecoreglobal_p.h" -QT_WARNING_PUSH -// For some reason adding -Wno-unused-parameter to QMAKE_CXXFLAGS has no -// effect with clang, so use a pragma for these dirty chromium headers -QT_WARNING_DISABLE_CLANG("-Wunused-parameter") - // We need to work around Chromium using 'signals' as a variable name in headers: #ifdef signals #define StAsH_signals signals @@ -73,7 +68,6 @@ QT_WARNING_DISABLE_CLANG("-Wunused-parameter") #define signals StAsH_signals #undef StAsH_signals #endif -QT_WARNING_POP #include <QNetworkCookie> #include <QPointer> diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp index d868e4f54..bca059ae6 100644 --- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp +++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp @@ -89,8 +89,8 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL return; WebEngineSettings *settings = contentsDelegate->webEngineSettings(); - if (!settings->testAttribute(WebEngineSettings::PdfViewerEnabled) - || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) { + if (!settings->testAttribute(QWebEngineSettings::PdfViewerEnabled) + || !settings->testAttribute(QWebEngineSettings::PluginsEnabled)) { // PluginServiceFilterQt will inform the URLLoader about the disabled state of plugins // and we can expect the download to be triggered automatically. It's unnecessary to // go further and start the guest view embedding process. diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp index ec107fe70..bc70928ab 100644 --- a/src/core/net/proxying_url_loader_factory_qt.cpp +++ b/src/core/net/proxying_url_loader_factory_qt.cpp @@ -136,8 +136,10 @@ public: void PauseReadingBodyFromNet() override; void ResumeReadingBodyFromNet() override; - void InterceptOnUIThread(QWebEngineUrlRequestInterceptor *profileInterceptor); - void InterceptOnIOThread(base::WaitableEvent *event, QWebEngineUrlRequestInterceptor *profileInterceptor); + static inline void cleanup(QWebEngineUrlRequestInfo *info) { delete info; } + +private: + void InterceptOnUIThread(); void ContinueAfterIntercept(); // This is called when the original URLLoaderClient has a connection error. @@ -172,7 +174,6 @@ public: const net::MutableNetworkTrafficAnnotationTag traffic_annotation_; - static inline void cleanup(QWebEngineUrlRequestInfo *info) { delete info; } QScopedPointer<QWebEngineUrlRequestInfo, InterceptedRequest> request_info_; mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_; @@ -273,37 +274,15 @@ void InterceptedRequest::Restart() Q_ASSERT(!request_info_); request_info_.reset(new QWebEngineUrlRequestInfo(info)); - // TODO: remove for Qt6 - bool isDeprecatedProfileInterceptor = profileInterceptor == nullptr; - if (profileInterceptor && profileInterceptor->property("deprecated").toBool()) { - isDeprecatedProfileInterceptor = true; - // sync call supports depracated call of an interceptor on io thread - base::WaitableEvent event; - base::PostTask(FROM_HERE, { content::BrowserThread::IO }, - base::BindOnce(&InterceptedRequest::InterceptOnIOThread, - base::Unretained(this), &event, profileInterceptor)); - event.Wait(); - if (request_info_->changed()) { - ContinueAfterIntercept(); - return; - } - } - InterceptOnUIThread(isDeprecatedProfileInterceptor ? nullptr : profileInterceptor); + InterceptOnUIThread(); ContinueAfterIntercept(); } -void InterceptedRequest::InterceptOnIOThread(base::WaitableEvent *event, QWebEngineUrlRequestInterceptor *interceptor) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - interceptor->interceptRequest(*request_info_); - event->Signal(); -} - -void InterceptedRequest::InterceptOnUIThread(QWebEngineUrlRequestInterceptor *profileInterceptor) +void InterceptedRequest::InterceptOnUIThread() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (profileInterceptor) - profileInterceptor->interceptRequest(*request_info_); + if (auto interceptor = getProfileInterceptor()) + interceptor->interceptRequest(*request_info_); if (!request_info_->changed()) { if (auto interceptor = getPageInterceptor()) diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp index 9a24f6bf4..f4d3f1618 100644 --- a/src/core/ozone/gl_context_qt.cpp +++ b/src/core/ozone/gl_context_qt.cpp @@ -173,6 +173,24 @@ QFunctionPointer GLContextHelper::getEglGetProcAddress() return get_proc_address; } +void *GLContextHelper::getGlxPlatformInterface() +{ +#if QT_CONFIG(opengl) && defined(USE_GLX) + if (QOpenGLContext *context = qt_gl_global_share_context()) + return context->nativeInterface<QNativeInterface::QGLXContext>(); +#endif + return nullptr; +} + +void *GLContextHelper::getEglPlatformInterface() +{ +#if QT_CONFIG(opengl) && QT_CONFIG(egl) + if (QOpenGLContext *context = qt_gl_global_share_context()) + return context->nativeInterface<QNativeInterface::QEGLContext>(); +#endif + return nullptr; +} + bool GLContextHelper::isCreateContextRobustnessSupported() { return contextHelper->m_robustness; diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h index cc4f6b0d1..612aae3f5 100644 --- a/src/core/ozone/gl_context_qt.h +++ b/src/core/ozone/gl_context_qt.h @@ -65,6 +65,8 @@ public: static QFunctionPointer getGlXGetProcAddress(); static QFunctionPointer getEglGetProcAddress(); static bool isCreateContextRobustnessSupported(); + static void *getGlxPlatformInterface(); + static void *getEglPlatformInterface(); private: Q_INVOKABLE bool initializeContextOnBrowserThread(gl::GLContext* context, gl::GLSurface* surface, gl::GLContextAttribs attribs); diff --git a/src/core/ozone/gl_ozone_egl_qt.cpp b/src/core/ozone/gl_ozone_egl_qt.cpp index 04b336990..14ba5e8d9 100644 --- a/src/core/ozone/gl_ozone_egl_qt.cpp +++ b/src/core/ozone/gl_ozone_egl_qt.cpp @@ -38,11 +38,10 @@ ****************************************************************************/ #if defined(USE_OZONE) -#include <QtCore/qobject.h> -#include <QtGui/qtgui-config.h> #include "gl_context_qt.h" #include "gl_ozone_egl_qt.h" #include "gl_surface_egl_qt.h" + #include "base/files/file_path.h" #include "base/native_library.h" #include "ui/gl/gl_context_egl.h" @@ -51,7 +50,6 @@ #include "ui/gl/init/gl_factory.h" #include "ui/gl/init/gl_initializer.h" - #include <EGL/egl.h> #include <dlfcn.h> @@ -79,13 +77,11 @@ bool GLOzoneEGLQt::LoadGLES2Bindings(gl::GLImplementation /*implementation*/) reinterpret_cast<gl::GLGetProcAddressProc>( base::GetFunctionPointerFromNativeLibrary(eglgles2Library, "eglGetProcAddress")); -#if QT_CONFIG(opengl) if (!get_proc_address) { // QTBUG-63341 most likely libgles2 not linked with libegl -> fallback to qpa get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(GLContextHelper::getEglGetProcAddress()); } -#endif if (!get_proc_address) { LOG(ERROR) << "eglGetProcAddress not found."; diff --git a/src/core/ozone/gl_share_context_qt.cpp b/src/core/ozone/gl_share_context_qt.cpp new file mode 100644 index 000000000..a17321455 --- /dev/null +++ b/src/core/ozone/gl_share_context_qt.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "gl_share_context_qt.h" +#include <QtGui/qtgui-config.h> +#include <qpa/qplatformnativeinterface.h> +#include <QtGui/qopenglcontext_platform.h> +#if defined(Q_OS_MACOS) +#include "macos_context_type_helper.h" +#endif +#if QT_CONFIG(opengl) +#include <QOpenGLContext> +#include <QOpenGLExtraFunctions> +#endif + +namespace QtWebEngineCore { + +QtShareGLContext::QtShareGLContext(QOpenGLContext *qtContext) + : gl::GLContext(nullptr), m_handle(nullptr) +{ +#if QT_CONFIG(opengl) + QOpenGLContext *context = QOpenGLContext::globalShareContext(); +#if defined(Q_OS_MACOS) + auto *ctx = context->nativeInterface<QNativeInterface::QCocoaGLContext>(); + if (ctx) + m_handle = cglContext(ctx->nativeContext()); +#endif +#if defined(Q_OS_WIN) + auto *ctx = context->nativeInterface<QNativeInterface::QWGLContext>(); +#endif +#if defined(Q_OS_LINUX) + auto *ctx = context->nativeInterface<QNativeInterface::QGLXContext>(); +#endif + if (ctx && !m_handle) + m_handle = (void *)ctx->nativeContext(); +#if QT_CONFIG(egl) + if (!m_handle) { + auto *ctx = context->nativeInterface<QNativeInterface::QEGLContext>(); + if (ctx) + m_handle = (void *)ctx->nativeContext(); + } +#endif + if (!m_handle) + qFatal("Could not get handle for shared contex"); +#endif // QT_CONFIG(opengl) +} + +unsigned int QtShareGLContext::CheckStickyGraphicsResetStatusImpl() +{ +#if QT_CONFIG(opengl) + if (QOpenGLContext *context = QOpenGLContext::globalShareContext()) { + if (context->format().testOption(QSurfaceFormat::ResetNotification)) + return context->extraFunctions()->glGetGraphicsResetStatus(); + } +#endif + return 0 /*GL_NO_ERROR*/; +} + +void ShareGroupQt::AboutToAddFirstContext() +{ +#if QT_CONFIG(opengl) + // This currently has to be setup by ::main in all applications using QQuickWebEngineView with + // delegated rendering. + QOpenGLContext *shareContext = QOpenGLContext::globalShareContext(); + if (!shareContext) { + qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to " + "call QtWebEngine::initialize() in your main() function before QCoreApplication is " + "created."); + } + m_shareContextQt = new QtShareGLContext(shareContext); +#endif +} + +} // namespace diff --git a/src/core/ozone/gl_share_context_qt.h b/src/core/ozone/gl_share_context_qt.h new file mode 100644 index 000000000..b07f5123e --- /dev/null +++ b/src/core/ozone/gl_share_context_qt.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GL_SHARE_CONTEXT_QT +#define GL_SHARE_CONTEXT_QT + +#include "ui/gl/gpu_timing.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_share_group.h" +#include "qtwebenginecoreglobal.h" + +QT_FORWARD_DECLARE_CLASS(QOpenGLContext) + +namespace QtWebEngineCore { + +class QtShareGLContext : public gl::GLContext +{ + +public: + QtShareGLContext(QOpenGLContext *qtContext); + void *GetHandle() override { return m_handle; } + unsigned int CheckStickyGraphicsResetStatusImpl() override; + // We don't care about the rest, this context shouldn't be used except for its handle. + bool Initialize(gl::GLSurface *, const gl::GLContextAttribs &) override + { + Q_UNREACHABLE(); + return false; + } + bool MakeCurrentImpl(gl::GLSurface *) override + { + Q_UNREACHABLE(); + return false; + } + void ReleaseCurrent(gl::GLSurface *) override { Q_UNREACHABLE(); } + bool IsCurrent(gl::GLSurface *) override + { + Q_UNREACHABLE(); + return false; + } + scoped_refptr<gl::GPUTimingClient> CreateGPUTimingClient() override { return nullptr; } + const gfx::ExtensionSet &GetExtensions() override + { + static const gfx::ExtensionSet s_emptySet; + return s_emptySet; + } + void ResetExtensions() override {} + +private: + void *m_handle; +}; + +class ShareGroupQt : public gl::GLShareGroup +{ + +public: + gl::GLContext *GetContext() override { return m_shareContextQt.get(); } + void AboutToAddFirstContext() override; + +private: + scoped_refptr<QtShareGLContext> m_shareContextQt; +}; +} // namespace +#endif diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp index 12b997148..846d930d6 100644 --- a/src/core/ozone/surface_factory_qt.cpp +++ b/src/core/ozone/surface_factory_qt.cpp @@ -51,13 +51,13 @@ namespace QtWebEngineCore { SurfaceFactoryQt::SurfaceFactoryQt() { #if defined(USE_GLX) - if (GLContextHelper::getGlXConfig()) { - m_impl = gl::kGLImplementationDesktopGL; + if (GLContextHelper::getGlxPlatformInterface()) { + m_impl = { gl::kGLImplementationDesktopGL }; m_ozone.reset(new ui::GLOzoneGLXQt()); } else #endif - if (GLContextHelper::getEGLConfig()) { - m_impl = gl::kGLImplementationEGLGLES2; + if (GLContextHelper::getEglPlatformInterface()) { + m_impl = { gl::kGLImplementationDesktopGL, gl::kGLImplementationEGLGLES2 }; m_ozone.reset(new ui::GLOzoneEGLQt()); } else { qFatal("No suitable graphics backend found\n"); @@ -66,7 +66,7 @@ SurfaceFactoryQt::SurfaceFactoryQt() std::vector<gl::GLImplementation> SurfaceFactoryQt::GetAllowedGLImplementations() { - return { m_impl }; + return m_impl; } ui::GLOzone* SurfaceFactoryQt::GetGLOzone(gl::GLImplementation implementation) diff --git a/src/core/ozone/surface_factory_qt.h b/src/core/ozone/surface_factory_qt.h index dee41d948..232f11e0f 100644 --- a/src/core/ozone/surface_factory_qt.h +++ b/src/core/ozone/surface_factory_qt.h @@ -53,7 +53,7 @@ public: std::vector<gl::GLImplementation> GetAllowedGLImplementations() override; ui::GLOzone* GetGLOzone(gl::GLImplementation implementation) override; private: - gl::GLImplementation m_impl; + std::vector<gl::GLImplementation> m_impl; std::unique_ptr<ui::GLOzone> m_ozone; }; diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index 885a40c15..f476a5aa1 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -218,8 +218,8 @@ int PermissionManagerQt::RequestPermission(content::PermissionType permission, ProfileAdapter::PermissionType permissionType = toQt(permission); if (permissionType == ProfileAdapter::ClipboardRead) { WebEngineSettings *settings = contentsDelegate->webEngineSettings(); - if (settings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard) - && settings->testAttribute(WebEngineSettings::JavascriptCanPaste)) + if (settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard) + && settings->testAttribute(QWebEngineSettings::JavascriptCanPaste)) std::move(callback).Run(blink::mojom::PermissionStatus::GRANTED); else std::move(callback).Run(blink::mojom::PermissionStatus::DENIED); @@ -260,8 +260,8 @@ int PermissionManagerQt::RequestPermissions(const std::vector<content::Permissio result.push_back(blink::mojom::PermissionStatus::DENIED); else if (permissionType == ProfileAdapter::ClipboardRead) { WebEngineSettings *settings = contentsDelegate->webEngineSettings(); - if (settings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard) - && settings->testAttribute(WebEngineSettings::JavascriptCanPaste)) + if (settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard) + && settings->testAttribute(QWebEngineSettings::JavascriptCanPaste)) result.push_back(blink::mojom::PermissionStatus::GRANTED); else result.push_back(blink::mojom::PermissionStatus::DENIED); @@ -312,10 +312,12 @@ blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForFrame( permission == content::PermissionType::CLIPBOARD_SANITIZED_WRITE) { WebContentsDelegateQt *delegate = static_cast<WebContentsDelegateQt *>( content::WebContents::FromRenderFrameHost(render_frame_host)->GetDelegate()); - if (!delegate->webEngineSettings()->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard)) + if (!delegate->webEngineSettings()->testAttribute( + QWebEngineSettings::JavascriptCanAccessClipboard)) return blink::mojom::PermissionStatus::DENIED; - if (permission == content::PermissionType::CLIPBOARD_READ_WRITE && - !delegate->webEngineSettings()->testAttribute(WebEngineSettings::JavascriptCanPaste)) + if (permission == content::PermissionType::CLIPBOARD_READ_WRITE + && !delegate->webEngineSettings()->testAttribute( + QWebEngineSettings::JavascriptCanPaste)) return blink::mojom::PermissionStatus::DENIED; return blink::mojom::PermissionStatus::GRANTED; } diff --git a/src/core/pref_service_adapter.h b/src/core/pref_service_adapter.h index 1c7c44a96..93a61302f 100644 --- a/src/core/pref_service_adapter.h +++ b/src/core/pref_service_adapter.h @@ -44,12 +44,6 @@ #include "components/prefs/pref_service.h" #include "qtwebenginecoreglobal_p.h" -QT_BEGIN_NAMESPACE -class QStringList; -QT_END_NAMESPACE - -class ProfileAdapter; - namespace QtWebEngineCore { class ProfileAdapter; diff --git a/src/core/printing/printer_worker.cpp b/src/core/printing/printer_worker.cpp new file mode 100644 index 000000000..cbd6b8da3 --- /dev/null +++ b/src/core/printing/printer_worker.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "printer_worker.h" + +#include "printing/pdfium_document_wrapper_qt.h" + +#include <QPainter> +#include <QPrinter> + +namespace QtWebEngineCore { + +PrinterWorker::PrinterWorker(QSharedPointer<QByteArray> data, QPrinter *printer) + : m_data(data), m_printer(printer) +{ +} + +PrinterWorker::~PrinterWorker() { } + +void PrinterWorker::print() +{ + if (!m_data->size()) { + qWarning("Failure to print on printer %ls: Print result data is empty.", + qUtf16Printable(m_printer->printerName())); + Q_EMIT resultReady(false); + return; + } + + PdfiumDocumentWrapperQt pdfiumWrapper(m_data->constData(), m_data->size()); + + int toPage = m_printer->toPage(); + int fromPage = m_printer->fromPage(); + bool ascendingOrder = true; + + if (fromPage == 0 && toPage == 0) { + fromPage = 1; + toPage = pdfiumWrapper.pageCount(); + } + fromPage = qMax(1, fromPage); + toPage = qMin(pdfiumWrapper.pageCount(), toPage); + + if (m_printer->pageOrder() == QPrinter::LastPageFirst) { + qSwap(fromPage, toPage); + ascendingOrder = false; + } + + int pageCopies = 1; + int documentCopies = 1; + + if (!m_printer->supportsMultipleCopies()) + documentCopies = m_printer->copyCount(); + + if (m_printer->collateCopies()) { + pageCopies = documentCopies; + documentCopies = 1; + } + + qreal resolution = m_printer->resolution() / 72.0; // pdfium uses points so 1/72 inch + + QPainter painter; + + for (int printedDocuments = 0; printedDocuments < documentCopies; printedDocuments++) { + if (printedDocuments > 0) + m_printer->newPage(); + + int currentPageIndex = fromPage; + + for (int i = 0; true; i++) { + QSizeF documentSize = (pdfiumWrapper.pageSize(currentPageIndex - 1) * resolution); + bool isLandscape = documentSize.width() > documentSize.height(); + m_printer->setPageOrientation(isLandscape ? QPageLayout::Landscape + : QPageLayout::Portrait); + QRectF pageRect = m_printer->pageRect(QPrinter::DevicePixel); + documentSize = documentSize.scaled(pageRect.size(), Qt::KeepAspectRatio); + + // setPageOrientation has to be called before qpainter.begin() or before + // qprinter.newPage() so correct metrics is used, therefore call begin now for only + // first page + if (!painter.isActive() && !painter.begin(m_printer)) { + qWarning("Failure to print on printer %ls: Could not open printer for painting.", + qUtf16Printable(m_printer->printerName())); + Q_EMIT resultReady(false); + return; + } + + if (i > 0) + m_printer->newPage(); + + for (int printedPages = 0; printedPages < pageCopies; printedPages++) { + if (m_printer->printerState() == QPrinter::Aborted + || m_printer->printerState() == QPrinter::Error) { + Q_EMIT resultReady(false); + return; + } + + if (printedPages > 0) + m_printer->newPage(); + + QImage currentImage = pdfiumWrapper.pageAsQImage( + currentPageIndex - 1, documentSize.width(), documentSize.height()); + if (currentImage.isNull()) { + Q_EMIT resultReady(false); + return; + } + painter.drawImage(0, 0, currentImage); + } + + if (currentPageIndex == toPage) + break; + + if (ascendingOrder) + currentPageIndex++; + else + currentPageIndex--; + } + } + painter.end(); + + Q_EMIT resultReady(true); + return; +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/display_producer.h b/src/core/printing/printer_worker.h index 5de09d2d2..9d1192bd2 100644 --- a/src/core/compositor/display_producer.h +++ b/src/core/printing/printer_worker.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -37,33 +37,52 @@ ** ****************************************************************************/ -#ifndef DISPLAY_PRODUCER_H -#define DISPLAY_PRODUCER_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PRINTER_WORKER_H +#define PRINTER_WORKER_H #include "qtwebenginecoreglobal_p.h" +#include <QSharedPointer> + QT_BEGIN_NAMESPACE -class QSGNode; +class QPrinter; QT_END_NAMESPACE namespace QtWebEngineCore { -class RenderWidgetHostViewQtDelegate; -// Produces composited frames for display. -class DisplayProducer +class Q_WEBENGINECORE_PRIVATE_EXPORT PrinterWorker : public QObject { + Q_OBJECT public: - // Generate scene graph nodes for the current frame. - // - // If this is a scheduled update (that is, scheduleUpdate was called - // earlier), then updatePaintNode will generate nodes for a new frame. - // Otherwise, it will just regenerate nodes for the old frame. - virtual QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *delegate) = 0; + PrinterWorker(QSharedPointer<QByteArray> data, QPrinter *printer); + virtual ~PrinterWorker(); + +public Q_SLOTS: + void print(); -protected: - ~DisplayProducer() {} +Q_SIGNALS: + void resultReady(bool success); + +private: + Q_DISABLE_COPY(PrinterWorker) + + QSharedPointer<QByteArray> m_data; + QPrinter *m_printer; }; } // namespace QtWebEngineCore -#endif // !DISPLAY_PRODUCER_H +Q_DECLARE_METATYPE(QtWebEngineCore::PrinterWorker *) + +#endif // PRINTER_WORKER_H diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index dff98717d..de28aee6c 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -257,7 +257,7 @@ QString ProfileAdapter::dataPath() const name = QStringLiteral("OffTheRecord"); else if (m_name.isEmpty()) name = QStringLiteral("UnknownProfile"); - return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation), name); + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), name); } void ProfileAdapter::setDataPath(const QString &path) diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index efd56e50e..f59768004 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -58,7 +58,6 @@ #include <QPointer> #include <QScopedPointer> #include <QString> -#include <QVector> #include "api/qwebengineclientcertificatestore.h" #include "api/qwebenginecookiestore.h" @@ -247,7 +246,7 @@ private: QHash<QByteArray, QSharedPointer<UserNotificationController>> m_persistentNotifications; QList<ProfileAdapterClient*> m_clients; - QVector<WebContentsAdapterClient *> m_webContentsAdapterClients; + QList<WebContentsAdapterClient *> m_webContentsAdapterClients; int m_httpCacheMaxSize; QrcUrlSchemeHandler m_qrcHandler; diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h index 394f92270..07c00044b 100644 --- a/src/core/profile_adapter_client.h +++ b/src/core/profile_adapter_client.h @@ -85,13 +85,6 @@ public: MimeHtmlSaveFormat }; - enum DownloadType { - Attachment = 0, - DownloadAttribute, - UserRequested, - SavePage - }; - // Keep in sync with content::DownloadInterruptReason enum DownloadInterruptReason { NoReason = 0, @@ -136,7 +129,7 @@ public: bool accepted; bool paused; bool done; - int downloadType; + bool isSavePageDownload; int downloadInterruptReason; WebContentsAdapterClient *page; QString suggestedFileName; diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h index 59f5a8c21..11b567b97 100644 --- a/src/core/profile_qt.h +++ b/src/core/profile_qt.h @@ -48,9 +48,6 @@ #include "profile_io_data_qt.h" #include <QtGlobal> -QT_BEGIN_NAMESPACE -class QStringList; -QT_END_NAMESPACE class InMemoryPrefStore; class PrefService; diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni index a35218775..b14fc1049 100644 --- a/src/core/qtwebengine_sources.gni +++ b/src/core/qtwebengine_sources.gni @@ -39,8 +39,19 @@ source_set("qtwebengine_spellcheck_sources") { } } +config("cpp17_config") { + # static initialized constexpr expressions must be compiled always as c++14 or always as c++17 + # and our qtwebengine core sources use them as c++17 + if (is_win) { + cflags_cc = [ "/std:c++17" ] + } else { + cflags_cc = [ "-std=c++17" ] + } +} + source_set("qtwebengine_sources") { configs += [ + ":cpp17_config", "//skia:skia_config", "//third_party/boringssl:external_config", ] diff --git a/src/core/render_view_context_menu_qt.cpp b/src/core/render_view_context_menu_qt.cpp index 8fdae498c..47c8a6e32 100644 --- a/src/core/render_view_context_menu_qt.cpp +++ b/src/core/render_view_context_menu_qt.cpp @@ -39,6 +39,7 @@ #include <QtCore/QCoreApplication> #include "render_view_context_menu_qt.h" +#include "qwebenginecontextmenurequest.h" namespace QtWebEngineCore { @@ -74,8 +75,8 @@ namespace QtWebEngineCore { return QCoreApplication::translate("RenderViewContextMenuQt", qUtf8Printable(names[menuItem])); } - RenderViewContextMenuQt::RenderViewContextMenuQt(const WebEngineContextMenuData &data) - : m_contextData(data) + RenderViewContextMenuQt::RenderViewContextMenuQt(QWebEngineContextMenuRequest *request) + : m_contextData(request) { } @@ -86,15 +87,17 @@ namespace QtWebEngineCore { appendSeparatorItem(); } - if (m_contextData.isEditable() && !m_contextData.spellCheckerSuggestions().isEmpty()) { + if (m_contextData->isContentEditable() + && !m_contextData->spellCheckerSuggestions().isEmpty()) { appendSpellingSuggestionItems(); appendSeparatorItem(); } - if (m_contextData.linkText().isEmpty() && !m_contextData.linkUrl().isValid() && !m_contextData.mediaUrl().isValid()) { - if (m_contextData.isEditable()) + if (m_contextData->linkText().isEmpty() && !m_contextData->filteredLinkUrl().isValid() + && !m_contextData->mediaUrl().isValid()) { + if (m_contextData->isContentEditable()) appendEditableItems(); - else if (!m_contextData.selectedText().isEmpty()) + else if (!m_contextData->selectedText().isEmpty()) appendCopyItem(); else appendPageItems(); @@ -102,27 +105,29 @@ namespace QtWebEngineCore { appendPageItems(); } - if (m_contextData.linkUrl().isValid() || !m_contextData.unfilteredLinkUrl().isEmpty() || !m_contextData.linkUrl().isEmpty()) + if (m_contextData->filteredLinkUrl().isValid() + || !m_contextData->linkUrl().isEmpty() + || !m_contextData->filteredLinkUrl().isEmpty()) appendLinkItems(); - if (m_contextData.mediaUrl().isValid()) { - switch (m_contextData.mediaType()) { - case WebEngineContextMenuData::MediaTypeImage: + if (m_contextData->mediaUrl().isValid()) { + switch (m_contextData->mediaType()) { + case QWebEngineContextMenuRequest::MediaTypeImage: appendSeparatorItem(); appendImageItems(); break; - case WebEngineContextMenuData::MediaTypeCanvas: + case QWebEngineContextMenuRequest::MediaTypeCanvas: Q_UNREACHABLE(); // mediaUrl is invalid for canvases break; - case WebEngineContextMenuData::MediaTypeAudio: - case WebEngineContextMenuData::MediaTypeVideo: + case QWebEngineContextMenuRequest::MediaTypeAudio: + case QWebEngineContextMenuRequest::MediaTypeVideo: appendSeparatorItem(); appendMediaItems(); break; default: break; } - } else if (m_contextData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) { + } else if (m_contextData->mediaType() == QWebEngineContextMenuRequest::MediaTypeCanvas) { appendSeparatorItem(); appendCanvasItems(); } @@ -160,7 +165,7 @@ namespace QtWebEngineCore { addMenuItem(RenderViewContextMenuQt::Cut); addMenuItem(RenderViewContextMenuQt::Copy); addMenuItem(RenderViewContextMenuQt::Paste); - if (m_contextData.misspelledWord().isEmpty()) { + if (m_contextData->misspelledWord().isEmpty()) { addMenuItem(RenderViewContextMenuQt::PasteAndMatchStyle); addMenuItem(RenderViewContextMenuQt::SelectAll); } @@ -190,7 +195,7 @@ namespace QtWebEngineCore { void RenderViewContextMenuQt::appendMediaItems() { addMenuItem(RenderViewContextMenuQt::ToggleMediaLoop); - if (m_contextData.mediaFlags() & QtWebEngineCore::WebEngineContextMenuData::MediaCanToggleControls) + if (m_contextData->mediaFlags() & QWebEngineContextMenuRequest::MediaCanToggleControls) addMenuItem(RenderViewContextMenuQt::ToggleMediaControls); addMenuItem(RenderViewContextMenuQt::DownloadMediaToDisk); addMenuItem(RenderViewContextMenuQt::CopyMediaUrlToClipboard); @@ -217,10 +222,8 @@ namespace QtWebEngineCore { bool RenderViewContextMenuQt::canViewSource() { - return m_contextData.linkText().isEmpty() - && !m_contextData.linkUrl().isValid() - && !m_contextData.mediaUrl().isValid() - && !m_contextData.isEditable() - && m_contextData.selectedText().isEmpty(); + return m_contextData->linkText().isEmpty() && !m_contextData->filteredLinkUrl().isValid() + && !m_contextData->mediaUrl().isValid() && !m_contextData->isContentEditable() + && m_contextData->selectedText().isEmpty(); } } diff --git a/src/core/render_view_context_menu_qt.h b/src/core/render_view_context_menu_qt.h index e1ee301fc..f818ce200 100644 --- a/src/core/render_view_context_menu_qt.h +++ b/src/core/render_view_context_menu_qt.h @@ -53,6 +53,8 @@ #include "web_contents_adapter_client.h" +QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest) + namespace QtWebEngineCore { class Q_WEBENGINECORE_PRIVATE_EXPORT RenderViewContextMenuQt @@ -99,7 +101,7 @@ public: static const QString getMenuItemName(RenderViewContextMenuQt::ContextMenuItem menuItem); - RenderViewContextMenuQt(const WebEngineContextMenuData &data); + RenderViewContextMenuQt(QWebEngineContextMenuRequest *data); void initMenu(); protected: @@ -109,7 +111,7 @@ protected: virtual void addMenuItem(ContextMenuItem menuItem) = 0; virtual bool isMenuItemEnabled(ContextMenuItem menuItem) = 0; - const WebEngineContextMenuData &m_contextData; + QWebEngineContextMenuRequest *m_contextData; private: void appendCanvasItems(); diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index e98c69c66..14622142c 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -44,9 +44,8 @@ #include "common/qt_messages.h" #include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt_delegate.h" -#include "touch_handle_drawable_client.h" +#include "render_widget_host_view_qt_delegate_client.h" #include "touch_selection_controller_client_qt.h" -#include "touch_selection_menu_controller.h" #include "type_conversion.h" #include "web_contents_adapter.h" #include "web_contents_adapter_client.h" @@ -58,7 +57,6 @@ #include "components/viz/common/surfaces/frame_sink_id_allocator.h" #include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/compositor/image_transport_factory.h" -#include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/display_util.h" #include "content/browser/renderer_host/frame_tree.h" #include "content/browser/renderer_host/frame_tree_node.h" @@ -79,9 +77,7 @@ #include "ui/events/event.h" #include "ui/events/gesture_detection/gesture_configuration.h" #include "ui/events/gesture_detection/gesture_provider_config_helper.h" -#include "ui/events/gesture_detection/motion_event.h" #include "ui/gfx/image/image_skia.h" -#include "ui/touch_selection/touch_selection_controller.h" #if defined(USE_OZONE) #include "ui/base/clipboard/scoped_clipboard_writer.h" @@ -96,24 +92,11 @@ #include "content/app/resources/grit/content_resources.h" #endif -#include <private/qguiapplication_p.h> -#include <qpa/qplatforminputcontext.h> -#include <qpa/qplatformintegration.h> -#include <QEvent> -#include <QFocusEvent> #include <QGuiApplication> -#include <QInputMethodEvent> -#include <QTextFormat> -#include <QKeyEvent> -#include <QMouseEvent> #include <QPixmap> #include <QScopeGuard> #include <QScreen> -#include <QStyleHints> -#include <QVariant> -#include <QWheelEvent> #include <QWindow> -#include <QtGui/private/qinputcontrol_p.h> namespace QtWebEngineCore { @@ -136,50 +119,6 @@ static inline ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& even return latency_info; } -static inline Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType) -{ - switch (inputType) { - case ui::TEXT_INPUT_TYPE_TEXT: - return Qt::ImhPreferLowercase; - case ui::TEXT_INPUT_TYPE_SEARCH: - return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; - case ui::TEXT_INPUT_TYPE_PASSWORD: - return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText; - case ui::TEXT_INPUT_TYPE_EMAIL: - return Qt::ImhEmailCharactersOnly; - case ui::TEXT_INPUT_TYPE_NUMBER: - return Qt::ImhFormattedNumbersOnly; - case ui::TEXT_INPUT_TYPE_TELEPHONE: - return Qt::ImhDialableCharactersOnly; - case ui::TEXT_INPUT_TYPE_URL: - return Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase; - case ui::TEXT_INPUT_TYPE_DATE_TIME: - case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: - case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: - return Qt::ImhDate | Qt::ImhTime; - case ui::TEXT_INPUT_TYPE_DATE: - case ui::TEXT_INPUT_TYPE_MONTH: - case ui::TEXT_INPUT_TYPE_WEEK: - return Qt::ImhDate; - case ui::TEXT_INPUT_TYPE_TIME: - return Qt::ImhTime; - case ui::TEXT_INPUT_TYPE_TEXT_AREA: - case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: - return Qt::ImhMultiLine | Qt::ImhPreferLowercase; - default: - return Qt::ImhNone; - } -} - -static inline int firstAvailableId(const QMap<int, int> &map) -{ - ui::BitSet32 usedIds; - QMap<int, int>::const_iterator end = map.end(); - for (QMap<int, int>::const_iterator it = map.begin(); it != end; ++it) - usedIds.mark_bit(it.value()); - return usedIds.first_unmarked_bit(); -} - static inline ui::GestureProvider::Config QtGestureProviderConfig() { ui::GestureProvider::Config config = ui::GetGestureProviderConfig(ui::GestureProviderConfigType::CURRENT_PLATFORM); // Causes an assert in CreateWebGestureEventFromGestureEventData and we don't need them in Qt. @@ -189,83 +128,6 @@ static inline ui::GestureProvider::Config QtGestureProviderConfig() { return config; } -static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) -{ - return QInputControl::isCommonTextEditShortcut(ke); -} - -static uint32_t s_eventId = 0; -class MotionEventQt : public ui::MotionEvent { -public: - MotionEventQt(const QList<QPair<int, QTouchEvent::TouchPoint>> &points, const base::TimeTicks &eventTime, - Action action, const Qt::KeyboardModifiers modifiers, int index = -1) - : touchPoints(points) - , eventTime(eventTime) - , action(action) - , eventId(++s_eventId) - , flags(flagsFromModifiers(modifiers)) - , index(index) - { - // index is only valid for ACTION_DOWN and ACTION_UP and should correspond to the point causing it - // see blink_event_util.cc:ToWebTouchPointState for details - Q_ASSERT_X((action != Action::POINTER_DOWN && action != Action::POINTER_UP && index == -1) - || (action == Action::POINTER_DOWN && index >= 0 && touchPoint(index).state() == Qt::TouchPointPressed) - || (action == Action::POINTER_UP && index >= 0 && touchPoint(index).state() == Qt::TouchPointReleased), - "MotionEventQt", qPrintable(QString("action: %1, index: %2, state: %3").arg(int(action)).arg(index).arg(touchPoint(index).state()))); - } - - uint32_t GetUniqueEventId() const override { return eventId; } - Action GetAction() const override { return action; } - int GetActionIndex() const override { return index; } - size_t GetPointerCount() const override { return touchPoints.size(); } - int GetPointerId(size_t pointer_index) const override { return touchPoints[pointer_index].first; } - float GetX(size_t pointer_index) const override { return touchPoint(pointer_index).pos().x(); } - float GetY(size_t pointer_index) const override { return touchPoint(pointer_index).pos().y(); } - float GetRawX(size_t pointer_index) const override { return touchPoint(pointer_index).screenPos().x(); } - float GetRawY(size_t pointer_index) const override { return touchPoint(pointer_index).screenPos().y(); } - float GetTouchMajor(size_t pointer_index) const override - { - QSizeF diams = touchPoint(pointer_index).ellipseDiameters(); - return std::max(diams.height(), diams.width()); - } - float GetTouchMinor(size_t pointer_index) const override - { - QSizeF diams = touchPoint(pointer_index).ellipseDiameters(); - return std::min(diams.height(), diams.width()); - } - float GetOrientation(size_t pointer_index) const override - { - return 0; - } - int GetFlags() const override { return flags; } - float GetPressure(size_t pointer_index) const override { return touchPoint(pointer_index).pressure(); } - float GetTiltX(size_t pointer_index) const override { return 0; } - float GetTiltY(size_t pointer_index) const override { return 0; } - float GetTwist(size_t) const override { return 0; } - float GetTangentialPressure(size_t) const override { return 0; } - base::TimeTicks GetEventTime() const override { return eventTime; } - - size_t GetHistorySize() const override { return 0; } - base::TimeTicks GetHistoricalEventTime(size_t historical_index) const override { return base::TimeTicks(); } - 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 { - bool isPen = touchPoint(pointer_index).flags() & QTouchEvent::TouchPoint::InfoFlag::Pen; - return isPen ? ui::MotionEvent::ToolType::STYLUS : ui::MotionEvent::ToolType::FINGER; - } - int GetButtonState() const override { return 0; } - -private: - QList<QPair<int, QTouchEvent::TouchPoint>> touchPoints; - base::TimeTicks eventTime; - Action action; - const uint32_t eventId; - int flags; - int index; - const QTouchEvent::TouchPoint& touchPoint(size_t i) const { return touchPoints[i].second; } -}; - extern display::Display toDisplayDisplay(int id, const QScreen *screen); static blink::ScreenInfo screenInfoFromQScreen(QScreen *screen) @@ -333,30 +195,13 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget : content::RenderWidgetHostViewBase::RenderWidgetHostViewBase(widget) , m_taskRunner(base::ThreadTaskRunnerHandle::Get()) , m_gestureProvider(QtGestureProviderConfig(), this) - , m_sendMotionActionDown(false) - , m_touchMotionStarted(false) , m_guestInputEventObserver(new GuestInputEventObserverQt(this)) - , m_visible(false) - , m_loadVisuallyCommittedState(NotCommitted) - , m_adapterClient(0) - , m_imeInProgress(false) - , m_receivedEmptyImeEvent(false) - , m_isMouseLocked(false) - , m_imState(0) - , m_anchorPositionWithinSelection(-1) - , m_cursorPositionWithinSelection(-1) - , m_cursorPosition(0) - , m_emptyPreviousSelection(true) - , m_wheelAckPending(false) - , m_mouseWheelPhaseHandler(this) , m_frameSinkId(host()->GetFrameSinkId()) + , m_delegateClient(new RenderWidgetHostViewQtDelegateClient(this)) { if (GetTextInputManager()) GetTextInputManager()->AddObserver(this); - const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); - m_imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); - m_rootLayer.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); m_rootLayer->SetColor(SK_ColorTRANSPARENT); @@ -376,9 +221,6 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget m_uiCompositor->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); // null means offscreen m_uiCompositor->SetRootLayer(m_rootLayer.get()); - m_displayFrameSink = DisplayFrameSink::findOrCreate(m_uiCompositor->frame_sink_id()); - m_displayFrameSink->connect(this); - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(GetFrameSinkId(), this); @@ -403,8 +245,6 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt() QObject::disconnect(m_adapterClientDestroyedConnection); - m_displayFrameSink->disconnect(this); - if (text_input_manager_) text_input_manager_->RemoveObserver(this); @@ -422,7 +262,7 @@ void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegat m_deferredShow = false; Show(); } - visualPropertiesChanged(); + delegateClient()->visualPropertiesChanged(); } void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterClient) @@ -464,7 +304,7 @@ void RenderWidgetHostViewQt::SetSize(const gfx::Size &sizeInDips) void RenderWidgetHostViewQt::SetBounds(const gfx::Rect &windowRectInDips) { - DCHECK(IsPopup()); + DCHECK(isPopup()); m_delegate->move(toQt(windowRectInDips.origin())); m_delegate->resize(windowRectInDips.width(), windowRectInDips.height()); } @@ -501,7 +341,7 @@ content::BrowserAccessibilityManager* RenderWidgetHostViewQt::CreateBrowserAcces // Set focus to the associated View component. void RenderWidgetHostViewQt::Focus() { - if (!IsPopup()) + if (!isPopup()) m_delegate->setKeyboardFocus(); host()->Focus(); } @@ -556,7 +396,7 @@ bool RenderWidgetHostViewQt::IsShowing() // Retrieve the bounds of the View, in screen coordinates. gfx::Rect RenderWidgetHostViewQt::GetViewBounds() { - return m_viewRectInDips; + return toGfx(delegateClient()->viewRectInDips()); } void RenderWidgetHostViewQt::UpdateBackgroundColor() @@ -582,7 +422,7 @@ blink::mojom::PointerLockResult RenderWidgetHostViewQt::LockMouse(bool request_u if (request_unadjusted_movement) return blink::mojom::PointerLockResult::kUnsupportedOptions; - m_previousMousePosition = QCursor::pos(); + delegateClient()->resetPreviousMousePosition(); m_delegate->lockMouse(); m_isMouseLocked = true; qApp->setOverrideCursor(Qt::BlankCursor); @@ -849,7 +689,7 @@ void RenderWidgetHostViewQt::GetScreenInfo(blink::ScreenInfo *results) gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow() { - return m_windowRectInDips; + return toGfx(delegateClient()->windowRectInDips()); } void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view, bool did_update_state) @@ -871,16 +711,18 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana #else m_delegate->setInputMethodHints(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText); #endif - m_surroundingText = toQt(state->value); + QString surroundingText = toQt(state->value); // Remove IME composition text from the surrounding text if (state->composition.has_value()) - m_surroundingText.remove(state->composition->start(), state->composition->end() - state->composition->start()); + surroundingText.remove(state->composition->start(), + state->composition->end() - state->composition->start()); + delegateClient()->setSurroundingText(surroundingText); // In case of text selection, the update is expected in RenderWidgetHostViewQt::selectionChanged(). if (GetSelectedText().empty()) { // At this point it is unknown whether the text input state has been updated due to a text selection. // Keep the cursor position updated for cursor movements too. - m_cursorPosition = state->selection.start(); + delegateClient()->setCursorPosition(state->selection.start()); m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE, type == ui::TEXT_INPUT_TYPE_PASSWORD); } @@ -890,14 +732,14 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana } // Ignore selection change triggered by ime composition unless it clears an actual text selection - if (state->composition.has_value() && m_emptyPreviousSelection) { + if (state->composition.has_value() && delegateClient()->isPreviousSelectionEmpty()) { m_imState = 0; return; } m_imState |= ImStateFlags::TextInputStateUpdated; if (m_imState == ImStateFlags::AllFlags) - selectionChanged(); + delegateClient()->selectionChanged(); } void RenderWidgetHostViewQt::OnSelectionBoundsChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) @@ -908,7 +750,7 @@ void RenderWidgetHostViewQt::OnSelectionBoundsChanged(content::TextInputManager m_imState |= ImStateFlags::TextSelectionBoundsUpdated; if (m_imState == ImStateFlags::AllFlags || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { - selectionChanged(); + delegateClient()->selectionChanged(); } } @@ -932,82 +774,10 @@ void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *t m_imState |= ImStateFlags::TextSelectionUpdated; if (m_imState == ImStateFlags::AllFlags || (m_imState == ImStateFlags::TextSelectionFlags && getTextInputType() == ui::TEXT_INPUT_TYPE_NONE)) { - selectionChanged(); + delegateClient()->selectionChanged(); } } -void RenderWidgetHostViewQt::selectionChanged() -{ - // Reset input manager state - m_imState = 0; - ui::TextInputType type = getTextInputType(); - - // Handle text selection out of an input field - if (type == ui::TEXT_INPUT_TYPE_NONE) { - if (GetSelectedText().empty() && m_emptyPreviousSelection) - return; - - // Reset position values to emit selectionChanged signal when clearing text selection - // by clicking into an input field. These values are intended to be used by inputMethodQuery - // so they are not expected to be valid when selection is out of an input field. - m_anchorPositionWithinSelection = -1; - m_cursorPositionWithinSelection = -1; - - m_emptyPreviousSelection = GetSelectedText().empty(); - m_adapterClient->selectionChanged(); - return; - } - - if (GetSelectedText().empty()) { - // RenderWidgetHostViewQt::OnUpdateTextInputStateCalled() does not update the cursor position - // if the selection is cleared because TextInputState changes before the TextSelection change. - Q_ASSERT(text_input_manager_->GetTextInputState()); - m_cursorPosition = text_input_manager_->GetTextInputState()->selection.start(); - m_delegate->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); - - m_anchorPositionWithinSelection = m_cursorPosition; - m_cursorPositionWithinSelection = m_cursorPosition; - - if (!m_emptyPreviousSelection) { - m_emptyPreviousSelection = true; - m_adapterClient->selectionChanged(); - } - - return; - } - - const content::TextInputManager::TextSelection *selection = text_input_manager_->GetTextSelection(); - if (!selection) - return; - - if (!selection->range().IsValid()) - return; - - int newAnchorPositionWithinSelection = 0; - int newCursorPositionWithinSelection = 0; - - if (text_input_manager_->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { - newAnchorPositionWithinSelection = selection->range().GetMax() - selection->offset(); - newCursorPositionWithinSelection = selection->range().GetMin() - selection->offset(); - } else { - newAnchorPositionWithinSelection = selection->range().GetMin() - selection->offset(); - newCursorPositionWithinSelection = selection->range().GetMax() - selection->offset(); - } - - if (m_anchorPositionWithinSelection == newAnchorPositionWithinSelection && m_cursorPositionWithinSelection == newCursorPositionWithinSelection) - return; - - m_anchorPositionWithinSelection = newAnchorPositionWithinSelection; - m_cursorPositionWithinSelection = newCursorPositionWithinSelection; - - if (!selection->selected_text().empty()) - m_cursorPosition = newCursorPositionWithinSelection; - - m_emptyPreviousSelection = selection->selected_text().empty(); - m_delegate->inputMethodStateChanged(true /*editorVisible*/, type == ui::TEXT_INPUT_TYPE_PASSWORD); - m_adapterClient->selectionChanged(); -} - void RenderWidgetHostViewQt::OnGestureEvent(const ui::GestureEventData& gesture) { if ((gesture.type() == ui::ET_GESTURE_PINCH_BEGIN @@ -1062,36 +832,12 @@ void RenderWidgetHostViewQt::OnDidUpdateVisualPropertiesComplete(const cc::Rende void RenderWidgetHostViewQt::OnDidFirstVisuallyNonEmptyPaint() { - if (m_loadVisuallyCommittedState == NotCommitted) { - m_loadVisuallyCommittedState = DidFirstVisuallyNonEmptyPaint; - } else if (m_loadVisuallyCommittedState == DidFirstCompositorFrameSwap) { - m_adapterClient->loadVisuallyCommitted(); - m_loadVisuallyCommittedState = NotCommitted; - } -} - -void RenderWidgetHostViewQt::scheduleUpdate() -{ - m_taskRunner->PostTask( - FROM_HERE, - base::BindOnce(&RenderWidgetHostViewQt::callUpdate, m_weakPtrFactory.GetWeakPtr())); -} - -void RenderWidgetHostViewQt::callUpdate() -{ - m_delegate->update(); - - if (m_loadVisuallyCommittedState == NotCommitted) { - m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; - } else if (m_loadVisuallyCommittedState == DidFirstVisuallyNonEmptyPaint) { - m_adapterClient->loadVisuallyCommitted(); - m_loadVisuallyCommittedState = NotCommitted; - } + m_adapterClient->didFirstVisuallyNonEmptyPaint(); } -QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) +Compositor::Id RenderWidgetHostViewQt::compositorId() { - return m_displayFrameSink->updatePaintNode(oldNode, m_delegate.get()); + return m_uiCompositor->frame_sink_id(); } void RenderWidgetHostViewQt::notifyShown() @@ -1107,7 +853,7 @@ void RenderWidgetHostViewQt::notifyShown() m_delegatedFrameHost->AttachToCompositor(m_uiCompositor.get()); m_delegatedFrameHost->WasShown(GetLocalSurfaceId(), - m_viewRectInDips.size(), + toGfx(delegateClient()->viewRectInDips().size()), nullptr); } @@ -1121,208 +867,7 @@ void RenderWidgetHostViewQt::notifyHidden() m_delegatedFrameHost->DetachFromCompositor(); } -void RenderWidgetHostViewQt::visualPropertiesChanged() -{ - if (!m_delegate) - return; - - gfx::Rect oldViewRect = m_viewRectInDips; - m_viewRectInDips = toGfx(m_delegate->viewGeometry().toAlignedRect()); - - gfx::Rect oldWindowRect = m_windowRectInDips; - m_windowRectInDips = toGfx(m_delegate->windowGeometry()); - - QWindow *window = m_delegate->window(); - blink::ScreenInfo oldScreenInfo = m_screenInfo; - m_screenInfo = screenInfoFromQScreen(window ? window->screen() : nullptr); - - if (m_viewRectInDips != oldViewRect || m_windowRectInDips != oldWindowRect) - host()->SendScreenRects(); - - if (m_viewRectInDips.size() != oldViewRect.size() || m_screenInfo != oldScreenInfo) - synchronizeVisualProperties(base::nullopt); -} - -bool RenderWidgetHostViewQt::forwardEvent(QEvent *event) -{ - Q_ASSERT(host()->GetView()); - - switch (event->type()) { - case QEvent::ShortcutOverride: { - QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); - - auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { -#ifdef Q_OS_MACOS - // Check if a shortcut is registered for this key sequence. - QKeySequence sequence = QKeySequence ( - (keyEvent->modifiers() | keyEvent->key()) & - ~(Qt::KeypadModifier | Qt::GroupSwitchModifier)); - if (QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence)) - return false; - - // The following shortcuts are handled out of input field too but - // disabled on macOS to let the blinking menu handling to the - // embedder application (see kKeyboardCodeKeyDownEntries in - // third_party/WebKit/Source/core/editing/EditingBehavior.cpp). - // Let them pass on macOS to generate the corresponding edit command. - return keyEvent->matches(QKeySequence::Copy) - || keyEvent->matches(QKeySequence::Paste) - || keyEvent->matches(QKeySequence::Cut) - || keyEvent->matches(QKeySequence::SelectAll); -#else - return false; -#endif - }; - - if (!inputMethodQuery(Qt::ImEnabled).toBool() && !(inputMethodQuery(Qt::ImHints).toInt() & Qt::ImhHiddenText) && !acceptKeyOutOfInputField(keyEvent)) - return false; - - Q_ASSERT(m_editCommand.empty()); - if (WebEventFactory::getEditCommand(keyEvent, &m_editCommand) - || isCommonTextEditShortcut(keyEvent)) { - event->accept(); - return true; - } - - return false; - } - case QEvent::MouseButtonPress: - Focus(); - Q_FALLTHROUGH(); - case QEvent::MouseButtonRelease: - case QEvent::MouseMove: - // Skip second MouseMove event when a window is being adopted, so that Chromium - // can properly handle further move events. - // Also make sure the adapter client exists to prevent a null pointer dereference, - // because it's possible for a QWebEnginePagePrivate (adapter) instance to be destroyed, - // and then the OS (observed on Windows) might still send mouse move events to a still - // existing popup RWHVQDW instance. - if (m_adapterClient && m_adapterClient->isBeingAdopted()) - return false; - handleMouseEvent(static_cast<QMouseEvent*>(event)); - break; - case QEvent::KeyPress: - case QEvent::KeyRelease: - handleKeyEvent(static_cast<QKeyEvent*>(event)); - break; - case QEvent::Wheel: - handleWheelEvent(static_cast<QWheelEvent*>(event)); - break; - case QEvent::TouchBegin: - Focus(); - Q_FALLTHROUGH(); - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::TouchCancel: - handleTouchEvent(static_cast<QTouchEvent*>(event)); - break; -#if QT_CONFIG(tabletevent) - case QEvent::TabletPress: - Focus(); - Q_FALLTHROUGH(); - case QEvent::TabletRelease: - case QEvent::TabletMove: - handleTabletEvent(static_cast<QTabletEvent*>(event)); - break; -#endif -#ifndef QT_NO_GESTURES - case QEvent::NativeGesture: - handleGestureEvent(static_cast<QNativeGestureEvent *>(event)); - break; -#endif // QT_NO_GESTURES - case QEvent::HoverMove: - handleHoverEvent(static_cast<QHoverEvent*>(event)); - break; - case QEvent::FocusIn: - case QEvent::FocusOut: - handleFocusEvent(static_cast<QFocusEvent*>(event)); - break; - case QEvent::InputMethod: - handleInputMethodEvent(static_cast<QInputMethodEvent*>(event)); - break; - case QEvent::InputMethodQuery: - handleInputMethodQueryEvent(static_cast<QInputMethodQueryEvent*>(event)); - break; - case QEvent::Leave: -#ifdef Q_OS_WIN - if (m_mouseButtonPressed > 0) - return false; -#endif - case QEvent::HoverLeave: { - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) { - auto webEvent = WebEventFactory::toWebMouseEvent(event); - host()->delegate()->GetInputEventRouter()->RouteMouseEvent(this, &webEvent, ui::LatencyInfo()); - } - } - break; - default: - return false; - } - return true; -} - -QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) -{ - switch (query) { - case Qt::ImEnabled: { - ui::TextInputType type = getTextInputType(); - bool editorVisible = type != ui::TEXT_INPUT_TYPE_NONE; - // IME manager should disable composition on input fields with ImhHiddenText hint if supported - if (m_imeHasHiddenTextCapability) - return QVariant(editorVisible); - - bool passwordInput = type == ui::TEXT_INPUT_TYPE_PASSWORD; - return QVariant(editorVisible && !passwordInput); - } - case Qt::ImFont: - // TODO: Implement this - return QVariant(); - case Qt::ImCursorRectangle: { - if (text_input_manager_) { - if (auto *region = text_input_manager_->GetSelectionRegion()) { - if (region->focus.GetHeight() > 0) { - gfx::Rect caretRect = gfx::RectBetweenSelectionBounds(region->anchor, region->focus); - if (caretRect.width() == 0) - caretRect.set_width(1); // IME API on Windows expects a width > 0 - return toQt(caretRect); - } - } - } - return QVariant(); - } - case Qt::ImCursorPosition: - return m_cursorPosition; - case Qt::ImAnchorPosition: - return GetSelectedText().empty() ? m_cursorPosition : m_anchorPositionWithinSelection; - case Qt::ImSurroundingText: - return m_surroundingText; - case Qt::ImCurrentSelection: - return toQt(GetSelectedText()); - case Qt::ImMaximumTextLength: - // TODO: Implement this - return QVariant(); // No limit. - case Qt::ImHints: -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) - return int(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); -#else - return int(toQtInputMethodHints(getTextInputType()) | Qt::ImhNoPredictiveText); -#endif - default: - return QVariant(); - } -} - -void RenderWidgetHostViewQt::closePopup() -{ - // We notify the popup to be closed by telling it that it lost focus. WebKit does the rest - // (hiding the widget and automatic memory cleanup via - // RenderWidget::CloseWidgetSoon() -> RenderWidgetHostImpl::ShutdownAndDestroyWidget(true). - host()->SetActive(false); - host()->LostFocus(); -} - -void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, blink::mojom::InputEventResultState ack_result) -{ +void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, blink::mojom::InputEventResultState ack_result) { Q_UNUSED(touch); const bool eventConsumed = ack_result == blink::mojom::InputEventResultState::kConsumed; const bool isSetNonBlocking = content::InputEventResultStateIsSetNonBlocking(ack_result); @@ -1341,284 +886,37 @@ void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEve host()->delegate()->GetInputEventRouter()->RouteTouchEvent(this, &touchEvent, CreateLatencyInfo(touchEvent)); } -QList<RenderWidgetHostViewQt::TouchPoint> RenderWidgetHostViewQt::mapTouchPoints(const QList<QTouchEvent::TouchPoint> &input) -{ - QList<TouchPoint> output; - for (int i = 0; i < input.size(); ++i) { - const QTouchEvent::TouchPoint &point = input[i]; - - int qtId = point.id(); - QMap<int, int>::const_iterator it = m_touchIdMapping.find(qtId); - if (it == m_touchIdMapping.end()) - it = m_touchIdMapping.insert(qtId, firstAvailableId(m_touchIdMapping)); - - output.append(qMakePair(it.value(), point)); - } - - Q_ASSERT(output.size() == std::accumulate(output.cbegin(), output.cend(), QSet<int>(), - [] (QSet<int> s, const TouchPoint &p) { s.insert(p.second.id()); return s; }).size()); - - for (auto &&point : qAsConst(input)) - if (point.state() == Qt::TouchPointReleased) - m_touchIdMapping.remove(point.id()); - - return output; -} - -bool RenderWidgetHostViewQt::IsPopup() const +bool RenderWidgetHostViewQt::isPopup() const { return widget_type_ == content::WidgetType::kPopup; } -void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event) +bool RenderWidgetHostViewQt::updateScreenInfo() { - if (event->type() == QEvent::MouseButtonPress) - m_mouseButtonPressed++; - if (event->type() == QEvent::MouseButtonRelease) - m_mouseButtonPressed--; - - // Don't forward mouse events synthesized by the system, which are caused by genuine touch - // events. Chromium would then process for e.g. a mouse click handler twice, once due to the - // system synthesized mouse event, and another time due to a touch-to-gesture-to-mouse - // transformation done by Chromium. - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; - handlePointerEvent<QMouseEvent>(event); -} - -void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) -{ - if (IsMouseLocked() && ev->key() == Qt::Key_Escape && ev->type() == QEvent::KeyRelease) - UnlockMouse(); - - if (m_receivedEmptyImeEvent) { - // IME composition was not finished with a valid commit string. - // We're getting the composition result in a key event. - if (ev->key() != 0) { - // The key event is not a result of an IME composition. Cancel IME. - host()->ImeCancelComposition(); - m_receivedEmptyImeEvent = false; - } else { - if (ev->type() == QEvent::KeyRelease) { - host()->ImeCommitText(toString16(ev->text()), - std::vector<ui::ImeTextSpan>(), - gfx::Range::InvalidRange(), - 0); - m_receivedEmptyImeEvent = false; - m_imeInProgress = false; - } - return; - } - } - - // Ignore autorepeating KeyRelease events so that the generated web events - // conform to the spec, which requires autorepeat to result in a sequence of - // keypress events and only one final keyup event: - // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Auto-repeat_handling - // https://w3c.github.io/uievents/#dom-keyboardevent-repeat - if (ev->type() == QEvent::KeyRelease && ev->isAutoRepeat()) - return; - - content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); - if (webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && !m_editCommand.empty()) { - ui::LatencyInfo latency; - latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); - std::vector<blink::mojom::EditCommandPtr> commands; - commands.emplace_back(blink::mojom::EditCommand::New(m_editCommand, "")); - m_editCommand.clear(); - GetFocusedWidget()->ForwardKeyboardEventWithCommands(webEvent, latency, std::move(commands), nullptr); - return; - } - - bool keyDownTextInsertion = webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && webEvent.text[0]; - webEvent.skip_in_browser = keyDownTextInsertion; - GetFocusedWidget()->ForwardKeyboardEvent(webEvent); - - if (keyDownTextInsertion) { - // Blink won't consume the RawKeyDown, but rather the Char event in this case. - // The RawKeyDown is skipped on the way back (see above). - // The same os_event will be set on both NativeWebKeyboardEvents. - webEvent.skip_in_browser = false; - webEvent.SetType(blink::WebInputEvent::Type::kChar); - GetFocusedWidget()->ForwardKeyboardEvent(webEvent); - } -} - -void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) -{ - // Reset input manager state - m_imState = 0; - - if (!host()) - return; - - QString commitString = ev->commitString(); - QString preeditString = ev->preeditString(); - - int cursorPositionInPreeditString = -1; - gfx::Range selectionRange = gfx::Range::InvalidRange(); - - const QList<QInputMethodEvent::Attribute> &attributes = ev->attributes(); - std::vector<ui::ImeTextSpan> underlines; - bool hasSelection = false; - - for (const auto &attribute : attributes) { - switch (attribute.type) { - case QInputMethodEvent::TextFormat: { - if (preeditString.isEmpty()) - break; - - int start = qMin(attribute.start, (attribute.start + attribute.length)); - int end = qMax(attribute.start, (attribute.start + attribute.length)); - - // Blink does not support negative position values. Adjust start and end positions - // to non-negative values. - if (start < 0) { - start = 0; - end = qMax(0, start + end); - } - - underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, - ui::ImeTextSpan::Thickness::kThin, ui::ImeTextSpan::UnderlineStyle::kSolid, - SK_ColorTRANSPARENT)); - - QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); - if (format.underlineStyle() != QTextCharFormat::NoUnderline) - underlines.back().underline_color = toSk(format.underlineColor()); - - break; - } - case QInputMethodEvent::Cursor: - // Always set the position of the cursor, even if it's marked invisible by Qt, otherwise - // there is no way the user will know which part of the composition string will be - // changed, when performing an IME-specific action (like selecting a different word - // suggestion). - cursorPositionInPreeditString = attribute.start; - break; - case QInputMethodEvent::Selection: - hasSelection = true; - - // Cancel IME composition - if (preeditString.isEmpty() && attribute.start + attribute.length == 0) { - selectionRange.set_start(0); - selectionRange.set_end(0); - break; - } - - selectionRange.set_start(qMin(attribute.start, (attribute.start + attribute.length))); - selectionRange.set_end(qMax(attribute.start, (attribute.start + attribute.length))); - break; - default: - break; - } - } - - if (!selectionRange.IsValid()) { - // We did not receive a valid selection range, hence the range is going to mark the - // cursor position. - int newCursorPosition = - (cursorPositionInPreeditString < 0) ? preeditString.length() - : cursorPositionInPreeditString; - selectionRange.set_start(newCursorPosition); - selectionRange.set_end(newCursorPosition); - } - - if (hasSelection) { - if (auto *frameWidgetInputHandler = getFrameWidgetInputHandler()) - frameWidgetInputHandler->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); - } - - int replacementLength = ev->replacementLength(); - gfx::Range replacementRange = gfx::Range::InvalidRange(); - - if (replacementLength > 0) - { - int replacementStart = ev->replacementStart() < 0 ? m_cursorPosition + ev->replacementStart() : ev->replacementStart(); - if (replacementStart >= 0 && replacementStart < m_surroundingText.length()) - replacementRange = gfx::Range(replacementStart, replacementStart + replacementLength); - } - - // There are so-far two known cases, when an empty QInputMethodEvent is received. - // First one happens when backspace is used to remove the last character in the pre-edit - // string, thus signaling the end of the composition. - // The second one happens (on Windows) when a Korean char gets composed, but instead of - // the event having a commit string, both strings are empty, and the actual char is received - // as a QKeyEvent after the QInputMethodEvent is processed. - // In lieu of the second case, we can't simply cancel the composition on an empty event, - // and then add the Korean char when QKeyEvent is received, because that leads to text - // flickering in the textarea (or any other element). - // Instead we postpone the processing of the empty QInputMethodEvent by posting it - // to the same focused object, and cancelling the composition on the next event loop tick. - if (commitString.isEmpty() && preeditString.isEmpty() && replacementLength == 0) { - if (!m_receivedEmptyImeEvent && m_imeInProgress && !hasSelection) { - m_receivedEmptyImeEvent = true; - QInputMethodEvent *eventCopy = new QInputMethodEvent(*ev); - QGuiApplication::postEvent(qApp->focusObject(), eventCopy); - } else { - m_receivedEmptyImeEvent = false; - if (m_imeInProgress) { - m_imeInProgress = false; - host()->ImeCancelComposition(); - } - } - - return; - } - - m_receivedEmptyImeEvent = false; - - // Finish compostion: insert or erase text. - if (!commitString.isEmpty() || replacementLength > 0) { - host()->ImeCommitText(toString16(commitString), - underlines, - replacementRange, - 0); - m_imeInProgress = false; - } - - // Update or start new composition. - // Be aware of that, we might get a commit string and a pre-edit string in a single event and - // this means a new composition. - if (!preeditString.isEmpty()) { - host()->ImeSetComposition(toString16(preeditString), - underlines, - replacementRange, - selectionRange.start(), - selectionRange.end()); - m_imeInProgress = true; - } -} + blink::ScreenInfo oldScreenInfo = m_screenInfo; + QScreen *screen = m_delegate->window() ? m_delegate->window()->screen() : nullptr; + m_screenInfo = screenInfoFromQScreen(screen); -void RenderWidgetHostViewQt::handleInputMethodQueryEvent(QInputMethodQueryEvent *ev) -{ - Qt::InputMethodQueries queries = ev->queries(); - for (uint i = 0; i < 32; ++i) { - Qt::InputMethodQuery query = (Qt::InputMethodQuery)(int)(queries & (1<<i)); - if (query) { - QVariant v = inputMethodQuery(query); - ev->setValue(query, v); - } - } - ev->accept(); + return (m_screenInfo != oldScreenInfo); } -void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) +void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *event) { if (!m_wheelAckPending) { Q_ASSERT(m_pendingWheelEvents.isEmpty()); - blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(ev); + blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(event); m_wheelAckPending = (webEvent.phase != blink::WebMouseWheelEvent::kPhaseEnded); - m_mouseWheelPhaseHandler.AddPhaseIfNeededAndScheduleEndEvent(webEvent, true); + GetMouseWheelPhaseHandler()->AddPhaseIfNeededAndScheduleEndEvent(webEvent, true); if (host()->delegate() && host()->delegate()->GetInputEventRouter()) host()->delegate()->GetInputEventRouter()->RouteMouseWheelEvent(this, &webEvent, ui::LatencyInfo()); return; } if (!m_pendingWheelEvents.isEmpty()) { // Try to combine with this wheel event with the last pending one. - if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev)) + if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), event)) return; } - m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev)); + m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(event)); } void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &event, blink::mojom::InputEventResultState /*ack_result*/) @@ -1656,277 +954,6 @@ content::MouseWheelPhaseHandler *RenderWidgetHostViewQt::GetMouseWheelPhaseHandl return &m_mouseWheelPhaseHandler; } -#ifndef QT_NO_GESTURES -void RenderWidgetHostViewQt::handleGestureEvent(QNativeGestureEvent *ev) -{ - const Qt::NativeGestureType type = ev->gestureType(); - // These are the only supported gestures by Chromium so far. - if (type == Qt::ZoomNativeGesture || type == Qt::SmartZoomNativeGesture) { - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) { - auto webEvent = WebEventFactory::toWebGestureEvent(ev); - host()->delegate()->GetInputEventRouter()->RouteGestureEvent(this, &webEvent, ui::LatencyInfo()); - } - } -} -#endif - -void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) -{ - // On macOS instead of handling touch events, we use the OS provided QNativeGestureEvents. -#ifdef Q_OS_MACOS - if (ev->spontaneous()) { - return; - } else { - VLOG(1) - << "Sending simulated touch events to Chromium does not work properly on macOS. " - "Consider using QNativeGestureEvents or QMouseEvents."; - } -#endif - - // Chromium expects the touch event timestamps to be comparable to base::TimeTicks::Now(). - // Most importantly we also have to preserve the relative time distance between events. - // Calculate a delta between event timestamps and Now() on the first received event, and - // apply this delta to all successive events. This delta is most likely smaller than it - // should by calculating it here but this will hopefully cause less than one frame of delay. - base::TimeTicks eventTimestamp = base::TimeTicks() + base::TimeDelta::FromMilliseconds(ev->timestamp()); - if (m_eventsToNowDelta == base::TimeDelta()) - m_eventsToNowDelta = base::TimeTicks::Now() - eventTimestamp; - eventTimestamp += m_eventsToNowDelta; - - auto touchPoints = mapTouchPoints(ev->touchPoints()); - // Make sure that POINTER_DOWN action is delivered before MOVE, and MOVE before POINTER_UP - std::sort(touchPoints.begin(), touchPoints.end(), [] (const TouchPoint &l, const TouchPoint &r) { - return l.second.state() < r.second.state(); - }); - - auto sc = qScopeGuard([&] () { - switch (ev->type()) { - case QEvent::TouchCancel: - for (auto &&it : qAsConst(touchPoints)) - m_touchIdMapping.remove(it.second.id()); - Q_FALLTHROUGH(); - - case QEvent::TouchEnd: - m_previousTouchPoints.clear(); - m_touchMotionStarted = false; - break; - - default: - m_previousTouchPoints = touchPoints; - break; - } - }); - - ui::MotionEvent::Action action; - // Check first if the touch event should be routed to the selectionController - if (!touchPoints.isEmpty()) { - switch (touchPoints[0].second.state()) { - case Qt::TouchPointPressed: - action = ui::MotionEvent::Action::DOWN; - break; - case Qt::TouchPointMoved: - action = ui::MotionEvent::Action::MOVE; - break; - case Qt::TouchPointReleased: - action = ui::MotionEvent::Action::UP; - break; - default: - action = ui::MotionEvent::Action::NONE; - break; - } - } else { - // An empty touchPoints always corresponds to a TouchCancel event. - // We can't forward touch cancellations without a previously processed touch event, - // as Chromium expects the previous touchPoints for Action::CANCEL. - // If both are empty that means the TouchCancel was sent without an ongoing touch, - // so there's nothing to cancel anyway. - Q_ASSERT(ev->type() == QEvent::TouchCancel); - touchPoints = m_previousTouchPoints; - if (touchPoints.isEmpty()) - return; - - action = ui::MotionEvent::Action::CANCEL; - } - - MotionEventQt me(touchPoints, eventTimestamp, action, ev->modifiers()); - if (m_touchSelectionController->WillHandleTouchEvent(me)) - return; - - switch (ev->type()) { - case QEvent::TouchBegin: - m_sendMotionActionDown = true; - m_touchMotionStarted = true; - m_touchSelectionControllerClient->onTouchDown(); - break; - case QEvent::TouchUpdate: - m_touchMotionStarted = true; - break; - case QEvent::TouchCancel: - { - // Only process TouchCancel events received following a TouchBegin or TouchUpdate event - if (m_touchMotionStarted) { - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, ev->modifiers()); - processMotionEvent(cancelEvent); - } - - return; - } - case QEvent::TouchEnd: - m_touchSelectionControllerClient->onTouchUp(); - break; - default: - break; - } - - if (m_imeInProgress && ev->type() == QEvent::TouchBegin) { - m_imeInProgress = false; - // Tell input method to commit the pre-edit string entered so far, and finish the - // composition operation. -#ifdef Q_OS_WIN - // Yes the function name is counter-intuitive, but commit isn't actually implemented - // by the Windows QPA, and reset does exactly what is necessary in this case. - qApp->inputMethod()->reset(); -#else - qApp->inputMethod()->commit(); -#endif - } - - // MEMO for the basis of this logic look into: - // * blink_event_util.cc:ToWebTouchPointState: which is used later to forward touch event - // composed from motion event after gesture recognition - // * gesture_detector.cc:GestureDetector::OnTouchEvent: contains logic for every motion - // event action and corresponding gesture recognition routines - // * input_router_imp.cc:InputRouterImp::SetMovementXYForTouchPoints: expectation about - // touch event content like number of points for different states - - int lastPressIndex = -1; - while ((lastPressIndex + 1) < touchPoints.size() && touchPoints[lastPressIndex + 1].second.state() == Qt::TouchPointPressed) - ++lastPressIndex; - - switch (ev->type()) { - case QEvent::TouchBegin: - processMotionEvent(MotionEventQt(touchPoints.mid(lastPressIndex), - eventTimestamp, ui::MotionEvent::Action::DOWN, ev->modifiers())); - --lastPressIndex; - Q_FALLTHROUGH(); - - case QEvent::TouchUpdate: - for (; lastPressIndex >= 0; --lastPressIndex) { - Q_ASSERT(touchPoints[lastPressIndex].second.state() == Qt::TouchPointPressed); - MotionEventQt me(touchPoints.mid(lastPressIndex), eventTimestamp, ui::MotionEvent::Action::POINTER_DOWN, ev->modifiers(), 0); - processMotionEvent(me); - } - - if (ev->touchPointStates() & Qt::TouchPointMoved) - processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, ui::MotionEvent::Action::MOVE, ev->modifiers())); - - Q_FALLTHROUGH(); - - case QEvent::TouchEnd: - while (!touchPoints.isEmpty() && touchPoints.back().second.state() == Qt::TouchPointReleased) { - auto action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : ui::MotionEvent::Action::UP; - int index = action == ui::MotionEvent::Action::POINTER_UP ? touchPoints.size() - 1 : -1; - processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, action, ev->modifiers(), index)); - touchPoints.pop_back(); - } - break; - - default: - Q_ASSERT_X(false, __FUNCTION__, "Other event types are expected to be already handled."); - break; - } -} - -#if QT_CONFIG(tabletevent) -void RenderWidgetHostViewQt::handleTabletEvent(QTabletEvent *event) -{ - handlePointerEvent<QTabletEvent>(event); -} -#endif - -template<class T> -void RenderWidgetHostViewQt::handlePointerEvent(T *event) -{ - // Currently WebMouseEvent is a subclass of WebPointerProperties, so basically - // tablet events are mouse events with extra properties. - blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event); - if ((webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown || webEvent.GetType() == blink::WebInputEvent::Type::kMouseUp) - && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { - // Blink can only handle the 5 main mouse-buttons and may assert when processing mouse-down for no button. - LOG(INFO) << "Unhandled mouse button"; - return; - } - - if (webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown) { - if (event->button() != m_clickHelper.lastPressButton - || (event->timestamp() - m_clickHelper.lastPressTimestamp > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval())) - || (event->pos() - m_clickHelper.lastPressPosition).manhattanLength() > qGuiApp->styleHints()->startDragDistance() - || m_clickHelper.clickCounter >= 3) - m_clickHelper.clickCounter = 0; - - m_clickHelper.lastPressTimestamp = event->timestamp(); - webEvent.click_count = ++m_clickHelper.clickCounter; - m_clickHelper.lastPressButton = event->button(); - m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint(); - } - - if (webEvent.GetType() == blink::WebInputEvent::Type::kMouseUp) - webEvent.click_count = m_clickHelper.clickCounter; - - webEvent.movement_x = event->globalX() - m_previousMousePosition.x(); - webEvent.movement_y = event->globalY() - m_previousMousePosition.y(); - - if (IsMouseLocked()) - QCursor::setPos(m_previousMousePosition); - else - m_previousMousePosition = event->globalPos(); - - if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown) { - m_imeInProgress = false; - // Tell input method to commit the pre-edit string entered so far, and finish the - // composition operation. -#ifdef Q_OS_WIN - // Yes the function name is counter-intuitive, but commit isn't actually implemented - // by the Windows QPA, and reset does exactly what is necessary in this case. - qApp->inputMethod()->reset(); -#else - qApp->inputMethod()->commit(); -#endif - } - - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) - host()->delegate()->GetInputEventRouter()->RouteMouseEvent(this, &webEvent, ui::LatencyInfo()); -} - -void RenderWidgetHostViewQt::handleHoverEvent(QHoverEvent *ev) -{ - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) { - auto webEvent = WebEventFactory::toWebMouseEvent(ev); - host()->delegate()->GetInputEventRouter()->RouteMouseEvent(this, &webEvent, ui::LatencyInfo()); - } -} - -void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) -{ - if (ev->gotFocus()) { - host()->GotFocus(); - host()->SetActive(true); - content::RenderViewHostImpl *viewHost = content::RenderViewHostImpl::From(host()); - Q_ASSERT(viewHost); - if (ev->reason() == Qt::TabFocusReason) - viewHost->SetInitialFocus(false); - else if (ev->reason() == Qt::BacktabFocusReason) - viewHost->SetInitialFocus(true); - ev->accept(); - - m_adapterClient->webContentsAdapter()->handlePendingMouseLockPermission(); - } else if (ev->lostFocus()) { - host()->SetActive(false); - host()->LostFocus(); - ev->accept(); - } -} - blink::mojom::FrameWidgetInputHandler *RenderWidgetHostViewQt::getFrameWidgetInputHandler() { auto *focused_widget = GetFocusedWidget(); diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 9c843e2a9..e01d91c84 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -40,7 +40,7 @@ #ifndef RENDER_WIDGET_HOST_VIEW_QT_H #define RENDER_WIDGET_HOST_VIEW_QT_H -#include "compositor/display_frame_sink.h" +#include "compositor/compositor.h" #include "delegated_frame_host_client_qt.h" #include "render_widget_host_view_qt_delegate.h" @@ -52,18 +52,9 @@ #include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/renderer_host/text_input_manager.h" -#include "content/public/browser/render_process_host_observer.h" -#include "gpu/ipc/common/gpu_messages.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" -#include <QMap> -#include <QPoint> -#include <QtGlobal> -#include <QtGui/QTouchEvent> - -QT_BEGIN_NAMESPACE -class QAccessibleInterface; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QAccessibleInterface) namespace content { class RenderFrameHost; @@ -76,43 +67,19 @@ class TouchSelectionController; namespace QtWebEngineCore { +class RenderWidgetHostViewQtDelegateClient; class GuestInputEventObserverQt; -class TouchHandleDrawableClient; class TouchSelectionControllerClientQt; -class TouchSelectionMenuController; - -struct MultipleMouseClickHelper -{ - QPoint lastPressPosition; - Qt::MouseButton lastPressButton; - int clickCounter; - ulong lastPressTimestamp; - - MultipleMouseClickHelper() - : lastPressPosition(QPoint()) - , lastPressButton(Qt::NoButton) - , clickCounter(0) - , lastPressTimestamp(0) - { - } -}; +class WebContentsAdapterClient; class RenderWidgetHostViewQt : public content::RenderWidgetHostViewBase , public ui::GestureProviderClient - , public RenderWidgetHostViewQtDelegateClient , public base::SupportsWeakPtr<RenderWidgetHostViewQt> , public content::TextInputManager::Observer , public content::RenderFrameMetadataProvider::Observer - , public DisplayConsumer { public: - enum LoadVisuallyCommittedState { - NotCommitted, - DidFirstVisuallyNonEmptyPaint, - DidFirstCompositorFrameSwap - }; - RenderWidgetHostViewQt(content::RenderWidgetHost* widget); ~RenderWidgetHostViewQt(); @@ -120,6 +87,7 @@ public: void setDelegate(RenderWidgetHostViewQtDelegate *delegate); WebContentsAdapterClient *adapterClient() { return m_adapterClient; } void setAdapterClient(WebContentsAdapterClient *adapterClient); + RenderWidgetHostViewQtDelegateClient *delegateClient() const { return m_delegateClient.get(); } void setGuest(content::RenderWidgetHostImpl *); void InitAsChild(gfx::NativeView) override; @@ -183,63 +151,43 @@ public: void DidStopFlinging() override; std::unique_ptr<content::SyntheticGestureTarget> CreateSyntheticGestureTarget() override; ui::Compositor *GetCompositor() override; +#if defined(OS_MAC) + void SetActive(bool active) override { QT_NOT_YET_IMPLEMENTED } + void SpeakSelection() override { QT_NOT_YET_IMPLEMENTED } + void ShowDefinitionForSelection() override { QT_NOT_YET_IMPLEMENTED } + void SetWindowFrameInScreen(const gfx::Rect&) override { QT_NOT_YET_IMPLEMENTED } +#endif // defined(OS_MAC) // Overridden from ui::GestureProviderClient. void OnGestureEvent(const ui::GestureEventData& gesture) override; - // Overridden from RenderWidgetHostViewQtDelegateClient. - QSGNode *updatePaintNode(QSGNode *) override; - void notifyShown() override; - void notifyHidden() override; - void visualPropertiesChanged() override; - bool forwardEvent(QEvent *) override; - QVariant inputMethodQuery(Qt::InputMethodQuery query) override; - void closePopup() override; - // Overridden from content::TextInputManager::Observer void OnUpdateTextInputStateCalled(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view, bool did_update_state) override; void OnSelectionBoundsChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) override; void OnTextSelectionChanged(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view) override; - void handleMouseEvent(QMouseEvent*); - void handleKeyEvent(QKeyEvent*); - void handleWheelEvent(QWheelEvent*); - void handleTouchEvent(QTouchEvent*); -#if QT_CONFIG(tabletevent) - void handleTabletEvent(QTabletEvent *ev); -#endif -#ifndef QT_NO_GESTURES - void handleGestureEvent(QNativeGestureEvent *); -#endif - void handleHoverEvent(QHoverEvent*); - void handleFocusEvent(QFocusEvent*); - void handleInputMethodEvent(QInputMethodEvent*); - void handleInputMethodQueryEvent(QInputMethodQueryEvent*); - - template<class T> void handlePointerEvent(T*); - -#if defined(OS_MAC) - void SetActive(bool active) override { QT_NOT_YET_IMPLEMENTED } - void SpeakSelection() override { QT_NOT_YET_IMPLEMENTED } - void ShowDefinitionForSelection() override { QT_NOT_YET_IMPLEMENTED } - void SetWindowFrameInScreen(const gfx::Rect&) override { QT_NOT_YET_IMPLEMENTED } -#endif // defined(OS_MAC) - // Overridden from content::BrowserAccessibilityDelegate content::BrowserAccessibilityManager* CreateBrowserAccessibilityManager(content::BrowserAccessibilityDelegate* delegate, bool for_root_frame) override; - // Called from WebContentsDelegateQt - void OnDidFirstVisuallyNonEmptyPaint(); - // Overridden from content::RenderFrameMetadataProvider::Observer void OnRenderFrameMetadataChangedAfterActivation() override; void OnRenderFrameMetadataChangedBeforeActivation(const cc::RenderFrameMetadata &) override {} void OnRenderFrameSubmission() override {} void OnLocalSurfaceIdChanged(const cc::RenderFrameMetadata &) override {} - // Overridden from DisplayConsumer - void scheduleUpdate() override; + // Called from RenderWidgetHostViewQtDelegateClient. + Compositor::Id compositorId(); + void notifyShown(); + void notifyHidden(); + bool updateScreenInfo(); + void handleWheelEvent(QWheelEvent *); + void processMotionEvent(const ui::MotionEvent &motionEvent); + void resetInputManagerState() { m_imState = 0; } + + // Called from WebContentsDelegateQt. + void OnDidFirstVisuallyNonEmptyPaint(); + // Called from WebContentsAdapter. gfx::SizeF lastContentsSize() const { return m_lastContentsSize; } gfx::Vector2dF lastScrollOffset() const { return m_lastScrollOffset; } @@ -248,88 +196,59 @@ public: blink::mojom::FrameWidgetInputHandler *getFrameWidgetInputHandler(); ui::TextInputType getTextInputType() const; + void synchronizeVisualProperties( + const base::Optional<viz::LocalSurfaceId> &childSurfaceId); + private: friend class DelegatedFrameHostClientQt; - void processMotionEvent(const ui::MotionEvent &motionEvent); - typedef QPair<int, QTouchEvent::TouchPoint> TouchPoint; - QList<TouchPoint> mapTouchPoints(const QList<QTouchEvent::TouchPoint> &input); - - bool IsPopup() const; - - void selectionChanged(); - - void synchronizeVisualProperties(const base::Optional<viz::LocalSurfaceId> &childSurfaceId); - - void callUpdate(); + bool isPopup() const; bool updateCursorFromResource(ui::mojom::CursorType type); - // Geometry of the view in screen DIPs. - gfx::Rect m_viewRectInDips; - // Geometry of the window, including frame, in screen DIPs. - gfx::Rect m_windowRectInDips; - blink::ScreenInfo m_screenInfo; - scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; + std::unique_ptr<content::CursorManager> m_cursorManager; ui::FilteredGestureProvider m_gestureProvider; - base::TimeDelta m_eventsToNowDelta; - bool m_sendMotionActionDown; - bool m_touchMotionStarted; - QMap<int, int> m_touchIdMapping; - QList<TouchPoint> m_previousTouchPoints; - std::unique_ptr<RenderWidgetHostViewQtDelegate> m_delegate; std::unique_ptr<GuestInputEventObserverQt> m_guestInputEventObserver; - bool m_visible; - bool m_deferredShow = false; - DelegatedFrameHostClientQt m_delegatedFrameHostClient{this}; - std::unique_ptr<content::DelegatedFrameHost> m_delegatedFrameHost; - std::unique_ptr<ui::Layer> m_rootLayer; - std::unique_ptr<ui::Compositor> m_uiCompositor; - scoped_refptr<DisplayFrameSink> m_displayFrameSink; - LoadVisuallyCommittedState m_loadVisuallyCommittedState; - + viz::FrameSinkId m_frameSinkId; + std::unique_ptr<RenderWidgetHostViewQtDelegateClient> m_delegateClient; + std::unique_ptr<RenderWidgetHostViewQtDelegate> m_delegate; QMetaObject::Connection m_adapterClientDestroyedConnection; - WebContentsAdapterClient *m_adapterClient; - MultipleMouseClickHelper m_clickHelper; - - bool m_imeInProgress; - bool m_receivedEmptyImeEvent; - QPoint m_previousMousePosition; - bool m_isMouseLocked; + WebContentsAdapterClient *m_adapterClient = nullptr; + bool m_isMouseLocked = false; + bool m_visible = false; + bool m_deferredShow = false; gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; + DelegatedFrameHostClientQt m_delegatedFrameHostClient { this }; + + // VIZ + blink::ScreenInfo m_screenInfo; + std::unique_ptr<content::DelegatedFrameHost> m_delegatedFrameHost; + std::unique_ptr<ui::Layer> m_rootLayer; + std::unique_ptr<ui::Compositor> m_uiCompositor; viz::ParentLocalSurfaceIdAllocator m_dfhLocalSurfaceIdAllocator; viz::ParentLocalSurfaceIdAllocator m_uiCompositorLocalSurfaceIdAllocator; - uint m_imState; - int m_anchorPositionWithinSelection; - int m_cursorPositionWithinSelection; - uint m_cursorPosition; - bool m_emptyPreviousSelection; - QString m_surroundingText; - - bool m_imeHasHiddenTextCapability; + // IME + uint m_imState = 0; - bool m_wheelAckPending; + // Wheel + bool m_wheelAckPending = false; QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; - content::MouseWheelPhaseHandler m_mouseWheelPhaseHandler; - viz::FrameSinkId m_frameSinkId; - - std::string m_editCommand; + content::MouseWheelPhaseHandler m_mouseWheelPhaseHandler { this }; + // TouchSelection std::unique_ptr<TouchSelectionControllerClientQt> m_touchSelectionControllerClient; std::unique_ptr<ui::TouchSelectionController> m_touchSelectionController; gfx::SelectionBound m_selectionStart; gfx::SelectionBound m_selectionEnd; - base::WeakPtrFactory<RenderWidgetHostViewQt> m_weakPtrFactory{this}; - - uint m_mouseButtonPressed = 0; + base::WeakPtrFactory<RenderWidgetHostViewQt> m_weakPtrFactory { this }; }; } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 5fda0eeb7..f9306dba9 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -53,37 +53,19 @@ #include "qtwebenginecoreglobal_p.h" -#include <QRect> -#include <QtGui/qwindowdefs.h> +#include <QtCore/QRect> +#include <QtGui/QColor> +#include <QtGui/QCursor> +#include <QtGui/QImage> QT_BEGIN_NAMESPACE -class QEvent; -class QInputMethodEvent; -class QSGNode; -class QSGTexture; -class QVariant; class QWheelEvent; - -class QSGImageNode; - +class QWindow; QT_END_NAMESPACE namespace QtWebEngineCore { class WebContentsAdapterClient; - -class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient { -public: - virtual ~RenderWidgetHostViewQtDelegateClient() { } - virtual QSGNode *updatePaintNode(QSGNode *) = 0; - virtual void notifyShown() = 0; - virtual void notifyHidden() = 0; - virtual void visualPropertiesChanged() = 0; - virtual bool forwardEvent(QEvent *) = 0; - virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) = 0; - virtual void closePopup() = 0; -}; - class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate { public: virtual ~RenderWidgetHostViewQtDelegate() { } @@ -98,16 +80,13 @@ public: virtual void hide() = 0; virtual bool isVisible() const = 0; virtual QWindow* window() const = 0; - virtual QSGTexture *createTextureFromImage(const QImage &) = 0; - virtual QSGImageNode *createImageNode() = 0; - virtual void update() = 0; virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; virtual void move(const QPoint &) = 0; virtual void inputMethodStateChanged(bool editorVisible, bool passwordInput) = 0; 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 adapterClientChanged(WebContentsAdapterClient *client) = 0; virtual void unhandledWheelEvent(QWheelEvent *) {} }; diff --git a/src/core/render_widget_host_view_qt_delegate_client.cpp b/src/core/render_widget_host_view_qt_delegate_client.cpp new file mode 100644 index 000000000..305f4c1e9 --- /dev/null +++ b/src/core/render_widget_host_view_qt_delegate_client.cpp @@ -0,0 +1,1016 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "render_widget_host_view_qt_delegate_client.h" + +#include "render_widget_host_view_qt.h" +#include "touch_selection_controller_client_qt.h" +#include "type_conversion.h" +#include "web_contents_adapter.h" +#include "web_contents_adapter_client.h" +#include "web_event_factory.h" + +#include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_input_event_router.h" +#include "ui/touch_selection/touch_selection_controller.h" + +#include <QEvent> +#include <QInputMethodEvent> +#include <QScopeGuard> +#include <QSGNode> +#include <QStyleHints> +#include <QTextFormat> +#include <QVariant> + +#include <private/qguiapplication_p.h> +#include <qpa/qplatforminputcontext.h> +#include <qpa/qplatformintegration.h> +#include <QtGui/private/qinputcontrol_p.h> + +namespace QtWebEngineCore { + +static inline int firstAvailableId(const QMap<int, int> &map) +{ + ui::BitSet32 usedIds; + QMap<int, int>::const_iterator end = map.end(); + for (QMap<int, int>::const_iterator it = map.begin(); it != end; ++it) + usedIds.mark_bit(it.value()); + return usedIds.first_unmarked_bit(); +} + +typedef QPair<int, QTouchEvent::TouchPoint> TouchPoint; +QList<TouchPoint> RenderWidgetHostViewQtDelegateClient::mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &input) +{ + QList<TouchPoint> output; + for (int i = 0; i < input.size(); ++i) { + const QTouchEvent::TouchPoint &point = input[i]; + + int qtId = point.id(); + QMap<int, int>::const_iterator it = m_touchIdMapping.find(qtId); + if (it == m_touchIdMapping.end()) { + Q_ASSERT_X(m_touchIdMapping.size() <= 16, "", "Number of mapped ids can't exceed 16 for velocity tracker"); + it = m_touchIdMapping.insert(qtId, firstAvailableId(m_touchIdMapping)); + } + + output.append(qMakePair(it.value(), point)); + } + + Q_ASSERT(output.size() == std::accumulate(output.cbegin(), output.cend(), QSet<int>(), + [] (QSet<int> s, const TouchPoint &p) { s.insert(p.second.id()); return s; }).size()); + + for (auto &&point : qAsConst(input)) + if (point.state() == QEventPoint::Released) + m_touchIdMapping.remove(point.id()); + + return output; +} + +static uint32_t s_eventId = 0; +class MotionEventQt : public ui::MotionEvent +{ +public: + MotionEventQt(const QList<TouchPoint> &touchPoints, + const base::TimeTicks &eventTime, Action action, + const Qt::KeyboardModifiers modifiers, int index = -1) + : touchPoints(touchPoints) + , eventTime(eventTime) + , action(action) + , eventId(++s_eventId) + , flags(flagsFromModifiers(modifiers)) + , index(index) + { + // index is only valid for ACTION_DOWN and ACTION_UP and should correspond to the point causing it + // see blink_event_util.cc:ToWebTouchPointState for details + Q_ASSERT_X((action != Action::POINTER_DOWN && action != Action::POINTER_UP && index == -1) + || (action == Action::POINTER_DOWN && index >= 0 && touchPoint(index).state() == QEventPoint::Pressed) + || (action == Action::POINTER_UP && index >= 0 && touchPoint(index).state() == QEventPoint::Released), + "MotionEventQt", qPrintable(QString("action: %1, index: %2, state: %3").arg(int(action)).arg(index).arg(touchPoint(index).state()))); + } + + uint32_t GetUniqueEventId() const override { return eventId; } + Action GetAction() const override { return action; } + int GetActionIndex() const override { return index; } + size_t GetPointerCount() const override { return touchPoints.size(); } + int GetPointerId(size_t pointer_index) const override + { + return touchPoints[pointer_index].first; + } + float GetX(size_t pointer_index) const override + { + return touchPoint(pointer_index).position().x(); + } + float GetY(size_t pointer_index) const override + { + return touchPoint(pointer_index).position().y(); + } + float GetRawX(size_t pointer_index) const override + { + return touchPoint(pointer_index).globalPosition().x(); + } + float GetRawY(size_t pointer_index) const override + { + return touchPoint(pointer_index).globalPosition().y(); + } + float GetTouchMajor(size_t pointer_index) const override + { + QSizeF diams = touchPoint(pointer_index).ellipseDiameters(); + return std::max(diams.height(), diams.width()); + } + float GetTouchMinor(size_t pointer_index) const override + { + QSizeF diams = touchPoint(pointer_index).ellipseDiameters(); + return std::min(diams.height(), diams.width()); + } + float GetOrientation(size_t pointer_index) const override { return 0; } + int GetFlags() const override { return flags; } + float GetPressure(size_t pointer_index) const override + { + return touchPoint(pointer_index).pressure(); + } + float GetTiltX(size_t pointer_index) const override { return 0; } + float GetTiltY(size_t pointer_index) const override { return 0; } + float GetTwist(size_t) const override { return 0; } + float GetTangentialPressure(size_t) const override { return 0; } + base::TimeTicks GetEventTime() const override { return eventTime; } + + size_t GetHistorySize() const override { return 0; } + base::TimeTicks GetHistoricalEventTime(size_t historical_index) const override + { + return base::TimeTicks(); + } + 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; + } + + int GetButtonState() const override { return 0; } + +private: + QList<TouchPoint> touchPoints; + base::TimeTicks eventTime; + Action action; + const uint32_t eventId; + int flags; + int index; + const QTouchEvent::TouchPoint& touchPoint(size_t i) const { return touchPoints[i].second; } +}; + +RenderWidgetHostViewQtDelegateClient::RenderWidgetHostViewQtDelegateClient( + RenderWidgetHostViewQt *rwhv) + : m_rwhv(rwhv) +{ + Q_ASSERT(rwhv); + + const QPlatformInputContext *context = + QGuiApplicationPrivate::platformIntegration()->inputContext(); + m_imeHasHiddenTextCapability = + context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); +} + +Compositor::Id RenderWidgetHostViewQtDelegateClient::compositorId() +{ + return m_rwhv->compositorId(); +} + +void RenderWidgetHostViewQtDelegateClient::notifyShown() +{ + m_rwhv->notifyShown(); +} + +void RenderWidgetHostViewQtDelegateClient::notifyHidden() +{ + m_rwhv->notifyHidden(); +} + +void RenderWidgetHostViewQtDelegateClient::visualPropertiesChanged() +{ + RenderWidgetHostViewQtDelegate *delegate = m_rwhv->delegate(); + if (!delegate) + return; + + QRect oldViewRect = m_viewRectInDips; + m_viewRectInDips = delegate->viewGeometry().toAlignedRect(); + + QRect oldWindowRect = m_windowRectInDips; + m_windowRectInDips = delegate->windowGeometry(); + + bool screenInfoChanged = m_rwhv->updateScreenInfo(); + + if (m_viewRectInDips != oldViewRect || m_windowRectInDips != oldWindowRect) + m_rwhv->host()->SendScreenRects(); + + if (m_viewRectInDips.size() != oldViewRect.size() || screenInfoChanged) + m_rwhv->synchronizeVisualProperties(base::nullopt); +} + +bool RenderWidgetHostViewQtDelegateClient::forwardEvent(QEvent *event) +{ + Q_ASSERT(m_rwhv->host()->GetView()); + + switch (event->type()) { + case QEvent::ShortcutOverride: { + QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); + + auto acceptKeyOutOfInputField = [](QKeyEvent *keyEvent) -> bool { +#ifdef Q_OS_MACOS + // Check if a shortcut is registered for this key sequence. + QKeySequence sequence = QKeySequence((keyEvent->modifiers() | keyEvent->key()) + & ~(Qt::KeypadModifier | Qt::GroupSwitchModifier)); + if (QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence)) + return false; + + // The following shortcuts are handled out of input field too but + // disabled on macOS to let the blinking menu handling to the + // embedder application (see kKeyboardCodeKeyDownEntries in + // third_party/WebKit/Source/core/editing/EditingBehavior.cpp). + // Let them pass on macOS to generate the corresponding edit command. + return keyEvent->matches(QKeySequence::Copy) || keyEvent->matches(QKeySequence::Paste) + || keyEvent->matches(QKeySequence::Cut) + || keyEvent->matches(QKeySequence::SelectAll); +#else + return false; +#endif + }; + + if (!inputMethodQuery(Qt::ImEnabled).toBool() + && !(inputMethodQuery(Qt::ImHints).toInt() & Qt::ImhHiddenText) + && !acceptKeyOutOfInputField(keyEvent)) + return false; + + Q_ASSERT(m_editCommand.empty()); + if (WebEventFactory::getEditCommand(keyEvent, &m_editCommand) + || QInputControl::isCommonTextEditShortcut(keyEvent)) { + event->accept(); + return true; + } + + return false; + } + case QEvent::MouseButtonPress: + m_rwhv->Focus(); + Q_FALLTHROUGH(); + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + // Skip second MouseMove event when a window is being adopted, so that Chromium + // can properly handle further move events. + // Also make sure the adapter client exists to prevent a null pointer dereference, + // because it's possible for a QWebEnginePagePrivate (adapter) instance to be destroyed, + // and then the OS (observed on Windows) might still send mouse move events to a still + // existing popup RWHVQDW instance. + if (m_rwhv->adapterClient() && m_rwhv->adapterClient()->isBeingAdopted()) + return false; + handleMouseEvent(static_cast<QMouseEvent *>(event)); + break; + case QEvent::KeyPress: + case QEvent::KeyRelease: + handleKeyEvent(static_cast<QKeyEvent *>(event)); + break; + case QEvent::Wheel: + m_rwhv->handleWheelEvent(static_cast<QWheelEvent *>(event)); + break; + case QEvent::TouchBegin: + m_rwhv->Focus(); + Q_FALLTHROUGH(); + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + handleTouchEvent(static_cast<QTouchEvent *>(event)); + break; +#if QT_CONFIG(tabletevent) + case QEvent::TabletPress: + m_rwhv->Focus(); + Q_FALLTHROUGH(); + case QEvent::TabletRelease: + case QEvent::TabletMove: + handleTabletEvent(static_cast<QTabletEvent *>(event)); + break; +#endif +#if QT_CONFIG(gestures) + case QEvent::NativeGesture: + handleGestureEvent(static_cast<QNativeGestureEvent *>(event)); + break; +#endif + case QEvent::HoverMove: + handleHoverEvent(static_cast<QHoverEvent *>(event)); + break; + case QEvent::FocusIn: + case QEvent::FocusOut: + handleFocusEvent(static_cast<QFocusEvent *>(event)); + break; + case QEvent::InputMethod: + handleInputMethodEvent(static_cast<QInputMethodEvent *>(event)); + break; + case QEvent::InputMethodQuery: + handleInputMethodQueryEvent(static_cast<QInputMethodQueryEvent *>(event)); + break; + case QEvent::Leave: +#ifdef Q_OS_WIN + if (m_mouseButtonPressed > 0) + return false; +#endif + case QEvent::HoverLeave: + if (m_rwhv->host()->delegate() && m_rwhv->host()->delegate()->GetInputEventRouter()) { + auto webEvent = WebEventFactory::toWebMouseEvent(event); + m_rwhv->host()->delegate()->GetInputEventRouter()->RouteMouseEvent(m_rwhv, &webEvent, ui::LatencyInfo()); + } + break; + default: + return false; + } + return true; +} + +QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQuery query) +{ + switch (query) { + case Qt::ImEnabled: { + ui::TextInputType type = m_rwhv->getTextInputType(); + bool editorVisible = type != ui::TEXT_INPUT_TYPE_NONE; + // IME manager should disable composition on input fields with ImhHiddenText hint if + // supported + if (m_imeHasHiddenTextCapability) + return QVariant(editorVisible); + + bool passwordInput = type == ui::TEXT_INPUT_TYPE_PASSWORD; + return QVariant(editorVisible && !passwordInput); + } + case Qt::ImFont: + // TODO: Implement this + return QVariant(); + case Qt::ImCursorRectangle: { + if (m_rwhv->GetTextInputManager()) { + if (auto *region = m_rwhv->GetTextInputManager()->GetSelectionRegion()) { + if (region->focus.GetHeight() > 0) { + gfx::Rect caretRect = + gfx::RectBetweenSelectionBounds(region->anchor, region->focus); + if (caretRect.width() == 0) + caretRect.set_width(1); // IME API on Windows expects a width > 0 + return toQt(caretRect); + } + } + } + return QVariant(); + } + case Qt::ImCursorPosition: + return m_cursorPosition; + case Qt::ImAnchorPosition: + return m_rwhv->GetSelectedText().empty() ? m_cursorPosition + : m_anchorPositionWithinSelection; + case Qt::ImSurroundingText: + return m_surroundingText; + case Qt::ImCurrentSelection: + return toQt(m_rwhv->GetSelectedText()); + case Qt::ImMaximumTextLength: + // TODO: Implement this + return QVariant(); // No limit. + case Qt::ImHints: +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText + | Qt::ImhNoTextHandles | Qt::ImhNoEditMenu); +#else + return int(toQtInputMethodHints(m_rwhv->getTextInputType()) | Qt::ImhNoPredictiveText); +#endif + default: + return QVariant(); + } +} + +void RenderWidgetHostViewQtDelegateClient::closePopup() +{ + // We notify the popup to be closed by telling it that it lost focus. WebKit does the rest + // (hiding the widget and automatic memory cleanup via + // RenderWidget::CloseWidgetSoon() -> RenderWidgetHostImpl::ShutdownAndDestroyWidget(true). + m_rwhv->host()->SetActive(false); + m_rwhv->host()->LostFocus(); +} + +template<class T> +void RenderWidgetHostViewQtDelegateClient::handlePointerEvent(T *event) +{ + // Currently WebMouseEvent is a subclass of WebPointerProperties, so basically + // tablet events are mouse events with extra properties. + blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event); + if ((webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown + || webEvent.GetType() == blink::WebInputEvent::Type::kMouseUp) + && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { + // Blink can only handle the 5 main mouse-buttons and may assert when processing mouse-down + // for no button. + LOG(INFO) << "Unhandled mouse button"; + return; + } + + if (webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown) { + if (event->button() != m_clickHelper.lastPressButton + || (event->timestamp() - m_clickHelper.lastPressTimestamp + > static_cast<ulong>(qGuiApp->styleHints()->mouseDoubleClickInterval())) + || (event->position() - m_clickHelper.lastPressPosition).manhattanLength() + > qGuiApp->styleHints()->startDragDistance() + || m_clickHelper.clickCounter >= 3) + m_clickHelper.clickCounter = 0; + + m_clickHelper.lastPressTimestamp = event->timestamp(); + webEvent.click_count = ++m_clickHelper.clickCounter; + m_clickHelper.lastPressButton = event->button(); + m_clickHelper.lastPressPosition = event->position().toPoint(); + } + + if (webEvent.GetType() == blink::WebInputEvent::Type::kMouseUp) + webEvent.click_count = m_clickHelper.clickCounter; + + webEvent.movement_x = event->globalPosition().x() - m_previousMousePosition.x(); + webEvent.movement_y = event->globalPosition().y() - m_previousMousePosition.y(); + + if (m_rwhv->IsMouseLocked()) + QCursor::setPos(m_previousMousePosition); + else + m_previousMousePosition = event->globalPosition().toPoint(); + + if (m_imeInProgress && webEvent.GetType() == blink::WebInputEvent::Type::kMouseDown) { + m_imeInProgress = false; + // Tell input method to commit the pre-edit string entered so far, and finish the + // composition operation. +#ifdef Q_OS_WIN + // Yes the function name is counter-intuitive, but commit isn't actually implemented + // by the Windows QPA, and reset does exactly what is necessary in this case. + qApp->inputMethod()->reset(); +#else + qApp->inputMethod()->commit(); +#endif + } + + if (m_rwhv->host()->delegate() && m_rwhv->host()->delegate()->GetInputEventRouter()) + m_rwhv->host()->delegate()->GetInputEventRouter()->RouteMouseEvent(m_rwhv, &webEvent, ui::LatencyInfo()); +} + +void RenderWidgetHostViewQtDelegateClient::handleMouseEvent(QMouseEvent *event) +{ + if (event->type() == QEvent::MouseButtonPress) + m_mouseButtonPressed++; + if (event->type() == QEvent::MouseButtonRelease) + m_mouseButtonPressed--; + + // Don't forward mouse events synthesized by the system, which are caused by genuine touch + // events. Chromium would then process for e.g. a mouse click handler twice, once due to the + // system synthesized mouse event, and another time due to a touch-to-gesture-to-mouse + // transformation done by Chromium. + if (event->source() == Qt::MouseEventSynthesizedBySystem) + return; + handlePointerEvent<QMouseEvent>(event); +} + +void RenderWidgetHostViewQtDelegateClient::handleKeyEvent(QKeyEvent *event) +{ + if (m_rwhv->IsMouseLocked() && event->key() == Qt::Key_Escape + && event->type() == QEvent::KeyRelease) + m_rwhv->UnlockMouse(); + + if (m_receivedEmptyImeEvent) { + // IME composition was not finished with a valid commit string. + // We're getting the composition result in a key event. + if (event->key() != 0) { + // The key event is not a result of an IME composition. Cancel IME. + m_rwhv->host()->ImeCancelComposition(); + m_receivedEmptyImeEvent = false; + } else { + if (event->type() == QEvent::KeyRelease) { + m_rwhv->host()->ImeCommitText(toString16(event->text()), + std::vector<ui::ImeTextSpan>(), + gfx::Range::InvalidRange(), 0); + m_receivedEmptyImeEvent = false; + m_imeInProgress = false; + } + return; + } + } + + // Ignore autorepeating KeyRelease events so that the generated web events + // conform to the spec, which requires autorepeat to result in a sequence of + // keypress events and only one final keyup event: + // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Auto-repeat_handling + // https://w3c.github.io/uievents/#dom-keyboardevent-repeat + if (event->type() == QEvent::KeyRelease && event->isAutoRepeat()) + return; + + content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(event); + if (webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && !m_editCommand.empty()) { + ui::LatencyInfo latency; + latency.set_source_event_type(ui::SourceEventType::KEY_PRESS); + std::vector<blink::mojom::EditCommandPtr> commands; + commands.emplace_back(blink::mojom::EditCommand::New(m_editCommand, "")); + m_editCommand.clear(); + m_rwhv->GetFocusedWidget()->ForwardKeyboardEventWithCommands(webEvent, latency, std::move(commands), nullptr); + return; + } + + bool keyDownTextInsertion = + webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && webEvent.text[0]; + webEvent.skip_in_browser = keyDownTextInsertion; + m_rwhv->GetFocusedWidget()->ForwardKeyboardEvent(webEvent); + + if (keyDownTextInsertion) { + // Blink won't consume the RawKeyDown, but rather the Char event in this case. + // The RawKeyDown is skipped on the way back (see above). + // The same os_event will be set on both NativeWebKeyboardEvents. + webEvent.skip_in_browser = false; + webEvent.SetType(blink::WebInputEvent::Type::kChar); + m_rwhv->GetFocusedWidget()->ForwardKeyboardEvent(webEvent); + } +} + +void RenderWidgetHostViewQtDelegateClient::handleTouchEvent(QTouchEvent *event) +{ + // On macOS instead of handling touch events, we use the OS provided QNativeGestureEvents. +#ifdef Q_OS_MACOS + if (event->spontaneous()) { + return; + } else { + VLOG(1) << "Sending simulated touch events to Chromium does not work properly on macOS. " + "Consider using QNativeGestureEvents or QMouseEvents."; + } +#endif + + // Chromium expects the touch event timestamps to be comparable to base::TimeTicks::Now(). + // Most importantly we also have to preserve the relative time distance between events. + // Calculate a delta between event timestamps and Now() on the first received event, and + // apply this delta to all successive events. This delta is most likely smaller than it + // should by calculating it here but this will hopefully cause less than one frame of delay. + base::TimeTicks eventTimestamp = base::TimeTicks() + base::TimeDelta::FromMilliseconds(event->timestamp()); + if (m_eventsToNowDelta == 0) + m_eventsToNowDelta = (base::TimeTicks::Now() - eventTimestamp).InMicroseconds(); + eventTimestamp += base::TimeDelta::FromMicroseconds(m_eventsToNowDelta); + + auto touchPoints = mapTouchPointIds(event->touchPoints()); + // Make sure that POINTER_DOWN action is delivered before MOVE, and MOVE before POINTER_UP + std::sort(touchPoints.begin(), touchPoints.end(), [] (const TouchPoint &l, const TouchPoint &r) { + return l.second.state() < r.second.state(); + }); + + auto sc = qScopeGuard([&] () { + switch (event->type()) { + case QEvent::TouchCancel: + for (auto &&it : qAsConst(touchPoints)) + m_touchIdMapping.remove(it.second.id()); + Q_FALLTHROUGH(); + + case QEvent::TouchEnd: + m_previousTouchPoints.clear(); + m_touchMotionStarted = false; + break; + + default: + m_previousTouchPoints = touchPoints; + break; + } + }); + + ui::MotionEvent::Action action; + // Check first if the touch event should be routed to the selectionController + if (!touchPoints.isEmpty()) { + switch (touchPoints[0].second.state()) { + case Qt::TouchPointPressed: + action = ui::MotionEvent::Action::DOWN; + break; + case Qt::TouchPointMoved: + action = ui::MotionEvent::Action::MOVE; + break; + case Qt::TouchPointReleased: + action = ui::MotionEvent::Action::UP; + break; + default: + action = ui::MotionEvent::Action::NONE; + break; + } + } else { + // An empty touchPoints always corresponds to a TouchCancel event. + // We can't forward touch cancellations without a previously processed touch event, + // as Chromium expects the previous touchPoints for Action::CANCEL. + // If both are empty that means the TouchCancel was sent without an ongoing touch, + // so there's nothing to cancel anyway. + Q_ASSERT(event->type() == QEvent::TouchCancel); + touchPoints = m_previousTouchPoints; + if (touchPoints.isEmpty()) + return; + + action = ui::MotionEvent::Action::CANCEL; + } + + MotionEventQt me(touchPoints, eventTimestamp, action, event->modifiers()); + if (m_rwhv->getTouchSelectionController()->WillHandleTouchEvent(me)) + return; + + switch (event->type()) { + case QEvent::TouchBegin: + m_sendMotionActionDown = true; + m_touchMotionStarted = true; + m_rwhv->getTouchSelectionControllerClient()->onTouchDown(); + break; + case QEvent::TouchUpdate: + m_touchMotionStarted = true; + break; + case QEvent::TouchCancel: + { + // Only process TouchCancel events received following a TouchBegin or TouchUpdate event + if (m_touchMotionStarted) { + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, event->modifiers()); + m_rwhv->processMotionEvent(cancelEvent); + } + + return; + } + case QEvent::TouchEnd: + m_rwhv->getTouchSelectionControllerClient()->onTouchUp(); + break; + default: + break; + } + + if (m_imeInProgress && event->type() == QEvent::TouchBegin) { + m_imeInProgress = false; + // Tell input method to commit the pre-edit string entered so far, and finish the + // composition operation. +#ifdef Q_OS_WIN + // Yes the function name is counter-intuitive, but commit isn't actually implemented + // by the Windows QPA, and reset does exactly what is necessary in this case. + qApp->inputMethod()->reset(); +#else + qApp->inputMethod()->commit(); +#endif + } + + // MEMO for the basis of this logic look into: + // * blink_event_util.cc:ToWebTouchPointState: which is used later to forward touch event + // composed from motion event after gesture recognition + // * gesture_detector.cc:GestureDetector::OnTouchEvent: contains logic for every motion + // event action and corresponding gesture recognition routines + // * input_router_imp.cc:InputRouterImp::SetMovementXYForTouchPoints: expectation about + // touch event content like number of points for different states + + int lastPressIndex = -1; + while ((lastPressIndex + 1) < touchPoints.size() && touchPoints[lastPressIndex + 1].second.state() == Qt::TouchPointPressed) + ++lastPressIndex; + + switch (event->type()) { + case QEvent::TouchBegin: + m_rwhv->processMotionEvent(MotionEventQt(touchPoints.mid(lastPressIndex), + eventTimestamp, ui::MotionEvent::Action::DOWN, event->modifiers())); + --lastPressIndex; + Q_FALLTHROUGH(); + + case QEvent::TouchUpdate: + for (; lastPressIndex >= 0; --lastPressIndex) { + Q_ASSERT(touchPoints[lastPressIndex].second.state() == Qt::TouchPointPressed); + MotionEventQt me(touchPoints.mid(lastPressIndex), eventTimestamp, ui::MotionEvent::Action::POINTER_DOWN, event->modifiers(), 0); + m_rwhv->processMotionEvent(me); + } + + if (event->touchPointStates() & Qt::TouchPointMoved) + m_rwhv->processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, ui::MotionEvent::Action::MOVE, event->modifiers())); + + Q_FALLTHROUGH(); + + case QEvent::TouchEnd: + while (!touchPoints.isEmpty() && touchPoints.back().second.state() == Qt::TouchPointReleased) { + auto action = touchPoints.size() > 1 ? ui::MotionEvent::Action::POINTER_UP : ui::MotionEvent::Action::UP; + int index = action == ui::MotionEvent::Action::POINTER_UP ? touchPoints.size() - 1 : -1; + m_rwhv->processMotionEvent(MotionEventQt(touchPoints, eventTimestamp, action, event->modifiers(), index)); + touchPoints.pop_back(); + } + break; + + default: + Q_ASSERT_X(false, __FUNCTION__, "Other event types are expected to be already handled."); + break; + } +} + +#if QT_CONFIG(tabletevent) +void RenderWidgetHostViewQtDelegateClient::handleTabletEvent(QTabletEvent *event) +{ + handlePointerEvent<QTabletEvent>(event); +} +#endif + +#if QT_CONFIG(gestures) +void RenderWidgetHostViewQtDelegateClient::handleGestureEvent(QNativeGestureEvent *event) +{ + const Qt::NativeGestureType type = event->gestureType(); + // These are the only supported gestures by Chromium so far. + if (type == Qt::ZoomNativeGesture || type == Qt::SmartZoomNativeGesture) { + auto *hostDelegate = m_rwhv->host()->delegate(); + if (hostDelegate && hostDelegate->GetInputEventRouter()) { + auto webEvent = WebEventFactory::toWebGestureEvent(event); + hostDelegate->GetInputEventRouter()->RouteGestureEvent(m_rwhv, &webEvent, ui::LatencyInfo()); + } + } +} +#endif + +void RenderWidgetHostViewQtDelegateClient::handleHoverEvent(QHoverEvent *event) +{ + auto *hostDelegate = m_rwhv->host()->delegate(); + if (hostDelegate && hostDelegate->GetInputEventRouter()) { + auto webEvent = WebEventFactory::toWebMouseEvent(event); + hostDelegate->GetInputEventRouter()->RouteMouseEvent(m_rwhv, &webEvent, ui::LatencyInfo()); + } +} + +void RenderWidgetHostViewQtDelegateClient::handleFocusEvent(QFocusEvent *event) +{ + if (event->gotFocus()) { + m_rwhv->host()->GotFocus(); + m_rwhv->host()->SetActive(true); + content::RenderViewHostImpl *rvh = content::RenderViewHostImpl::From(m_rwhv->host()); + Q_ASSERT(rvh); + if (event->reason() == Qt::TabFocusReason) + rvh->SetInitialFocus(false); + else if (event->reason() == Qt::BacktabFocusReason) + rvh->SetInitialFocus(true); + event->accept(); + + m_rwhv->adapterClient()->webContentsAdapter()->handlePendingMouseLockPermission(); + } else if (event->lostFocus()) { + m_rwhv->host()->SetActive(false); + m_rwhv->host()->LostFocus(); + event->accept(); + } +} + +void RenderWidgetHostViewQtDelegateClient::handleInputMethodEvent(QInputMethodEvent *event) +{ + m_rwhv->resetInputManagerState(); + + if (!m_rwhv->host()) + return; + + QString commitString = event->commitString(); + QString preeditString = event->preeditString(); + + int cursorPositionInPreeditString = -1; + gfx::Range selectionRange = gfx::Range::InvalidRange(); + + const QList<QInputMethodEvent::Attribute> &attributes = event->attributes(); + std::vector<ui::ImeTextSpan> underlines; + bool hasSelection = false; + + for (const auto &attribute : attributes) { + switch (attribute.type) { + case QInputMethodEvent::TextFormat: { + if (preeditString.isEmpty()) + break; + + int start = qMin(attribute.start, (attribute.start + attribute.length)); + int end = qMax(attribute.start, (attribute.start + attribute.length)); + + // Blink does not support negative position values. Adjust start and end positions + // to non-negative values. + if (start < 0) { + start = 0; + end = qMax(0, start + end); + } + + underlines.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, start, end, + ui::ImeTextSpan::Thickness::kThin, + ui::ImeTextSpan::UnderlineStyle::kSolid, + SK_ColorTRANSPARENT)); + + QTextCharFormat format = qvariant_cast<QTextFormat>(attribute.value).toCharFormat(); + if (format.underlineStyle() != QTextCharFormat::NoUnderline) + underlines.back().underline_color = toSk(format.underlineColor()); + + break; + } + case QInputMethodEvent::Cursor: + // Always set the position of the cursor, even if it's marked invisible by Qt, otherwise + // there is no way the user will know which part of the composition string will be + // changed, when performing an IME-specific action (like selecting a different word + // suggestion). + cursorPositionInPreeditString = attribute.start; + break; + case QInputMethodEvent::Selection: + hasSelection = true; + + // Cancel IME composition + if (preeditString.isEmpty() && attribute.start + attribute.length == 0) { + selectionRange.set_start(0); + selectionRange.set_end(0); + break; + } + + selectionRange.set_start(qMin(attribute.start, (attribute.start + attribute.length))); + selectionRange.set_end(qMax(attribute.start, (attribute.start + attribute.length))); + break; + default: + break; + } + } + + if (!selectionRange.IsValid()) { + // We did not receive a valid selection range, hence the range is going to mark the + // cursor position. + int newCursorPosition = (cursorPositionInPreeditString < 0) ? preeditString.length() + : cursorPositionInPreeditString; + selectionRange.set_start(newCursorPosition); + selectionRange.set_end(newCursorPosition); + } + + if (hasSelection) { + if (auto *frameWidgetInputHandler = m_rwhv->getFrameWidgetInputHandler()) + frameWidgetInputHandler->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); + } + + int replacementLength = event->replacementLength(); + gfx::Range replacementRange = gfx::Range::InvalidRange(); + + if (replacementLength > 0) { + int replacementStart = event->replacementStart() < 0 + ? m_cursorPosition + event->replacementStart() + : event->replacementStart(); + if (replacementStart >= 0 && replacementStart < m_surroundingText.length()) + replacementRange = gfx::Range(replacementStart, replacementStart + replacementLength); + } + + // There are so-far two known cases, when an empty QInputMethodEvent is received. + // First one happens when backspace is used to remove the last character in the pre-edit + // string, thus signaling the end of the composition. + // The second one happens (on Windows) when a Korean char gets composed, but instead of + // the event having a commit string, both strings are empty, and the actual char is received + // as a QKeyEvent after the QInputMethodEvent is processed. + // In lieu of the second case, we can't simply cancel the composition on an empty event, + // and then add the Korean char when QKeyEvent is received, because that leads to text + // flickering in the textarea (or any other element). + // Instead we postpone the processing of the empty QInputMethodEvent by posting it + // to the same focused object, and cancelling the composition on the next event loop tick. + if (commitString.isEmpty() && preeditString.isEmpty() && replacementLength == 0) { + if (!m_receivedEmptyImeEvent && m_imeInProgress && !hasSelection) { + m_receivedEmptyImeEvent = true; + QGuiApplication::postEvent(qApp->focusObject(), event->clone()); + } else { + m_receivedEmptyImeEvent = false; + if (m_imeInProgress) { + m_imeInProgress = false; + m_rwhv->host()->ImeCancelComposition(); + } + } + + return; + } + + m_receivedEmptyImeEvent = false; + + // Finish compostion: insert or erase text. + if (!commitString.isEmpty() || replacementLength > 0) { + m_rwhv->host()->ImeCommitText(toString16(commitString), underlines, replacementRange, 0); + m_imeInProgress = false; + } + + // Update or start new composition. + // Be aware of that, we might get a commit string and a pre-edit string in a single event and + // this means a new composition. + if (!preeditString.isEmpty()) { + m_rwhv->host()->ImeSetComposition(toString16(preeditString), underlines, replacementRange, + selectionRange.start(), selectionRange.end()); + m_imeInProgress = true; + } +} + +void RenderWidgetHostViewQtDelegateClient::handleInputMethodQueryEvent( + QInputMethodQueryEvent *event) +{ + Qt::InputMethodQueries queries = event->queries(); + for (uint i = 0; i < 32; ++i) { + Qt::InputMethodQuery query = (Qt::InputMethodQuery)(int)(queries & (1 << i)); + if (query) { + QVariant v = inputMethodQuery(query); + event->setValue(query, v); + } + } + event->accept(); +} + +void RenderWidgetHostViewQtDelegateClient::clearPreviousTouchMotionState() +{ + m_previousTouchPoints.clear(); + m_touchMotionStarted = false; +} + +void RenderWidgetHostViewQtDelegateClient::selectionChanged() +{ + m_rwhv->resetInputManagerState(); + ui::TextInputType type = m_rwhv->getTextInputType(); + content::TextInputManager *text_input_manager = m_rwhv->GetTextInputManager(); + + // Handle text selection out of an input field + if (type == ui::TEXT_INPUT_TYPE_NONE) { + if (m_rwhv->GetSelectedText().empty() && m_emptyPreviousSelection) + return; + + // Reset position values to emit selectionChanged signal when clearing text selection + // by clicking into an input field. These values are intended to be used by inputMethodQuery + // so they are not expected to be valid when selection is out of an input field. + m_anchorPositionWithinSelection = -1; + m_cursorPositionWithinSelection = -1; + + m_emptyPreviousSelection = m_rwhv->GetSelectedText().empty(); + m_rwhv->adapterClient()->selectionChanged(); + return; + } + + if (m_rwhv->GetSelectedText().empty()) { + // RenderWidgetHostViewQt::OnUpdateTextInputStateCalled() does not update the cursor + // position if the selection is cleared because TextInputState changes before the + // TextSelection change. + Q_ASSERT(text_input_manager->GetTextInputState()); + m_cursorPosition = text_input_manager->GetTextInputState()->selection.start(); + m_rwhv->delegate()->inputMethodStateChanged(true /*editorVisible*/, + type == ui::TEXT_INPUT_TYPE_PASSWORD); + + m_anchorPositionWithinSelection = m_cursorPosition; + m_cursorPositionWithinSelection = m_cursorPosition; + + if (!m_emptyPreviousSelection) { + m_emptyPreviousSelection = true; + m_rwhv->adapterClient()->selectionChanged(); + } + + return; + } + + const content::TextInputManager::TextSelection *selection = + text_input_manager->GetTextSelection(); + if (!selection) + return; + + if (!selection->range().IsValid()) + return; + + int newAnchorPositionWithinSelection = 0; + int newCursorPositionWithinSelection = 0; + + if (text_input_manager->GetSelectionRegion()->anchor.type() == gfx::SelectionBound::RIGHT) { + newAnchorPositionWithinSelection = selection->range().GetMax() - selection->offset(); + newCursorPositionWithinSelection = selection->range().GetMin() - selection->offset(); + } else { + newAnchorPositionWithinSelection = selection->range().GetMin() - selection->offset(); + newCursorPositionWithinSelection = selection->range().GetMax() - selection->offset(); + } + + if (m_anchorPositionWithinSelection == newAnchorPositionWithinSelection + && m_cursorPositionWithinSelection == newCursorPositionWithinSelection) { + return; + } + + m_anchorPositionWithinSelection = newAnchorPositionWithinSelection; + m_cursorPositionWithinSelection = newCursorPositionWithinSelection; + + if (!selection->selected_text().empty()) + m_cursorPosition = newCursorPositionWithinSelection; + + m_emptyPreviousSelection = selection->selected_text().empty(); + m_rwhv->delegate()->inputMethodStateChanged(true /*editorVisible*/, + type == ui::TEXT_INPUT_TYPE_PASSWORD); + m_rwhv->adapterClient()->selectionChanged(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate_client.h b/src/core/render_widget_host_view_qt_delegate_client.h new file mode 100644 index 000000000..4ba5da227 --- /dev/null +++ b/src/core/render_widget_host_view_qt_delegate_client.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H +#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H + +#include "compositor/compositor.h" + +#include <QtGui/QCursor> +#include <QtGui/QTouchEvent> + +QT_BEGIN_NAMESPACE +class QEvent; +class QVariant; +class QMouseEvent; +class QKeyEvent; +class QTabletEvent; +class QNativeGestureEvent; +class QHoverEvent; +class QFocusEvent; +class QInputMethodEvent; +class QInputMethodQueryEvent; +QT_END_NAMESPACE + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQt; + +struct MultipleMouseClickHelper +{ + QPoint lastPressPosition; + Qt::MouseButton lastPressButton = Qt::NoButton; + int clickCounter = 0; + ulong lastPressTimestamp = 0; +}; + +class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient +{ +public: + RenderWidgetHostViewQtDelegateClient(RenderWidgetHostViewQt *rwhv); + + Compositor::Id compositorId(); + void notifyShown(); + void notifyHidden(); + void visualPropertiesChanged(); + bool forwardEvent(QEvent *); + QVariant inputMethodQuery(Qt::InputMethodQuery query); + void closePopup(); + +private: + friend class RenderWidgetHostViewQt; + + template<class T> + void handlePointerEvent(T *); + void handleMouseEvent(QMouseEvent *); + void handleKeyEvent(QKeyEvent *); + void handleTouchEvent(QTouchEvent *); +#if QT_CONFIG(tabletevent) + void handleTabletEvent(QTabletEvent *); +#endif +#if QT_CONFIG(gestures) + void handleGestureEvent(QNativeGestureEvent *); +#endif + void handleHoverEvent(QHoverEvent *); + void handleFocusEvent(QFocusEvent *); + void handleInputMethodEvent(QInputMethodEvent *); + void handleInputMethodQueryEvent(QInputMethodQueryEvent *); + + QRect viewRectInDips() const { return m_viewRectInDips; } + QRect windowRectInDips() const { return m_windowRectInDips; } + + // Mouse + void resetPreviousMousePosition() { m_previousMousePosition = QCursor::pos(); } + + // Touch + void clearPreviousTouchMotionState(); + + // IME + void selectionChanged(); + void setCursorPosition(uint pos) { m_cursorPosition = pos; } + void setSurroundingText(const QString &text) { m_surroundingText = text; } + bool isPreviousSelectionEmpty() const { return m_emptyPreviousSelection; } + + RenderWidgetHostViewQt *m_rwhv; + + // Mouse + bool m_imeHasHiddenTextCapability; + uint m_mouseButtonPressed = 0; + QPoint m_previousMousePosition; + MultipleMouseClickHelper m_clickHelper; + + // Key + std::string m_editCommand; + + // Touch + typedef QPair<int, QTouchEvent::TouchPoint> TouchPoint; + QList<TouchPoint> mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &input); + QMap<int, int> m_touchIdMapping; + QList<TouchPoint> m_previousTouchPoints; + bool m_touchMotionStarted = false; + bool m_sendMotionActionDown = false; + int64_t m_eventsToNowDelta = 0; // delta for first touch in microseconds + + // IME + bool m_receivedEmptyImeEvent = false; + bool m_imeInProgress = false; + bool m_emptyPreviousSelection = true; + uint m_cursorPosition = 0; + int m_anchorPositionWithinSelection = -1; + int m_cursorPositionWithinSelection = -1; + QString m_surroundingText; + + // Geometry of the view in screen DIPs. + QRect m_viewRectInDips; + // Geometry of the window, including frame, in screen DIPs. + QRect m_windowRectInDips; +}; + +} // namespace QtWebEngineCore + +#endif // RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_CLIENT_H diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 317fde8f7..ed7f98f23 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -71,7 +71,6 @@ #include "third_party/blink/public/platform/web_url_error.h" #include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/web/web_security_policy.h" -#include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/webui/jstemplate_builder.h" @@ -151,7 +150,7 @@ void ContentRendererClientQt::RenderThreadStarted() // Allow XMLHttpRequests from qrc to file. // ### consider removing for Qt6 - blink::WebURL qrc(blink::KURL("qrc:")); + blink::WebURL qrc(GURL("qrc:")); blink::WebString file(blink::WebString::FromASCII("file")); blink::WebSecurityPolicy::AddOriginAccessAllowListEntry( qrc, file, blink::WebString(), 0, network::mojom::CorsDomainMatchMode::kAllowSubdomains, @@ -160,7 +159,7 @@ void ContentRendererClientQt::RenderThreadStarted() #if BUILDFLAG(ENABLE_EXTENSIONS) // Allow the pdf viewer extension to access chrome resources - blink::WebURL pdfViewerExtension(blink::KURL("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai")); + blink::WebURL pdfViewerExtension(GURL("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai")); blink::WebString chromeResources(blink::WebString::FromASCII("chrome")); blink::WebSecurityPolicy::AddOriginAccessAllowListEntry( pdfViewerExtension, chromeResources, blink::WebString(), 0, @@ -301,7 +300,7 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF const error_page::Error &error, std::string *errorHtml) { - Q_UNUSED(renderFrame) + Q_UNUSED(renderFrame); const bool isPost = QByteArray::fromStdString(httpMethod) == QByteArrayLiteral("POST"); if (errorHtml) { diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp index c7b220fe6..af1f234ac 100644 --- a/src/core/renderer/user_resource_controller.cpp +++ b/src/core/renderer/user_resource_controller.cpp @@ -198,8 +198,8 @@ void UserResourceController::runScripts(QtWebEngineCore::UserScriptData::Injecti return; const bool isMainFrame = renderFrame->IsMainFrame(); - QList<uint64_t> scriptsToRun = m_frameUserScriptMap.value(globalScriptsIndex).toList(); - scriptsToRun.append(m_frameUserScriptMap.value(renderFrame).toList()); + QList<uint64_t> scriptsToRun = m_frameUserScriptMap.value(globalScriptsIndex).values(); + scriptsToRun.append(m_frameUserScriptMap.value(renderFrame).values()); for (uint64_t id : qAsConst(scriptsToRun)) { const QtWebEngineCore::UserScriptData &script = m_scripts.value(id); diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp index 520c492ea..1efefc1d0 100644 --- a/src/core/renderer/web_channel_ipc_transport.cpp +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -153,19 +153,9 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) return; } v8::Local<v8::String> jsonString = v8::Local<v8::String>::Cast(jsonValue); - - QByteArray json(jsonString->Utf8Length(isolate), 0); - jsonString->WriteUtf8(isolate, json.data(), json.size(), nullptr, v8::String::REPLACE_INVALID_UTF8); - - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(json, &error); - if (error.error != QJsonParseError::NoError) { - args->ThrowTypeError("Invalid JSON"); - return; - } - - int size = 0; - const char *rawData = doc.rawData(&size); + std::vector<uint8_t> json(jsonString->Utf8Length(isolate), 0); + jsonString->WriteUtf8(isolate, reinterpret_cast<char *>(json.data()), json.size(), nullptr, + v8::String::REPLACE_INVALID_UTF8); if (!m_remote) { renderFrame->GetRemoteAssociatedInterfaces()->GetInterface(&m_remote); @@ -173,7 +163,7 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) } DCHECK(renderFrame == m_renderFrame); - m_remote->DispatchWebChannelMessage(std::vector<uint8_t>(rawData, rawData + size)); + m_remote->DispatchWebChannelMessage(json); } gin::ObjectTemplateBuilder WebChannelTransport::GetObjectTemplateBuilder(v8::Isolate *isolate) @@ -222,18 +212,14 @@ void WebChannelIPCTransport::ResetWorldId() m_worldId = 0; } -void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson, uint32_t worldId) +void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t> &json, + uint32_t worldId) { DCHECK(m_worldId == worldId); if (!m_canUseContext) return; - QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()), binaryJson.size(), - QJsonDocument::BypassValidation); - DCHECK(doc.isObject()); - QByteArray json = doc.toJson(QJsonDocument::Compact); - blink::WebLocalFrame *frame = render_frame()->GetWebFrame(); v8::Isolate *isolate = blink::MainThreadIsolate(); v8::HandleScope handleScope(isolate); @@ -264,7 +250,9 @@ void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t v8::Local<v8::Object> messageObject(v8::Object::New(isolate)); v8::Maybe<bool> wasSet = messageObject->DefineOwnProperty( context, v8::String::NewFromUtf8(isolate, "data").ToLocalChecked(), - v8::String::NewFromUtf8(isolate, json.constData(), v8::NewStringType::kNormal, json.size()).ToLocalChecked(), + v8::String::NewFromUtf8(isolate, reinterpret_cast<const char *>(json.data()), + v8::NewStringType::kNormal, json.size()) + .ToLocalChecked(), v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); DCHECK(!wasSet.IsNothing() && wasSet.FromJust()); diff --git a/src/core/renderer/web_channel_ipc_transport.h b/src/core/renderer/web_channel_ipc_transport.h index 4bed5f26d..276167a67 100644 --- a/src/core/renderer/web_channel_ipc_transport.h +++ b/src/core/renderer/web_channel_ipc_transport.h @@ -61,7 +61,7 @@ private: // qtwebchannel::mojom::WebChannelTransportRender void SetWorldId(uint32_t worldId) override; void ResetWorldId() override; - void DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson, uint32_t worldId) override; + void DispatchWebChannelMessage(const std::vector<uint8_t> &json, uint32_t worldId) override; // RenderFrameObserver void WillReleaseScriptContext(v8::Local<v8::Context> context, int worldId) override; diff --git a/src/core/renderer_host/user_resource_controller_host.cpp b/src/core/renderer_host/user_resource_controller_host.cpp index cea246c37..58559848f 100644 --- a/src/core/renderer_host/user_resource_controller_host.cpp +++ b/src/core/renderer_host/user_resource_controller_host.cpp @@ -129,8 +129,6 @@ void UserResourceControllerHost::RenderProcessObserverHelper::RenderProcessHostD void UserResourceControllerHost::addUserScript(const UserScript &script, WebContentsAdapter *adapter) { - if (script.isNull()) - return; // Global scripts should be dispatched to all our render processes. const bool isProfileWideScript = !adapter; if (isProfileWideScript) { @@ -161,8 +159,6 @@ void UserResourceControllerHost::addUserScript(const UserScript &script, WebCont bool UserResourceControllerHost::removeUserScript(const UserScript &script, WebContentsAdapter *adapter) { - if (script.isNull()) - return false; const bool isProfileWideScript = !adapter; if (isProfileWideScript) { QList<UserScript>::iterator it = std::find(m_profileWideScripts.begin(), m_profileWideScripts.end(), script); diff --git a/src/core/renderer_host/user_resource_controller_host.h b/src/core/renderer_host/user_resource_controller_host.h index 8b6099dcf..a88264f2d 100644 --- a/src/core/renderer_host/user_resource_controller_host.h +++ b/src/core/renderer_host/user_resource_controller_host.h @@ -78,6 +78,7 @@ class UserResourceControllerRenderFrame; namespace QtWebEngineCore { +class UserScript; using UserResourceControllerRemote = mojo::AssociatedRemote<qtwebengine::mojom::UserResourceController>; using UserResourceControllerRenderFrameRemote = mojo::AssociatedRemote<qtwebengine::mojom::UserResourceControllerRenderFrame>; class WebContentsAdapter; diff --git a/src/core/renderer_host/web_channel_ipc_transport_host.cpp b/src/core/renderer_host/web_channel_ipc_transport_host.cpp index 087e0e83b..ca6fb895e 100644 --- a/src/core/renderer_host/web_channel_ipc_transport_host.cpp +++ b/src/core/renderer_host/web_channel_ipc_transport_host.cpp @@ -93,12 +93,11 @@ uint WebChannelIPCTransportHost::worldId() const void WebChannelIPCTransportHost::sendMessage(const QJsonObject &message) { QJsonDocument doc(message); - int size = 0; - const char *rawData = doc.rawData(&size); + QByteArray json = doc.toJson(QJsonDocument::Compact); content::RenderFrameHost *frame = web_contents()->GetMainFrame(); qCDebug(log).nospace() << "sending webchannel message to " << frame << ": " << doc; GetWebChannelIPCTransportRemote(frame)->DispatchWebChannelMessage( - std::vector<uint8_t>(rawData, rawData + size), m_worldId); + std::vector<uint8_t>(json.begin(), json.end()), m_worldId); } void WebChannelIPCTransportHost::setWorldId(uint32_t worldId) @@ -127,7 +126,7 @@ void WebChannelIPCTransportHost::resetWorldId() } } -void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson) +void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uint8_t> &json) { content::RenderFrameHost *frame = web_contents()->GetMainFrame(); @@ -135,7 +134,8 @@ void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uin return; } - QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()), binaryJson.size()); + QJsonDocument doc = QJsonDocument::fromJson( + QByteArray(reinterpret_cast<const char *>(json.data()), json.size())); if (!doc.isObject()) { qCCritical(log).nospace() << "received invalid webchannel message from " << frame; diff --git a/src/core/renderer_host/web_channel_ipc_transport_host.h b/src/core/renderer_host/web_channel_ipc_transport_host.h index d06483ee6..794238667 100644 --- a/src/core/renderer_host/web_channel_ipc_transport_host.h +++ b/src/core/renderer_host/web_channel_ipc_transport_host.h @@ -71,7 +71,6 @@ public: private: void setWorldId(content::RenderFrameHost *frame, uint32_t worldId); void resetWorldId(); - void onWebChannelMessage(const std::vector<char> &message); const mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportRender> & GetWebChannelIPCTransportRemote(content::RenderFrameHost *rfh); @@ -81,7 +80,7 @@ private: void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override; // qtwebchannel::mojom::WebChannelTransportHost - void DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson) override; + void DispatchWebChannelMessage(const std::vector<uint8_t> &json) override; // Empty only during construction/destruction. Synchronized to all the // WebChannelIPCTransports/RenderFrames in the observed WebContents. diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index 3723f97ea..a4cc57b76 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -311,4 +311,40 @@ QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate) return chain; } +Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType) +{ + switch (inputType) { + case ui::TEXT_INPUT_TYPE_TEXT: + return Qt::ImhPreferLowercase; + case ui::TEXT_INPUT_TYPE_SEARCH: + return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_TYPE_PASSWORD: + return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase + | Qt::ImhHiddenText; + case ui::TEXT_INPUT_TYPE_EMAIL: + return Qt::ImhEmailCharactersOnly; + case ui::TEXT_INPUT_TYPE_NUMBER: + return Qt::ImhFormattedNumbersOnly; + case ui::TEXT_INPUT_TYPE_TELEPHONE: + return Qt::ImhDialableCharactersOnly; + case ui::TEXT_INPUT_TYPE_URL: + return Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase; + case ui::TEXT_INPUT_TYPE_DATE_TIME: + case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL: + case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD: + return Qt::ImhDate | Qt::ImhTime; + case ui::TEXT_INPUT_TYPE_DATE: + case ui::TEXT_INPUT_TYPE_MONTH: + case ui::TEXT_INPUT_TYPE_WEEK: + return Qt::ImhDate; + case ui::TEXT_INPUT_TYPE_TIME: + return Qt::ImhTime; + case ui::TEXT_INPUT_TYPE_TEXT_AREA: + case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE: + return Qt::ImhMultiLine | Qt::ImhPreferLowercase; + default: + return Qt::ImhNone; + } +} + } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 1152ed9a9..85fd763b4 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -59,6 +59,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPixelRef.h" #include "third_party/skia/include/core/SkMatrix44.h" +#include "ui/base/ime/text_input_type.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" @@ -79,9 +80,9 @@ namespace QtWebEngineCore { inline QString toQt(const base::string16 &string) { #if defined(OS_WIN) - return QString::fromStdWString(string.data()); + return QString::fromStdWString(string); #else - return QString::fromUtf16(string.data()); + return QString::fromUtf16(reinterpret_cast<const char16_t *>(string.data()), string.size()); #endif } @@ -275,6 +276,8 @@ FaviconInfo toFaviconInfo(const blink::mojom::FaviconURLPtr &favicon_url); QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate); +Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType); + } // namespace QtWebEngineCore #endif // TYPE_CONVERSION_H diff --git a/src/core/user_script.cpp b/src/core/user_script.cpp index f4daaf7c6..1c8a78cd3 100644 --- a/src/core/user_script.cpp +++ b/src/core/user_script.cpp @@ -72,30 +72,19 @@ ASSERT_ENUMS_MATCH(UserScript::DocumentElementCreation, UserScriptData::Document UserScript::UserScript() : QSharedData() { + static uint64_t idCount = 0; + m_scriptData.scriptId = idCount++; } -UserScript::UserScript(const UserScript &other) - : QSharedData(other) -{ - if (other.isNull()) - return; - scriptData.reset(new UserScriptData(*other.scriptData)); - m_name = other.m_name; -} +UserScript::UserScript(const UserScript &other) = default; -UserScript::~UserScript() -{ -} +UserScript::~UserScript() = default; UserScript &UserScript::operator=(const UserScript &other) { - if (other.isNull()) { - scriptData.reset(); - m_name = QString(); - return *this; - } - scriptData.reset(new UserScriptData(*other.scriptData)); + m_scriptData = other.m_scriptData; m_name = other.m_name; + m_url = other.m_url; return *this; } @@ -107,104 +96,82 @@ QString UserScript::name() const void UserScript::setName(const QString &name) { m_name = name; - initData(); - scriptData->url = GURL(QStringLiteral("userScript:%1").arg(name).toStdString()); + m_scriptData.url = GURL(QStringLiteral("userScript:%1").arg(name).toStdString()); } QString UserScript::sourceCode() const { - if (isNull()) - return QString(); - return toQt(scriptData->source); + return toQt(m_scriptData.source); } void UserScript::setSourceCode(const QString &source) { - initData(); - scriptData->source = source.toStdString(); + m_scriptData.source = source.toStdString(); parseMetadataHeader(); } -UserScript::InjectionPoint UserScript::injectionPoint() const +QUrl UserScript::sourceUrl() const { - if (isNull()) - return UserScript::AfterLoad; - return static_cast<UserScript::InjectionPoint>(scriptData->injectionPoint); + return m_url; } -void UserScript::setInjectionPoint(UserScript::InjectionPoint p) +void UserScript::setSourceUrl(const QUrl &url) { - initData(); - scriptData->injectionPoint = p; + m_url = url; } -uint UserScript::worldId() const +UserScript::InjectionPoint UserScript::injectionPoint() const { - if (isNull()) - return 1; - return scriptData->worldId; + return static_cast<UserScript::InjectionPoint>(m_scriptData.injectionPoint); } -void UserScript::setWorldId(uint id) +void UserScript::setInjectionPoint(UserScript::InjectionPoint p) { - initData(); - scriptData->worldId = id; + m_scriptData.injectionPoint = p; } -bool UserScript::runsOnSubFrames() const +quint32 UserScript::worldId() const { - if (isNull()) - return false; - return scriptData->injectForSubframes; + return m_scriptData.worldId; } -void UserScript::setRunsOnSubFrames(bool on) +void UserScript::setWorldId(quint32 id) { - initData(); - scriptData->injectForSubframes = on; + m_scriptData.worldId = id; } -bool UserScript::operator==(const UserScript &other) const +bool UserScript::runsOnSubFrames() const { - if (isNull() != other.isNull()) - return false; - if (isNull()) // neither is valid - return true; - return worldId() == other.worldId() - && runsOnSubFrames() == other.runsOnSubFrames() - && injectionPoint() == other.injectionPoint() - && name() == other.name() && sourceCode() == other.sourceCode(); + return m_scriptData.injectForSubframes; } -void UserScript::initData() +void UserScript::setRunsOnSubFrames(bool on) { - static uint64_t idCount = 0; - if (scriptData.isNull()) { - scriptData.reset(new UserScriptData); - scriptData->scriptId = idCount++; - } + m_scriptData.injectForSubframes = on; } -bool UserScript::isNull() const +const UserScriptData &UserScript::data() const { - return scriptData.isNull(); + return m_scriptData; } -UserScriptData &UserScript::data() const +bool UserScript::operator==(const UserScript &other) const { - return *(scriptData.data()); + return worldId() == other.worldId() && runsOnSubFrames() == other.runsOnSubFrames() + && injectionPoint() == other.injectionPoint() && name() == other.name() + && sourceCode() == other.sourceCode() && sourceUrl() == other.sourceUrl(); } void UserScript::parseMetadataHeader() { // Clear previous values - scriptData->globs.clear(); - scriptData->excludeGlobs.clear(); - scriptData->urlPatterns.clear(); + m_scriptData.globs.clear(); + m_scriptData.excludeGlobs.clear(); + m_scriptData.urlPatterns.clear(); // Logic taken from Chromium (extensions/browser/user_script_loader.cc) // http://wiki.greasespot.net/Metadata_block - const std::string &script_text = scriptData->source; + const std::string &script_text = m_scriptData.source; base::StringPiece line; size_t line_start = 0; size_t line_end = line_start; @@ -250,7 +217,7 @@ void UserScript::parseMetadataHeader() base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\"); base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?"); } - scriptData->globs.push_back(value); + m_scriptData.globs.push_back(value); } else if (GetDeclarationValue(line, kExcludeDeclaration, &value)) { if (value.front() != '/' || value.back() != '/') { // The greasemonkey spec only allows for wildcards (*), so @@ -258,16 +225,16 @@ void UserScript::parseMetadataHeader() base::ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\"); base::ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?"); } - scriptData->excludeGlobs.push_back(value); + m_scriptData.excludeGlobs.push_back(value); } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) { - scriptData->urlPatterns.push_back(value); + m_scriptData.urlPatterns.push_back(value); } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) { if (value == kRunAtDocumentStartValue) - scriptData->injectionPoint = DocumentElementCreation; + m_scriptData.injectionPoint = DocumentElementCreation; else if (value == kRunAtDocumentEndValue) - scriptData->injectionPoint = DocumentLoadFinished; + m_scriptData.injectionPoint = DocumentLoadFinished; else if (value == kRunAtDocumentIdleValue) - scriptData->injectionPoint = AfterLoad; + m_scriptData.injectionPoint = AfterLoad; } } @@ -276,8 +243,8 @@ void UserScript::parseMetadataHeader() // If no patterns were specified, default to @include *. This is what // Greasemonkey does. - if (scriptData->globs.empty() && scriptData->urlPatterns.empty()) - scriptData->globs.push_back("*"); + if (m_scriptData.globs.empty() && m_scriptData.urlPatterns.empty()) + m_scriptData.globs.push_back("*"); } } // namespace QtWebEngineCore diff --git a/src/core/user_script.h b/src/core/user_script.h index e06141259..2be1b4ed0 100644 --- a/src/core/user_script.h +++ b/src/core/user_script.h @@ -53,16 +53,19 @@ #include "qtwebenginecoreglobal_p.h" +#include "qtwebengine/userscript/user_script_data.h" + #include <QtCore/QScopedPointer> #include <QtCore/QSharedData> #include <QtCore/QString> +#include <QtCore/QUrl> namespace QtWebEngineCore { -struct UserScriptData; class UserResourceControllerHost; -class Q_WEBENGINECORE_PRIVATE_EXPORT UserScript : public QSharedData { +class UserScript : public QSharedData +{ public: enum InjectionPoint { AfterLoad, @@ -75,19 +78,20 @@ public: ~UserScript(); UserScript &operator=(const UserScript &other); - bool isNull() const; - QString name() const; void setName(const QString &); QString sourceCode() const; void setSourceCode(const QString &); + QUrl sourceUrl() const; + void setSourceUrl(const QUrl &); + InjectionPoint injectionPoint() const; void setInjectionPoint(InjectionPoint); - uint worldId() const; - void setWorldId(uint id); + quint32 worldId() const; + void setWorldId(quint32 id); bool runsOnSubFrames() const; void setRunsOnSubFrames(bool on); @@ -95,13 +99,13 @@ public: bool operator==(const UserScript &) const; private: - void initData(); - UserScriptData &data() const; + const UserScriptData &data() const; void parseMetadataHeader(); friend class UserResourceControllerHost; - QScopedPointer<UserScriptData> scriptData; + UserScriptData m_scriptData; QString m_name; + QUrl m_url; }; } // namespace QtWebEngineCore diff --git a/src/core/visited_links_manager_qt.h b/src/core/visited_links_manager_qt.h index c4e24ce1f..27d46f8ff 100644 --- a/src/core/visited_links_manager_qt.h +++ b/src/core/visited_links_manager_qt.h @@ -55,9 +55,7 @@ #include <QList> #include <QScopedPointer> -QT_BEGIN_NAMESPACE -class QUrl; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QUrl) namespace visitedlink { class VisitedLinkWriter; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index bfeab41a2..0f41a53cb 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -119,6 +119,7 @@ #include <QtCore/qmimedata.h> #include <QtCore/qtemporarydir.h> #include <QtGui/qdrag.h> +#include <QtGui/QDragEnterEvent> #include <QtGui/qpixmap.h> // Can't include headers as qaccessible.h conflicts with Chromium headers. @@ -490,7 +491,7 @@ void WebContentsAdapter::setClient(WebContentsAdapterClient *adapterClient) Q_ASSERT(m_profileAdapter); // This might replace any adapter that has been initialized with this WebEngineSettings. - adapterClient->webEngineSettings()->setWebContentsAdapter(this); + WebEngineSettings::get(adapterClient->webEngineSettings())->setWebContentsAdapter(this); } bool WebContentsAdapter::isInitialized() const @@ -566,7 +567,8 @@ void WebContentsAdapter::initializeRenderPrefs() commandLine->GetSwitchValueASCII(switches::kForceWebRtcIPHandlingPolicy); else rendererPrefs->webrtc_ip_handling_policy = - m_adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly) + m_adapterClient->webEngineSettings()->testAttribute( + QWebEngineSettings::WebRTCPublicInterfacesOnly) ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly : blink::kWebRTCIPHandlingDefault; #endif @@ -622,7 +624,7 @@ void WebContentsAdapter::reload() bool wasDiscarded = (m_lifecycleState == LifecycleState::Discarded); setLifecycleState(LifecycleState::Active); CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); + WebEngineSettings *settings = WebEngineSettings::get(m_adapterClient->webEngineSettings()); settings->doApply(); if (!wasDiscarded) // undiscard() already triggers a reload m_webContents->GetController().Reload(content::ReloadType::NORMAL, /*checkRepost = */false); @@ -637,7 +639,7 @@ void WebContentsAdapter::reloadAndBypassCache() bool wasDiscarded = (m_lifecycleState == LifecycleState::Discarded); setLifecycleState(LifecycleState::Active); CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); + WebEngineSettings *settings = WebEngineSettings::get(m_adapterClient->webEngineSettings()); settings->doApply(); if (!wasDiscarded) // undiscard() already triggers a reload m_webContents->GetController().Reload(content::ReloadType::BYPASSING_CACHE, /*checkRepost = */false); @@ -670,8 +672,7 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); - settings->doApply(); + WebEngineSettings::get(m_adapterClient->webEngineSettings())->doApply(); // The situation can occur when relying on the editingFinished signal in QML to set the url // of the WebView. @@ -726,8 +727,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) } // convert the custom headers into the format that chromium expects - QVector<QByteArray> headers = request.headers(); - for (QVector<QByteArray>::const_iterator it = headers.cbegin(); it != headers.cend(); ++it) { + QList<QByteArray> headers = request.headers(); + for (QList<QByteArray>::const_iterator it = headers.cbegin(); it != headers.cend(); ++it) { if (params.extra_headers.length() > 0) params.extra_headers += '\n'; params.extra_headers += (*it).toStdString() + ": " + request.header(*it).toStdString(); @@ -759,8 +760,7 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT CHECK_VALID_RENDER_WIDGET_HOST_VIEW(m_webContents->GetRenderViewHost()); - WebEngineSettings *settings = m_adapterClient->webEngineSettings(); - settings->doApply(); + WebEngineSettings::get(m_adapterClient->webEngineSettings())->doApply(); QByteArray encodedData = data.toPercentEncoding(); std::string urlString; @@ -1131,7 +1131,6 @@ void WebContentsAdapter::download(const QUrl &url, const QString &suggestedFileN if (!dlm) return; - dlmd->markNextDownloadAsUserRequested(); dlm->SetDelegate(dlmd); net::NetworkTrafficAnnotationTag traffic_annotation = @@ -1669,19 +1668,19 @@ void WebContentsAdapter::enterDrag(QDragEnterEvent *e, const QPointF &screenPos) content::RenderViewHost *rvh = m_webContents->GetRenderViewHost(); rvh->GetWidget()->FilterDropData(m_currentDropData.get()); - rvh->GetWidget()->DragTargetDragEnter(*m_currentDropData, toGfx(e->posF()), toGfx(screenPos), + rvh->GetWidget()->DragTargetDragEnter(*m_currentDropData, toGfx(e->position()), toGfx(screenPos), toWeb(e->possibleActions()), - toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); + toWeb(e->buttons()) | toWeb(e->modifiers())); } Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const QPointF &screenPos) { CHECK_INITIALIZED(Qt::DropAction()); content::RenderViewHost *rvh = m_webContents->GetRenderViewHost(); - m_lastDragClientPos = e->posF(); + m_lastDragClientPos = e->position(); m_lastDragScreenPos = screenPos; rvh->GetWidget()->DragTargetDragOver(toGfx(m_lastDragClientPos), toGfx(m_lastDragScreenPos), toWeb(e->possibleActions()), - toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); + toWeb(e->buttons()) | toWeb(e->modifiers())); waitForUpdateDragActionCalled(); return toQt(blink::DragOperation(m_currentDropAction)); } @@ -1724,10 +1723,10 @@ void WebContentsAdapter::endDragging(QDropEvent *e, const QPointF &screenPos) CHECK_INITIALIZED(); content::RenderViewHost *rvh = m_webContents->GetRenderViewHost(); rvh->GetWidget()->FilterDropData(m_currentDropData.get()); - m_lastDragClientPos = e->posF(); + m_lastDragClientPos = e->position(); m_lastDragScreenPos = screenPos; rvh->GetWidget()->DragTargetDrop(*m_currentDropData, toGfx(m_lastDragClientPos), toGfx(m_lastDragScreenPos), - toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); + toWeb(e->buttons()) | toWeb(e->modifiers())); m_currentDropData.reset(); } @@ -1752,8 +1751,8 @@ void WebContentsAdapter::replaceMisspelling(const QString &word) void WebContentsAdapter::focusIfNecessary() { CHECK_INITIALIZED(); - const WebEngineSettings *settings = m_adapterClient->webEngineSettings(); - bool focusOnNavigation = settings->testAttribute(WebEngineSettings::FocusOnNavigationEnabled); + const QWebEngineSettings *settings = m_adapterClient->webEngineSettings(); + bool focusOnNavigation = settings->testAttribute(QWebEngineSettings::FocusOnNavigationEnabled); if (focusOnNavigation) m_webContents->Focus(); } diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 78dda6060..ef710579b 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -52,6 +52,7 @@ #define WEB_CONTENTS_ADAPTER_H #include "qtwebenginecoreglobal_p.h" +#include "qwebenginecontextmenurequest_p.h" #include "web_contents_adapter_client.h" #include <memory> #include <QtGui/qtgui-config.h> diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 267266d81..497b94720 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -57,13 +57,10 @@ #include <QFlags> #include <QRect> -#include <QSharedPointer> #include <QString> #include <QStringList> #include <QUrl> -QT_FORWARD_DECLARE_CLASS(CertificateErrorController) -QT_FORWARD_DECLARE_CLASS(ClientCertSelectController) QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QVariant) QT_FORWARD_DECLARE_CLASS(QWebEngineFindTextResult) @@ -71,6 +68,9 @@ QT_FORWARD_DECLARE_CLASS(QWebEngineQuotaRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineRegisterProtocolHandlerRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInfo) QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInterceptor) +QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest) +QT_FORWARD_DECLARE_CLASS(QWebEngineCertificateError); +QT_FORWARD_DECLARE_CLASS(QWebEngineSettings) namespace content { struct DropData; @@ -78,6 +78,8 @@ struct DropData; namespace QtWebEngineCore { +class CertificateErrorController; +class ClientCertSelectController; class AuthenticationDialogController; class ColorChooserController; class FilePickerController; @@ -91,279 +93,6 @@ class WebContentsAdapter; class WebContentsDelegateQt; class WebEngineSettings; -// Must match blink::WebReferrerPolicy -enum class ReferrerPolicy { - Always, - Default, - NoReferrerWhenDowngrade, - Never, - Origin, - OriginWhenCrossOrigin, - NoReferrerWhenDowngradeOriginWhenCrossOrigin, - SameOrigin, - StrictOrigin, - Last = StrictOrigin, -}; - -class WebEngineContextMenuSharedData : public QSharedData { - -public: - WebEngineContextMenuSharedData() - : hasImageContent(false) - , isEditable(false) - , isSpellCheckerEnabled(false) - , mediaType(0) - , mediaFlags(0) - , editFlags(0) - { - } - bool hasImageContent; - bool isEditable; - bool isSpellCheckerEnabled; - uint mediaType; - uint mediaFlags; - uint editFlags; - QPoint pos; - QUrl linkUrl; - QUrl unfilteredLinkUrl; - QUrl mediaUrl; - QString altText; - QString linkText; - QString titleText; - QString selectedText; - QString suggestedFileName; - QString misspelledWord; - QStringList spellCheckerSuggestions; - QUrl pageUrl; - QUrl frameUrl; - ReferrerPolicy referrerPolicy = ReferrerPolicy::Default; - // Some likely candidates for future additions as we add support for the related actions: - // bool isImageBlocked; - // <enum tbd> mediaType; - // ... -}; - -class WebEngineContextMenuData { -public: - // Must match blink::WebContextMenuData::MediaType: - enum MediaType { - // No special node is in context. - MediaTypeNone = 0x0, - // An image node is selected. - MediaTypeImage, - // A video node is selected. - MediaTypeVideo, - // An audio node is selected. - MediaTypeAudio, - // A canvas node is selected. - MediaTypeCanvas, - // A file node is selected. - MediaTypeFile, - // A plugin node is selected. - MediaTypePlugin, - MediaTypeLast = MediaTypePlugin - }; - // Must match blink::WebContextMenuData::MediaFlags: - enum MediaFlags { - MediaNone = 0x0, - MediaInError = 0x1, - MediaPaused = 0x2, - MediaMuted = 0x4, - MediaLoop = 0x8, - MediaCanSave = 0x10, - MediaHasAudio = 0x20, - MediaCanToggleControls = 0x40, - MediaControls = 0x80, - MediaCanPrint = 0x100, - MediaCanRotate = 0x200, - }; - - // Must match blink::WebContextMenuData::EditFlags: - enum EditFlags { - CanDoNone = 0x0, - CanUndo = 0x1, - CanRedo = 0x2, - CanCut = 0x4, - CanCopy = 0x8, - CanPaste = 0x10, - CanDelete = 0x20, - CanSelectAll = 0x40, - CanTranslate = 0x80, - CanEditRichly = 0x100, - }; - - WebEngineContextMenuData():d(new WebEngineContextMenuSharedData) { - } - - void setPosition(const QPoint &pos) { - d->pos = pos; - } - - QPoint position() const { - return d->pos; - } - - void setLinkUrl(const QUrl &url) { - d->linkUrl = url; - } - - QUrl linkUrl() const { - return d->linkUrl; - } - - void setUnfilteredLinkUrl(const QUrl &url) { - d->unfilteredLinkUrl = url; - } - - QUrl unfilteredLinkUrl() const { - return d->unfilteredLinkUrl; - } - - void setAltText(const QString &text) { - d->altText = text; - } - - QString altText() const { - return d->altText; - } - - void setLinkText(const QString &text) { - d->linkText = text; - } - - QString linkText() const { - return d->linkText; - } - - void setTitleText(const QString &text) { - d->titleText = text; - } - - QString titleText() const { - return d->titleText; - } - - void setSelectedText(const QString &text) { - d->selectedText = text; - } - - QString selectedText() const { - return d->selectedText; - } - - void setMediaUrl(const QUrl &url) { - d->mediaUrl = url; - } - - QUrl mediaUrl() const { - return d->mediaUrl; - } - - void setMediaType(MediaType type) { - d->mediaType = type; - } - - MediaType mediaType() const { - return MediaType(d->mediaType); - } - - void setHasImageContent(bool imageContent) { - d->hasImageContent = imageContent; - } - - bool hasImageContent() const { - return d->hasImageContent; - } - - void setMediaFlags(MediaFlags flags) { - d->mediaFlags = flags; - } - - MediaFlags mediaFlags() const { - return MediaFlags(d->mediaFlags); - } - - void setEditFlags(EditFlags flags) { - d->editFlags = flags; - } - - EditFlags editFlags() const { - return EditFlags(d->editFlags); - } - - void setSuggestedFileName(const QString &filename) { - d->suggestedFileName = filename; - } - - QString suggestedFileName() const { - return d->suggestedFileName; - } - - void setIsEditable(bool editable) { - d->isEditable = editable; - } - - bool isEditable() const { - return d->isEditable; - } - - void setIsSpellCheckerEnabled(bool spellCheckerEnabled) { - d->isSpellCheckerEnabled = spellCheckerEnabled; - } - - bool isSpellCheckerEnabled() const { - return d->isSpellCheckerEnabled; - } - - void setMisspelledWord(const QString &word) { - d->misspelledWord = word; - } - - QString misspelledWord() const { - return d->misspelledWord; - } - - void setSpellCheckerSuggestions(const QStringList &suggestions) { - d->spellCheckerSuggestions = suggestions; - } - - QStringList spellCheckerSuggestions() const { - return d->spellCheckerSuggestions; - } - - void setFrameUrl(const QUrl &url) { - d->frameUrl = url; - } - - QUrl frameUrl() const { - return d->frameUrl; - } - - void setPageUrl(const QUrl &url) { - d->pageUrl = url; - } - - QUrl pageUrl() const { - return d->pageUrl; - } - - QUrl referrerUrl() const { - return !d->frameUrl.isEmpty() ? d->frameUrl : d->pageUrl; - } - - void setReferrerPolicy(ReferrerPolicy referrerPolicy) { - d->referrerPolicy = referrerPolicy; - } - - ReferrerPolicy referrerPolicy() const { - return d->referrerPolicy; - } - -private: - QSharedDataPointer<WebEngineContextMenuSharedData> d; -}; - - class Q_WEBENGINECORE_PRIVATE_EXPORT WebContentsAdapterClient { public: // This must match window_open_disposition_list.h. @@ -465,7 +194,7 @@ public: virtual QColor backgroundColor() const = 0; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0; virtual void loadCommitted() = 0; - virtual void loadVisuallyCommitted() = 0; + virtual void didFirstVisuallyNonEmptyPaint() = 0; virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, const QString &errorDescription, bool triggersErrorPage) = 0; virtual void focusContainer() = 0; @@ -477,7 +206,7 @@ public: virtual bool isBeingAdopted() = 0; virtual void close() = 0; virtual void windowCloseRejected() = 0; - virtual void contextMenuRequested(const WebEngineContextMenuData &) = 0; + virtual void contextMenuRequested(QWebEngineContextMenuRequest *request) = 0; virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) = 0; virtual void requestFullScreenMode(const QUrl &origin, bool fullscreen) = 0; virtual bool isFullScreenMode() const = 0; @@ -500,25 +229,22 @@ public: virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runQuotaRequest(QWebEngineQuotaRequest) = 0; virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0; - virtual WebEngineSettings *webEngineSettings() const = 0; + virtual QWebEngineSettings *webEngineSettings() const = 0; RenderProcessTerminationStatus renderProcessExitStatus(int); virtual void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) = 0; virtual void requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) = 0; - virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) = 0; + virtual void allowCertificateError(const QWebEngineCertificateError &error) = 0; virtual void selectClientCert(const QSharedPointer<ClientCertSelectController> &selectController) = 0; virtual void updateScrollPosition(const QPointF &position) = 0; virtual void updateContentsSize(const QSizeF &size) = 0; virtual void updateNavigationActions() = 0; virtual void updateEditActions() = 0; - virtual void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, - const QPixmap &pixmap, const QPoint &offset) = 0; - virtual bool supportsDragging() const = 0; + virtual QObject *dragSource() const = 0; virtual bool isEnabled() const = 0; virtual const QObject *holdingQObject() const = 0; virtual void setToolTip(const QString& toolTipText) = 0; virtual ClientType clientType() = 0; virtual void printRequested() = 0; - virtual void widgetChanged(RenderWidgetHostViewQtDelegate *newWidget) = 0; virtual TouchHandleDrawableClient *createTouchHandle(const QMap<int, QImage> &images) = 0; virtual void showTouchSelectionMenu(TouchSelectionMenuController *menuController, const QRect &bounds, const QSize &handleSize) = 0; virtual void hideTouchSelectionMenu() = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 1e92a46f8..773bef8da 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -60,7 +60,7 @@ #include "web_contents_view_qt.h" #include "web_engine_context.h" #include "web_engine_settings.h" - +#include "certificate_error_controller.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "components/error_page/common/error.h" #include "components/error_page/common/localized_error.h" @@ -335,12 +335,18 @@ void WebContentsDelegateQt::RenderViewHostChanged(content::RenderViewHost *, con { if (newHost && newHost->GetWidget() && newHost->GetWidget()->GetView()) { auto rwhv = static_cast<RenderWidgetHostViewQt *>(newHost->GetWidget()->GetView()); - m_viewClient->widgetChanged(rwhv->delegate()); + Q_ASSERT(rwhv->delegate()); + rwhv->delegate()->adapterClientChanged(m_viewClient); } } void WebContentsDelegateQt::EmitLoadStarted(const QUrl &url, bool isErrorPage) { + for (auto &&wc : m_certificateErrorControllers) + if (auto controller = wc.lock()) + controller->deactivate(); + m_certificateErrorControllers.clear(); + m_isDocumentEmpty = true; m_viewClient->loadStarted(url, isErrorPage); m_viewClient->updateNavigationActions(); @@ -372,7 +378,7 @@ void WebContentsDelegateQt::EmitLoadStarted(const QUrl &url, bool isErrorPage) void WebContentsDelegateQt::DidStartNavigation(content::NavigationHandle *navigation_handle) { - if (!webEngineSettings()->testAttribute(WebEngineSettings::ErrorPageEnabled)) + if (!webEngineSettings()->testAttribute(QWebEngineSettings::ErrorPageEnabled)) navigation_handle->SetSilentlyIgnoreErrors(); if (!navigation_handle->IsInMainFrame()) @@ -386,8 +392,8 @@ void WebContentsDelegateQt::DidStartNavigation(content::NavigationHandle *naviga void WebContentsDelegateQt::EmitLoadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, const QString &errorDescription, bool triggersErrorPage) { - Q_ASSERT(!isErrorPage || webEngineSettings()->testAttribute(WebEngineSettings::ErrorPageEnabled)); - Q_ASSERT((triggersErrorPage && webEngineSettings()->testAttribute(WebEngineSettings::ErrorPageEnabled)) || !triggersErrorPage); + Q_ASSERT(!isErrorPage || webEngineSettings()->testAttribute(QWebEngineSettings::ErrorPageEnabled)); + Q_ASSERT((triggersErrorPage && webEngineSettings()->testAttribute(QWebEngineSettings::ErrorPageEnabled)) || !triggersErrorPage); // When error page enabled we don't need to send the error page load finished signal if (m_loadProgressMap[url] == 100) @@ -491,7 +497,7 @@ void WebContentsDelegateQt::DidStopLoading() void WebContentsDelegateQt::didFailLoad(const QUrl &url, int errorCode, const QString &errorDescription) { m_viewClient->iconChanged(QUrl()); - bool errorPageEnabled = webEngineSettings()->testAttribute(WebEngineSettings::ErrorPageEnabled); + bool errorPageEnabled = webEngineSettings()->testAttribute(QWebEngineSettings::ErrorPageEnabled); // Delay notifying failure until the error-page is done loading. // Error-pages are not loaded on failures due to abort. bool aborted = (errorCode == -3 /* ERR_ABORTED*/ ); @@ -548,7 +554,7 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame content::NavigationEntry *entry = web_contents()->GetController().GetActiveEntry(); int http_statuscode = entry ? entry->GetHttpStatusCode() : 0; - bool errorPageEnabled = webEngineSettings()->testAttribute(WebEngineSettings::ErrorPageEnabled); + bool errorPageEnabled = webEngineSettings()->testAttribute(QWebEngineSettings::ErrorPageEnabled); bool triggersErrorPage = errorPageEnabled && (http_statuscode >= 400) && m_isDocumentEmpty; EmitLoadFinished(http_statuscode < 400, toQt(validated_url), false /* isErrorPage */, http_statuscode, QString(), triggersErrorPage); } @@ -637,7 +643,7 @@ void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost * /*frameHos bool WebContentsDelegateQt::DidAddMessageToConsole(content::WebContents *source, blink::mojom::ConsoleMessageLevel log_level, const base::string16 &message, int32_t line_no, const base::string16 &source_id) { - Q_UNUSED(source) + Q_UNUSED(source); m_viewClient->javaScriptConsoleMessage(mapToJavascriptConsoleMessageLevel(log_level), toQt(message), static_cast<int>(line_no), toQt(source_id)); return false; } @@ -668,7 +674,7 @@ void WebContentsDelegateQt::SetContentsBounds(content::WebContents *source, cons void WebContentsDelegateQt::UpdateTargetURL(content::WebContents* source, const GURL& url) { - Q_UNUSED(source) + Q_UNUSED(source); m_viewClient->didUpdateTargetURL(toQt(url)); } @@ -689,8 +695,8 @@ void WebContentsDelegateQt::DidFirstVisuallyNonEmptyPaint() void WebContentsDelegateQt::ActivateContents(content::WebContents* contents) { - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - if (settings->testAttribute(settings->Attribute::AllowWindowActivationFromJavaScript)) + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + if (settings->testAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript)) contents->Focus(); } @@ -706,7 +712,7 @@ void WebContentsDelegateQt::RequestToLockMouse(content::WebContents *web_content void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *webContents, blink::web_pref::WebPreferences *webPreferences) { - m_viewClient->webEngineSettings()->overrideWebPreferences(webContents, webPreferences); + WebEngineSettings::get(m_viewClient->webEngineSettings())->overrideWebPreferences(webContents, webPreferences); } QSharedPointer<WebContentsAdapter> @@ -722,9 +728,15 @@ WebContentsDelegateQt::createWindow(std::unique_ptr<content::WebContents> new_co toQt(initial_pos), url); } -void WebContentsDelegateQt::allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) +void WebContentsDelegateQt::allowCertificateError( + const QSharedPointer<CertificateErrorController> &controller) { - m_viewClient->allowCertificateError(errorController); + QWebEngineCertificateError error(controller); + m_viewClient->allowCertificateError(error); + if (!error.isOverridable() || (!controller->deferred() && !controller->answered())) + error.rejectCertificate(); + else + m_certificateErrorControllers.append(controller); } void WebContentsDelegateQt::selectClientCert(const QSharedPointer<ClientCertSelectController> &selectController) @@ -741,17 +753,17 @@ extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(u void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) { - WebEngineSettings *settings = m_viewClient->webEngineSettings(); + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); bool navigationAllowedByPolicy = false; bool navigationRequestAccepted = true; switch (settings->unknownUrlSchemePolicy()) { - case WebEngineSettings::DisallowUnknownUrlSchemes: + case QWebEngineSettings::DisallowUnknownUrlSchemes: break; - case WebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction: + case QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction: navigationAllowedByPolicy = has_user_gesture; break; - case WebEngineSettings::AllowAllUnknownUrlSchemes: + case QWebEngineSettings::AllowAllUnknownUrlSchemes: navigationAllowedByPolicy = true; break; default: @@ -887,7 +899,7 @@ FindTextHelper *WebContentsDelegateQt::findTextHelper() } WebEngineSettings *WebContentsDelegateQt::webEngineSettings() const { - return m_viewClient->webEngineSettings(); + return WebEngineSettings::get(m_viewClient->webEngineSettings()); } WebContentsAdapter *WebContentsDelegateQt::webContentsAdapter() const diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 5a3dff6e9..ff4352131 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -52,11 +52,8 @@ #include "favicon_manager.h" #include "find_text_helper.h" #include "javascript_dialog_manager_qt.h" - -#include <QtCore/qvector.h> - -QT_FORWARD_DECLARE_CLASS(CertificateErrorController) -QT_FORWARD_DECLARE_CLASS(ClientCertSelectController) +#include <QtCore/qlist.h> +#include <QWebEngineCertificateError> namespace blink { namespace web_pref { @@ -92,7 +89,7 @@ protected: private: WebContentsAdapterClient *m_viewClient; - QVector<content::FrameTreeNode *> m_observedNodes; + QList<content::FrameTreeNode *> m_observedNodes; }; class SavePageInfo @@ -226,7 +223,7 @@ private: int &streamCount(blink::mojom::MediaStreamType type); WebContentsAdapterClient *m_viewClient; - QVector<int64_t> m_loadingErrorFrameList; + QList<int64_t> m_loadingErrorFrameList; QScopedPointer<FaviconManager> m_faviconManager; QScopedPointer<FindTextHelper> m_findTextHelper; SavePageInfo m_savePageInfo; @@ -247,6 +244,7 @@ private: bool m_isNavigationCommitted = false; bool m_isDocumentEmpty = true; base::WeakPtrFactory<WebContentsDelegateQt> m_weakPtrFactory { this }; + QList<QWeakPointer<CertificateErrorController>> m_certificateErrorControllers; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 900c53829..9041f1489 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -68,6 +68,8 @@ WebContentsViewQt::WebContentsViewQt(content::WebContents *webContents) : m_webContents(webContents) , m_client(nullptr) , m_factoryClient(nullptr) + , m_contextMenuRequest( + new QWebEngineContextMenuRequest(new QWebEngineContextMenuRequestPrivate())) { } @@ -79,7 +81,7 @@ void WebContentsViewQt::setFactoryClient(WebContentsAdapterClient* client) // Check if a RWHV was created before the pre-initialization. if (auto view = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) { - view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view->delegateClient())); } } @@ -100,7 +102,7 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(conten RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); if (m_factoryClient) { - view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view->delegateClient())); if (m_client) view->setAdapterClient(m_client); } @@ -113,7 +115,7 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForChildWidget(c RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); Q_ASSERT(m_client); - view->setDelegate(m_client->CreateRenderWidgetHostViewQtDelegateForPopup(view)); + view->setDelegate(m_client->CreateRenderWidgetHostViewQtDelegateForPopup(view->delegateClient())); view->setAdapterClient(m_client); return view; @@ -162,73 +164,76 @@ void WebContentsViewQt::FocusThroughTabTraversal(bool reverse) web_contents->GetRenderViewHost()->SetInitialFocus(reverse); } - -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeNone, blink::ContextMenuDataMediaType::kNone) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeImage, blink::ContextMenuDataMediaType::kImage) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeVideo, blink::ContextMenuDataMediaType::kVideo) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeAudio, blink::ContextMenuDataMediaType::kAudio) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeCanvas, blink::ContextMenuDataMediaType::kCanvas) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypeFile, blink::ContextMenuDataMediaType::kFile) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaTypePlugin, blink::ContextMenuDataMediaType::kPlugin) - -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaNone, blink::WebContextMenuData::kMediaNone) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaInError, blink::WebContextMenuData::kMediaInError) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaPaused, blink::WebContextMenuData::kMediaPaused) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaMuted, blink::WebContextMenuData::kMediaMuted) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaLoop, blink::WebContextMenuData::kMediaLoop) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanSave, blink::WebContextMenuData::kMediaCanSave) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaHasAudio, blink::WebContextMenuData::kMediaHasAudio) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanToggleControls, blink::WebContextMenuData::kMediaCanToggleControls) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaControls, blink::WebContextMenuData::kMediaControls) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanPrint, blink::WebContextMenuData::kMediaCanPrint) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanRotate, blink::WebContextMenuData::kMediaCanRotate) - -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanDoNone, blink::kCanDoNone) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanUndo, blink::kCanUndo) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanRedo, blink::kCanRedo) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanCut, blink::kCanCut) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanCopy, blink::kCanCopy) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanPaste, blink::kCanPaste) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanDelete, blink::kCanDelete) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanSelectAll, blink::kCanSelectAll) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanTranslate, blink::kCanTranslate) -ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanEditRichly, blink::kCanEditRichly) - -WebEngineContextMenuData WebContentsViewQt::buildContextMenuData(const content::ContextMenuParams ¶ms) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeNone, + blink::ContextMenuDataMediaType::kNone) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeImage, + blink::ContextMenuDataMediaType::kImage) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeVideo, + blink::ContextMenuDataMediaType::kVideo) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeAudio, + blink::ContextMenuDataMediaType::kAudio) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeCanvas, + blink::ContextMenuDataMediaType::kCanvas) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypeFile, + blink::ContextMenuDataMediaType::kFile) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaTypePlugin, + blink::ContextMenuDataMediaType::kPlugin) + +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaInError, + blink::WebContextMenuData::kMediaInError) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaPaused, + blink::WebContextMenuData::kMediaPaused) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaMuted, blink::WebContextMenuData::kMediaMuted) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaLoop, blink::WebContextMenuData::kMediaLoop) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanSave, + blink::WebContextMenuData::kMediaCanSave) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaHasAudio, + blink::WebContextMenuData::kMediaHasAudio) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanToggleControls, + blink::WebContextMenuData::kMediaCanToggleControls) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaControls, + blink::WebContextMenuData::kMediaControls) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanPrint, + blink::WebContextMenuData::kMediaCanPrint) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::MediaCanRotate, + blink::WebContextMenuData::kMediaCanRotate) + +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanUndo, blink::kCanUndo) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanRedo, blink::kCanRedo) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanCut, blink::kCanCut) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanCopy, blink::kCanCopy) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanPaste, blink::kCanPaste) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanDelete, blink::kCanDelete) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanSelectAll, blink::kCanSelectAll) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanTranslate, blink::kCanTranslate) +ASSERT_ENUMS_MATCH(QWebEngineContextMenuRequest::CanEditRichly, blink::kCanEditRichly) + +// static +void WebContentsViewQt::update(QWebEngineContextMenuRequest *request, + const content::ContextMenuParams ¶ms, bool spellcheckEnabled) { - WebEngineContextMenuData ret; - ret.setPosition(QPoint(params.x, params.y)); - ret.setLinkUrl(toQt(params.link_url)); - ret.setLinkText(toQt(params.link_text)); - ret.setAltText(toQt(params.alt_text)); - ret.setTitleText(toQt(params.title_text)); - ret.setUnfilteredLinkUrl(toQt(params.unfiltered_link_url)); - ret.setSelectedText(toQt(params.selection_text)); - ret.setMediaUrl(toQt(params.src_url)); - ret.setMediaType((WebEngineContextMenuData::MediaType)params.media_type); - ret.setHasImageContent(params.has_image_contents); - ret.setMediaFlags((WebEngineContextMenuData::MediaFlags)params.media_flags); - ret.setEditFlags((WebEngineContextMenuData::EditFlags)params.edit_flags); - ret.setSuggestedFileName(toQt(params.suggested_filename)); - ret.setIsEditable(params.is_editable); + auto *re = request->d.data(); + re->m_position = QPoint(params.x, params.y); + re->m_filteredLinkUrl = toQt(params.link_url); + re->m_linkText = toQt(params.link_text); + re->m_altText = toQt(params.alt_text); + re->m_titleText = toQt(params.title_text); + re->m_unfilteredLinkUrl = toQt(params.unfiltered_link_url); + re->m_selectedText = toQt(params.selection_text); + re->m_mediaUrl = toQt(params.src_url); + re->m_mediaType = (QWebEngineContextMenuRequest::MediaType)params.media_type; + re->m_hasImageContent = params.has_image_contents; + re->m_mediaFlags = (QWebEngineContextMenuRequest::MediaFlags)params.media_flags; + re->m_editFlags = (QWebEngineContextMenuRequest::EditFlags)params.edit_flags; + re->m_suggestedFileName = toQt(params.suggested_filename); + re->m_isEditable = params.is_editable; #if QT_CONFIG(webengine_spellchecker) - ret.setMisspelledWord(toQt(params.misspelled_word)); - ret.setSpellCheckerSuggestions(fromVector(params.dictionary_suggestions)); + re->m_misspelledWord = toQt(params.misspelled_word); + re->m_spellCheckerSuggestions = fromVector(params.dictionary_suggestions); #endif - ret.setFrameUrl(toQt(params.frame_url)); - ret.setPageUrl(toQt(params.page_url)); - ret.setReferrerPolicy((ReferrerPolicy)params.referrer_policy); - return ret; -} - -void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const content::ContextMenuParams ¶ms) -{ - if (auto rwhv = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) { - if (rwhv && rwhv->getTouchSelectionControllerClient()->handleContextMenu(params)) - return; - } - - WebEngineContextMenuData contextMenuData(buildContextMenuData(params)); + re->m_frameUrl = toQt(params.frame_url); + re->m_pageUrl = toQt(params.page_url); + re->m_referrerPolicy = (ReferrerPolicy)params.referrer_policy; #if QT_CONFIG(webengine_spellchecker) // Do not use params.spellcheck_enabled, since it is never // correctly initialized for chrome asynchronous spellchecking. @@ -237,9 +242,21 @@ void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const conten // must be initialized to true due to the way how the initialization sequence // in SpellCheck works ie. typing the first word triggers the creation // of the SpellcheckService. Use user preference store instead. - contextMenuData.setIsSpellCheckerEnabled(m_client->profileAdapter()->isSpellCheckEnabled()); + re->m_isSpellCheckerEnabled = spellcheckEnabled; #endif - m_client->contextMenuRequested(contextMenuData); +} + +void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, + const content::ContextMenuParams ¶ms) +{ + if (auto rwhv = + static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) { + if (rwhv && rwhv->getTouchSelectionControllerClient()->handleContextMenu(params)) + return; + } + const bool spellcheckEnabled = m_client->profileAdapter()->isSpellCheckEnabled(); + update(m_contextMenuRequest.get(), params, spellcheckEnabled); + m_client->contextMenuRequested(m_contextMenuRequest.get()); } static Qt::DropActions toQtDropActions(blink::DragOperationsMask ops) @@ -264,7 +281,8 @@ void WebContentsViewQt::StartDragging(const content::DropData &drop_data, #if QT_CONFIG(draganddrop) Q_UNUSED(event_info); - if (!m_client->supportsDragging()) { + QObject *dragSource = m_client->dragSource(); + if (!dragSource) { if (source_rwh) source_rwh->DragSourceSystemDragEnded(); return; @@ -278,7 +296,7 @@ void WebContentsViewQt::StartDragging(const content::DropData &drop_data, hotspot.setY(image_offset.y()); } - m_client->startDragging(drop_data, toQtDropActions(allowed_ops), pixmap, hotspot); + m_client->webContentsAdapter()->startDragging(dragSource, drop_data, toQtDropActions(allowed_ops), pixmap, hotspot); #endif // QT_CONFIG(draganddrop) } diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index da0c5d20c..ff3b9d632 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -46,6 +46,12 @@ #include "api/qtwebenginecoreglobal_p.h" #include "web_contents_adapter_client.h" +QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest) + +namespace extensions { +class MimeHandlerViewGuestDelegateQt; +} + namespace content { class WebContents; } @@ -60,7 +66,7 @@ class WebContentsViewQt public: static inline WebContentsViewQt *from(WebContentsView *view) { return static_cast<WebContentsViewQt*>(view); } - WebContentsViewQt(content::WebContents *webContents); + WebContentsViewQt(content::WebContents* webContents); void setFactoryClient(WebContentsAdapterClient* client); void setClient(WebContentsAdapterClient* client); @@ -121,12 +127,17 @@ public: void LostFocus(content::RenderWidgetHostImpl *render_widget_host) override; void TakeFocus(bool reverse) override; - static WebEngineContextMenuData buildContextMenuData(const content::ContextMenuParams ¶ms); +private: + static void update(QWebEngineContextMenuRequest *request, + const content::ContextMenuParams ¶ms, bool spellcheckEnabled); private: content::WebContents *m_webContents; WebContentsAdapterClient *m_client; WebContentsAdapterClient *m_factoryClient; + std::unique_ptr<QWebEngineContextMenuRequest> m_contextMenuRequest; + + friend class extensions::MimeHandlerViewGuestDelegateQt; }; } // namespace QtWebEngineCore diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index f342e788d..94f214a07 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -133,16 +133,15 @@ #include <QOffscreenSurface> #if QT_CONFIG(opengl) # include <QOpenGLContext> +# include <qopenglcontext_platform.h> #endif #include <QQuickWindow> #include <QStringList> #include <QSurfaceFormat> -#include <QVector> #include <QNetworkProxy> #include <QtGui/qpa/qplatformintegration.h> #include <QtGui/private/qguiapplication_p.h> - -using namespace QtWebEngineCore; +#include <QLoggingCategory> #if QT_CONFIG(opengl) QT_BEGIN_NAMESPACE @@ -150,10 +149,10 @@ Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context(); QT_END_NAMESPACE #endif -namespace { +namespace QtWebEngineCore { #if QT_CONFIG(opengl) -bool usingANGLE() +static bool usingANGLE() { #if defined(Q_OS_WIN) if (qt_gl_global_share_context()) @@ -164,8 +163,11 @@ bool usingANGLE() #endif } -bool usingDefaultSGBackend() +static bool usingDefaultSGBackend() { + if (QQuickWindow::graphicsApi() != QSGRendererInterface::OpenGL) + return false; + const QStringList args = QGuiApplication::arguments(); //folow logic from contextFactory in src/quick/scenegraph/qsgcontextplugin.cpp @@ -185,16 +187,105 @@ bool usingDefaultSGBackend() return device.isEmpty(); } + +bool usingSoftwareDynamicGL() +{ + if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) + return true; +#if defined(Q_OS_WIN) + HMODULE handle = QNativeInterface::QWGLContext::openGLModuleHandle(); + wchar_t path[MAX_PATH]; + DWORD size = GetModuleFileName(handle, path, MAX_PATH); + QFileInfo openGLModule(QString::fromWCharArray(path, size)); + return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); +#else + return false; +#endif +} + +static const char *getGLType(bool enableGLSoftwareRendering) +{ + const char *glType = nullptr; + const bool tryGL = (usingDefaultSGBackend() && !usingSoftwareDynamicGL() + && QGuiApplicationPrivate::platformIntegration()->hasCapability( + QPlatformIntegration::OpenGL)) + || enableGLSoftwareRendering; + if (tryGL) { + if (!qt_gl_global_share_context() || !qt_gl_global_share_context()->isValid()) { + qWarning("WebEngineContext used before QtWebEngine::initialize() or OpenGL context " + "creation failed."); + } else { + const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + switch (sharedFormat.renderableType()) { + case QSurfaceFormat::OpenGL: + glType = gl::kGLImplementationDesktopName; + // Check if Core profile was requested and is supported. + if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) { +#ifdef Q_OS_MACOS + glType = gl::kGLImplementationCoreProfileName; +#else + qWarning("An OpenGL Core Profile was requested, but it is not supported " + "on the current platform. Falling back to a non-Core profile. " + "Note that this might cause rendering issues."); +#endif + } + break; + case QSurfaceFormat::OpenGLES: + glType = usingANGLE() ? gl::kGLImplementationANGLEName + : gl::kGLImplementationEGLName; + break; + case QSurfaceFormat::OpenVG: + case QSurfaceFormat::DefaultRenderableType: + default: + // Shared contex created but no rederable type set. + qWarning("Unsupported rendering surface format. Please open bug report at " + "https://bugreports.qt.io"); + } + } + } + return glType; +} +#else +static cont char *getGLType(bool enableGLSoftwareRendering) +{ + return nullptr; +} #endif // QT_CONFIG(opengl) + #if QT_CONFIG(webengine_pepper_plugins) void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&) { } #endif -} // namespace - -namespace QtWebEngineCore { +static void logContext(const char *glType, base::CommandLine *cmd) +{ + QLoggingCategory webEngineContextLog("qt.webenginecontext"); + if (webEngineContextLog.isInfoEnabled()) { + const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format(); + const auto profile = QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey( + sharedFormat.profile()); + const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey( + sharedFormat.renderableType()); + const base::CommandLine::SwitchMap switch_map = cmd->GetSwitches(); + QStringList params; + for (const auto &pair : switch_map) + params << " * " << toQt(pair.first) + << toQt(pair.second) << "\n"; + qCInfo(webEngineContextLog, + "\n\nGLImplementation: %s\n" + "Surface Type: %s\n" + "Surface Profile: %s\n" + "Surface Version: %d.%d\n" + "Using Default SG Backend: %s\n" + "Using Software Dynamic GL: %s\n" + "Using Angle: %s\n\n" + "Init Parameters:\n %s", + glType, type, profile, sharedFormat.majorVersion(), sharedFormat.minorVersion(), + usingDefaultSGBackend() ? "yes" : "no", usingSoftwareDynamicGL() ? "yes" : "no", + usingANGLE() ? "yes" : "no", qPrintable(params.join(" "))); + } +} #if defined(Q_OS_WIN) sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterfaceInfo *info) @@ -210,36 +301,22 @@ sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterf extern std::unique_ptr<base::MessagePump> messagePumpFactory(); -bool usingSoftwareDynamicGL() +static void setupProxyPac(base::CommandLine *commandLine) { - if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) - return true; -#if defined(Q_OS_WIN) && QT_CONFIG(opengl) - HMODULE handle = static_cast<HMODULE>(QOpenGLContext::openGLModuleHandle()); - wchar_t path[MAX_PATH]; - DWORD size = GetModuleFileName(handle, path, MAX_PATH); - QFileInfo openGLModule(QString::fromWCharArray(path, size)); - return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); -#else - return false; -#endif -} - -void setupProxyPac(base::CommandLine *commandLine){ if (commandLine->HasSwitch(switches::kProxyPacUrl)) { QUrl pac_url(toQt(commandLine->GetSwitchValueASCII(switches::kProxyPacUrl))); if (pac_url.isValid() && (pac_url.isLocalFile() || - !pac_url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive))) { + !pac_url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive))) { QFile file; if (pac_url.isLocalFile()) - file.setFileName(pac_url.toLocalFile()); + file.setFileName(pac_url.toLocalFile()); else - file.setFileName(pac_url.path().prepend(QChar(':'))); + file.setFileName(pac_url.path().prepend(QChar(':'))); if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QByteArray ba = file.readAll(); - commandLine->RemoveSwitch(switches::kProxyPacUrl); - commandLine->AppendSwitchASCII(switches::kProxyPacUrl, - ba.toBase64().prepend("data:application/x-javascript-config;base64,").toStdString()); + QByteArray ba = file.readAll(); + commandLine->RemoveSwitch(switches::kProxyPacUrl); + commandLine->AppendSwitchASCII(switches::kProxyPacUrl, + ba.toBase64().prepend("data:application/x-javascript-config;base64,").toStdString()); } } } @@ -604,12 +681,6 @@ WebEngineContext::WebEngineContext() QStringList appArgs = QCoreApplication::arguments(); - // If user requested GL support instead of using Skia rendering to - // bitmaps, use software rendering via software OpenGL. This might be less - // performant, but at least provides WebGL support. - // TODO(miklocek), check if this still works with latest chromium - bool enableGLSoftwareRendering = appArgs.contains(QStringLiteral("--enable-webgl-software-rendering")); - bool useEmbeddedSwitches = false; #if defined(QTWEBENGINE_EMBEDDED_SWITCHES) useEmbeddedSwitches = !appArgs.contains(QStringLiteral("--disable-embedded-switches")); @@ -625,6 +696,9 @@ WebEngineContext::WebEngineContext() // Enable sandboxing on OS X and Linux (Desktop / Embedded) by default. bool disable_sandbox = qEnvironmentVariableIsSet(kDisableSandboxEnv); +#if defined(Q_OS_WIN) + disable_sandbox = true; // FIXME: Windows sandbox no longer works on CI, but works fine locally. +#endif if (!disable_sandbox) { #if defined(Q_OS_LINUX) parsedCommandLine->AppendSwitch(sandbox::policy::switches::kDisableSetuidSandbox); @@ -636,30 +710,6 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing); -#if defined(Q_OS_WIN) - // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create - // an OpenGL Core Profile context. If the switch is not set, it would always try to create a - // Core Profile context, even if Qt uses a legacy profile, which causes - // "Could not share GL contexts" warnings, because it's not possible to share between Core and - // legacy profiles. See GLContextWGL::Initialize(). - // Given that Desktop GL Core profile is not currently supported on Windows anyway, pass this - // switch to get rid of the warnings. - // - // The switch is also used to determine which version of OpenGL ES to use (2 or 3) when using - // ANGLE. - // If the switch is not set, Chromium will always try to create an ES3 context, even if Qt uses - // an ES2 context, which causes resource sharing issues (black screen), - // see gpu::gles2::GenerateGLContextAttribs(). - // Make sure to disable ES3 context creation when using ES2. - const bool isGLES2Context = qt_gl_global_share_context() - && qt_gl_global_share_context()->isOpenGLES() - && qt_gl_global_share_context()->format().majorVersion() == 2; - const bool isDesktopGLOrSoftware = !usingANGLE(); - - if (isDesktopGLOrSoftware || isGLES2Context) - parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); -#endif - // Do not advertise a feature we have removed at compile time parsedCommandLine->AppendSwitch(switches::kDisableSpeechAPI); @@ -711,74 +761,12 @@ WebEngineContext::WebEngineContext() GLContextHelper::initialize(); - const char *glType = 0; -#if QT_CONFIG(opengl) - - const bool tryGL = (usingDefaultSGBackend() && !usingSoftwareDynamicGL() && - QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) - || enableGLSoftwareRendering; - if (tryGL) { - if (qt_gl_global_share_context() && qt_gl_global_share_context()->isValid()) { - // If the native handle is QEGLNativeContext try to use GL ES/2. - // If there is no native handle, assume we are using wayland and try GL ES/2. - // If we are using ANGLE on Windows, use OpenGL ES (2 or 3). - if (qt_gl_global_share_context()->nativeHandle().isNull() - || !strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), - "QEGLNativeContext") - || usingANGLE()) - { - if (qt_gl_global_share_context()->isOpenGLES()) { - glType = usingANGLE() ? gl::kGLImplementationANGLEName : gl::kGLImplementationEGLName; - } else { - QOpenGLContext context; - QSurfaceFormat format; - - format.setRenderableType(QSurfaceFormat::OpenGL); - format.setVersion(2, 0); - - context.setFormat(format); - context.setShareContext(qt_gl_global_share_context()); - if (context.create()) { - QOffscreenSurface surface; - - surface.setFormat(format); - surface.create(); - - if (context.makeCurrent(&surface)) { - if (context.hasExtension("GL_ARB_ES2_compatibility")) - glType = gl::kGLImplementationEGLName; - - context.doneCurrent(); - } - - surface.destroy(); - } - } - } else { - if (!qt_gl_global_share_context()->isOpenGLES()) { - // Default to Desktop non-Core profile OpenGL. - glType = gl::kGLImplementationDesktopName; - - // Check if Core profile was requested and is supported. - QSurfaceFormat globalSharedFormat = qt_gl_global_share_context()->format(); - if (globalSharedFormat.profile() == QSurfaceFormat::CoreProfile) { -#ifdef Q_OS_MACOS - glType = gl::kGLImplementationCoreProfileName; -#else - qWarning("An OpenGL Core Profile was requested, but it is not supported " - "on the current platform. Falling back to a non-Core profile. " - "Note that this might cause rendering issues."); -#endif - } - } - } - if (qt_gl_global_share_context()->format().profile() == QSurfaceFormat::CompatibilityProfile) - parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext); - } else { - qWarning("WebEngineContext used before QtWebEngine::initialize() or OpenGL context creation failed."); - } - } -#endif // QT_CONFIG(opengl) + // If user requested GL support instead of using Skia rendering to + // bitmaps, use software rendering via software OpenGL. This might be less + // performant, but at least provides WebGL support. + // TODO(miklocek), check if this still works with latest chromium + const bool enableGLSoftwareRendering = appArgs.contains(QStringLiteral("--enable-webgl-software-rendering")); + const char *glType = getGLType(enableGLSoftwareRendering); if (glType) { parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); @@ -787,6 +775,29 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kDisableGpuRasterization); parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlacklist); } + const QSurfaceFormat sharedFormat = QOpenGLContext::globalShareContext()->format(); + if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile) + parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext); +#if defined(Q_OS_WIN) + // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create + // an OpenGL Core Profile context. If the switch is not set, it would always try to create a + // Core Profile context, even if Qt uses a legacy profile, which causes + // "Could not share GL contexts" warnings, because it's not possible to share between Core and + // legacy profiles. See GLContextWGL::Initialize(). + // Given that Desktop GL Core profile is not currently supported on Windows anyway, pass this + // switch to get rid of the warnings. + // + // The switch is also used to determine which version of OpenGL ES to use (2 or 3) when using + // ANGLE. + // If the switch is not set, Chromium will always try to create an ES3 context, even if Qt uses + // an ES2 context, which causes resource sharing issues (black screen), + // see gpu::gles2::GenerateGLContextAttribs(). + // Make sure to disable ES3 context creation when using ES2. + const bool isGLES2Context = QOpenGLContext::globalShareContext()->isOpenGLES() + && QOpenGLContext::globalShareContext()->format().majorVersion() == 2; + if (!usingANGLE() || isGLES2Context) + parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); +#endif } else { parsedCommandLine->AppendSwitch(switches::kDisableGpu); } @@ -869,6 +880,8 @@ WebEngineContext::WebEngineContext() #endif content::WebUIControllerFactory::RegisterFactory(WebUIControllerFactoryQt::GetInstance()); + + logContext(glType, parsedCommandLine); } #if QT_CONFIG(webengine_printing_and_pdf) @@ -897,8 +910,8 @@ gpu::SyncPointManager *WebEngineContext::syncPointManager() return spm; QMutexLocker lock(&s_spmMutex); if (!s_syncPointManager) - s_syncPointManager.store(new gpu::SyncPointManager()); - return s_syncPointManager.load(); + s_syncPointManager.storeRelaxed(new gpu::SyncPointManager()); + return s_syncPointManager.loadRelaxed(); } base::CommandLine* WebEngineContext::commandLine() { diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index f60082059..9ac598c67 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -47,7 +47,7 @@ #include "base/values.h" #include <QtGui/qtgui-config.h> -#include <QVector> +#include <QList> namespace base { class RunLoop; @@ -149,7 +149,7 @@ private: std::unique_ptr<QObject> m_globalQObject; std::unique_ptr<ProfileAdapter> m_defaultProfileAdapter; std::unique_ptr<DevToolsServerQt> m_devtoolsServer; - QVector<ProfileAdapter*> m_profileAdapters; + QList<ProfileAdapter*> m_profileAdapters; #if QT_CONFIG(accessibility) std::unique_ptr<AccessibilityActivationObserver> m_accessibilityActivationObserver; #endif diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 09a4141b0..47c4634b3 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -168,7 +168,7 @@ QString subProcessPath() candidatePaths << getPath(frameworkBundle()) % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME); #else - candidatePaths << QLibraryInfo::location(QLibraryInfo::LibraryExecutablesPath) + candidatePaths << QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) % QLatin1Char('/') % processBinary; #endif candidatePaths << QCoreApplication::applicationDirPath() @@ -205,7 +205,7 @@ QString localesPath() #if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_locales"); #else - QLibraryInfo::location(QLibraryInfo::TranslationsPath) % QDir::separator() % QLatin1String("qtwebengine_locales"); + QLibraryInfo::path(QLibraryInfo::TranslationsPath) % QDir::separator() % QLatin1String("qtwebengine_locales"); #endif if (!initialized) { @@ -254,7 +254,7 @@ QString dictionariesPath() candidatePaths << frameworkDictionariesPath; #endif - QString libraryDictionariesPath = QLibraryInfo::location(QLibraryInfo::DataPath) + QString libraryDictionariesPath = QLibraryInfo::path(QLibraryInfo::DataPath) % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); candidatePaths << libraryDictionariesPath; } @@ -280,13 +280,13 @@ QString resourcesDataPath() #elif defined(OS_MAC) QLibraryInfo::location(QLibraryInfo::DataPath) % QLatin1String("/Resources"); #else - QLibraryInfo::location(QLibraryInfo::DataPath) % QLatin1String("/resources"); + QLibraryInfo::path(QLibraryInfo::DataPath) % QLatin1String("/resources"); #endif if (!initialized) { initialized = true; if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { qWarning("Qt WebEngine resources not found at %s. Trying parent directory...", qPrintable(potentialResourcesPath)); - potentialResourcesPath = QLibraryInfo::location(QLibraryInfo::DataPath); + potentialResourcesPath = QLibraryInfo::path(QLibraryInfo::DataPath); } if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { qWarning("Qt WebEngine resources not found at %s. Trying application directory...", qPrintable(potentialResourcesPath)); @@ -377,8 +377,8 @@ bool WebEngineLibraryInfo::isUNCPath(const QString &path) { return (base::FilePath::IsSeparator(path.at(0).toLatin1()) && base::FilePath::IsSeparator(path.at(1).toLatin1()) - && path.at(2) != "." && path.at(2) != "?" - && path.at(2).isLetter() && path.at(3) != ":"); + && path.at(2) != QLatin1Char('.') && path.at(2) != QLatin1Char('?') + && path.at(2).isLetter() && path.at(3) != QLatin1Char(':')); } #endif diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 4115d10d7..d7feb0e41 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -59,13 +59,12 @@ #include <QFont> #include <QTimer> -#include <QTouchDevice> namespace QtWebEngineCore { -QHash<WebEngineSettings::Attribute, bool> WebEngineSettings::s_defaultAttributes; -QHash<WebEngineSettings::FontFamily, QString> WebEngineSettings::s_defaultFontFamilies; -QHash<WebEngineSettings::FontSize, int> WebEngineSettings::s_defaultFontSizes; +QHash<QWebEngineSettings::WebAttribute, bool> WebEngineSettings::s_defaultAttributes; +QHash<QWebEngineSettings::FontFamily, QString> WebEngineSettings::s_defaultFontFamilies; +QHash<QWebEngineSettings::FontSize, int> WebEngineSettings::s_defaultFontSizes; static const int batchTimerTimeout = 0; @@ -93,13 +92,14 @@ static inline bool isTouchEventsAPIEnabled() { } WebEngineSettings::WebEngineSettings(WebEngineSettings *_parentSettings) - : m_adapter(0) + : m_adapter(nullptr) , parentSettings(_parentSettings) - , m_unknownUrlSchemePolicy(WebEngineSettings::InheritedUnknownUrlSchemePolicy) + , m_unknownUrlSchemePolicy(QWebEngineSettings::InheritedUnknownUrlSchemePolicy) { if (parentSettings) parentSettings->childSettings.insert(this); - + else + initDefaults(); m_batchTimer.setSingleShot(true); m_batchTimer.setInterval(batchTimerTimeout); QObject::connect(&m_batchTimer, &QTimer::timeout, [this]() { @@ -132,13 +132,13 @@ void WebEngineSettings::overrideWebPreferences(content::WebContents *webContents } } -void WebEngineSettings::setAttribute(WebEngineSettings::Attribute attr, bool on) +void WebEngineSettings::setAttribute(QWebEngineSettings::WebAttribute attr, bool on) { m_attributes.insert(attr, on); scheduleApplyRecursively(); } -bool WebEngineSettings::testAttribute(WebEngineSettings::Attribute attr) const +bool WebEngineSettings::testAttribute(QWebEngineSettings::WebAttribute attr) const { auto it = m_attributes.constFind(attr); if (it != m_attributes.constEnd()) @@ -151,7 +151,7 @@ bool WebEngineSettings::testAttribute(WebEngineSettings::Attribute attr) const return s_defaultAttributes.value(attr); } -bool WebEngineSettings::isAttributeExplicitlySet(Attribute attr) const +bool WebEngineSettings::isAttributeExplicitlySet(QWebEngineSettings::WebAttribute attr) const { if (m_attributes.contains(attr)) return true; @@ -162,19 +162,19 @@ bool WebEngineSettings::isAttributeExplicitlySet(Attribute attr) const return false; } -void WebEngineSettings::resetAttribute(WebEngineSettings::Attribute attr) +void WebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) { m_attributes.remove(attr); scheduleApplyRecursively(); } -void WebEngineSettings::setFontFamily(WebEngineSettings::FontFamily which, const QString &family) +void WebEngineSettings::setFontFamily(QWebEngineSettings::FontFamily which, const QString &family) { m_fontFamilies.insert(which, family); scheduleApplyRecursively(); } -QString WebEngineSettings::fontFamily(WebEngineSettings::FontFamily which) +QString WebEngineSettings::fontFamily(QWebEngineSettings::FontFamily which) { if (!parentSettings) { Q_ASSERT(s_defaultFontFamilies.contains(which)); @@ -183,19 +183,19 @@ QString WebEngineSettings::fontFamily(WebEngineSettings::FontFamily which) return m_fontFamilies.value(which, parentSettings->fontFamily(which)); } -void WebEngineSettings::resetFontFamily(WebEngineSettings::FontFamily which) +void WebEngineSettings::resetFontFamily(QWebEngineSettings::FontFamily which) { m_fontFamilies.remove(which); scheduleApplyRecursively(); } -void WebEngineSettings::setFontSize(WebEngineSettings::FontSize type, int size) +void WebEngineSettings::setFontSize(QWebEngineSettings::FontSize type, int size) { m_fontSizes.insert(type, size); scheduleApplyRecursively(); } -int WebEngineSettings::fontSize(WebEngineSettings::FontSize type) const +int WebEngineSettings::fontSize(QWebEngineSettings::FontSize type) const { if (!parentSettings) { Q_ASSERT(s_defaultFontSizes.contains(type)); @@ -204,7 +204,7 @@ int WebEngineSettings::fontSize(WebEngineSettings::FontSize type) const return m_fontSizes.value(type, parentSettings->fontSize(type)); } -void WebEngineSettings::resetFontSize(WebEngineSettings::FontSize type) +void WebEngineSettings::resetFontSize(QWebEngineSettings::FontSize type) { m_fontSizes.remove(type); scheduleApplyRecursively(); @@ -223,42 +223,42 @@ QString WebEngineSettings::defaultTextEncoding() const return m_defaultEncoding.isEmpty()? parentSettings->defaultTextEncoding() : m_defaultEncoding; } -void WebEngineSettings::setUnknownUrlSchemePolicy(WebEngineSettings::UnknownUrlSchemePolicy policy) +void WebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy) { m_unknownUrlSchemePolicy = policy; } -WebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy() const +QWebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy() const { // value InheritedUnknownUrlSchemePolicy means it is taken from parent, if possible. If there // is no parent, then AllowUnknownUrlSchemesFromUserInteraction (the default behavior) is used. - if (m_unknownUrlSchemePolicy != InheritedUnknownUrlSchemePolicy) + if (m_unknownUrlSchemePolicy != QWebEngineSettings::InheritedUnknownUrlSchemePolicy) return m_unknownUrlSchemePolicy; if (parentSettings) return parentSettings->unknownUrlSchemePolicy(); - return AllowUnknownUrlSchemesFromUserInteraction; + return QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction; } void WebEngineSettings::initDefaults() { if (s_defaultAttributes.isEmpty()) { // Initialize the default settings. - s_defaultAttributes.insert(AutoLoadImages, true); - s_defaultAttributes.insert(JavascriptEnabled, true); - s_defaultAttributes.insert(JavascriptCanOpenWindows, true); - s_defaultAttributes.insert(JavascriptCanAccessClipboard, false); - s_defaultAttributes.insert(LinksIncludedInFocusChain, true); - s_defaultAttributes.insert(LocalStorageEnabled, true); - s_defaultAttributes.insert(LocalContentCanAccessRemoteUrls, false); - s_defaultAttributes.insert(XSSAuditingEnabled, false); - s_defaultAttributes.insert(SpatialNavigationEnabled, false); - s_defaultAttributes.insert(LocalContentCanAccessFileUrls, true); - s_defaultAttributes.insert(HyperlinkAuditingEnabled, false); - s_defaultAttributes.insert(ErrorPageEnabled, true); - s_defaultAttributes.insert(PluginsEnabled, false); - s_defaultAttributes.insert(FullScreenSupportEnabled, false); - s_defaultAttributes.insert(ScreenCaptureEnabled, false); - s_defaultAttributes.insert(ShowScrollBars, true); + s_defaultAttributes.insert(QWebEngineSettings::AutoLoadImages, true); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptCanOpenWindows, true); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptCanAccessClipboard, false); + s_defaultAttributes.insert(QWebEngineSettings::LinksIncludedInFocusChain, true); + s_defaultAttributes.insert(QWebEngineSettings::LocalStorageEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::LocalContentCanAccessRemoteUrls, false); + s_defaultAttributes.insert(QWebEngineSettings::XSSAuditingEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::SpatialNavigationEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + s_defaultAttributes.insert(QWebEngineSettings::HyperlinkAuditingEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::ErrorPageEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::PluginsEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::FullScreenSupportEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::ScreenCaptureEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::ShowScrollBars, true); // The following defaults matches logic in render_view_host_impl.cc // But first we must ensure the WebContext has been initialized QtWebEngineCore::WebEngineContext::current(); @@ -270,27 +270,30 @@ void WebEngineSettings::initDefaults() bool accelerated2dCanvas = !commandLine->HasSwitch(switches::kDisableAccelerated2dCanvas); bool allowRunningInsecureContent = commandLine->HasSwitch(switches::kAllowRunningInsecureContent); - s_defaultAttributes.insert(ScrollAnimatorEnabled, smoothScrolling); - s_defaultAttributes.insert(WebGLEnabled, webGL); - s_defaultAttributes.insert(Accelerated2dCanvasEnabled, accelerated2dCanvas); - s_defaultAttributes.insert(AutoLoadIconsForPage, true); - s_defaultAttributes.insert(TouchIconsEnabled, false); - s_defaultAttributes.insert(FocusOnNavigationEnabled, false); - s_defaultAttributes.insert(PrintElementBackgrounds, true); - s_defaultAttributes.insert(AllowRunningInsecureContent, allowRunningInsecureContent); - s_defaultAttributes.insert(AllowGeolocationOnInsecureOrigins, false); - s_defaultAttributes.insert(AllowWindowActivationFromJavaScript, false); + s_defaultAttributes.insert(QWebEngineSettings::ScrollAnimatorEnabled, smoothScrolling); + s_defaultAttributes.insert(QWebEngineSettings::WebGLEnabled, webGL); + s_defaultAttributes.insert(QWebEngineSettings::Accelerated2dCanvasEnabled, + accelerated2dCanvas); + s_defaultAttributes.insert(QWebEngineSettings::AutoLoadIconsForPage, true); + s_defaultAttributes.insert(QWebEngineSettings::TouchIconsEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::FocusOnNavigationEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::PrintElementBackgrounds, true); + s_defaultAttributes.insert(QWebEngineSettings::AllowRunningInsecureContent, + allowRunningInsecureContent); + s_defaultAttributes.insert(QWebEngineSettings::AllowGeolocationOnInsecureOrigins, false); + s_defaultAttributes.insert(QWebEngineSettings::AllowWindowActivationFromJavaScript, false); bool playbackRequiresUserGesture = false; if (commandLine->HasSwitch(switches::kAutoplayPolicy)) playbackRequiresUserGesture = (commandLine->GetSwitchValueASCII(switches::kAutoplayPolicy) != switches::autoplay::kNoUserGestureRequiredPolicy); - s_defaultAttributes.insert(PlaybackRequiresUserGesture, playbackRequiresUserGesture); - s_defaultAttributes.insert(WebRTCPublicInterfacesOnly, false); - s_defaultAttributes.insert(JavascriptCanPaste, false); - s_defaultAttributes.insert(DnsPrefetchEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::PlaybackRequiresUserGesture, + playbackRequiresUserGesture); + s_defaultAttributes.insert(QWebEngineSettings::WebRTCPublicInterfacesOnly, false); + s_defaultAttributes.insert(QWebEngineSettings::JavascriptCanPaste, false); + s_defaultAttributes.insert(QWebEngineSettings::DnsPrefetchEnabled, false); #if QT_CONFIG(webengine_extensions) - s_defaultAttributes.insert(PdfViewerEnabled, true); + s_defaultAttributes.insert(QWebEngineSettings::PdfViewerEnabled, true); #else - s_defaultAttributes.insert(PdfViewerEnabled, false); + s_defaultAttributes.insert(QWebEngineSettings::PdfViewerEnabled, false); #endif } @@ -298,32 +301,34 @@ void WebEngineSettings::initDefaults() // Default fonts QFont defaultFont; defaultFont.setStyleHint(QFont::Serif); - s_defaultFontFamilies.insert(StandardFont, defaultFont.defaultFamily()); - s_defaultFontFamilies.insert(SerifFont, defaultFont.defaultFamily()); - s_defaultFontFamilies.insert(PictographFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::StandardFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::SerifFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::PictographFont, + defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::Fantasy); - s_defaultFontFamilies.insert(FantasyFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::FantasyFont, defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::Cursive); - s_defaultFontFamilies.insert(CursiveFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::CursiveFont, defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::SansSerif); - s_defaultFontFamilies.insert(SansSerifFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::SansSerifFont, + defaultFont.defaultFamily()); defaultFont.setStyleHint(QFont::Monospace); - s_defaultFontFamilies.insert(FixedFont, defaultFont.defaultFamily()); + s_defaultFontFamilies.insert(QWebEngineSettings::FixedFont, defaultFont.defaultFamily()); } if (s_defaultFontSizes.isEmpty()) { - s_defaultFontSizes.insert(MinimumFontSize, 0); - s_defaultFontSizes.insert(MinimumLogicalFontSize, 6); - s_defaultFontSizes.insert(DefaultFixedFontSize, 13); - s_defaultFontSizes.insert(DefaultFontSize, 16); + s_defaultFontSizes.insert(QWebEngineSettings::MinimumFontSize, 0); + s_defaultFontSizes.insert(QWebEngineSettings::MinimumLogicalFontSize, 6); + s_defaultFontSizes.insert(QWebEngineSettings::DefaultFixedFontSize, 13); + s_defaultFontSizes.insert(QWebEngineSettings::DefaultFontSize, 16); } m_defaultEncoding = QStringLiteral("ISO-8859-1"); - m_unknownUrlSchemePolicy = InheritedUnknownUrlSchemePolicy; + m_unknownUrlSchemePolicy = QWebEngineSettings::InheritedUnknownUrlSchemePolicy; } void WebEngineSettings::scheduleApply() @@ -363,46 +368,59 @@ void WebEngineSettings::applySettingsToWebPreferences(blink::web_pref::WebPrefer } // Attributes mapping. - prefs->loads_images_automatically = testAttribute(AutoLoadImages); - prefs->javascript_enabled = testAttribute(JavascriptEnabled); - prefs->javascript_can_access_clipboard = testAttribute(JavascriptCanAccessClipboard); - prefs->tabs_to_links = testAttribute(LinksIncludedInFocusChain); - prefs->local_storage_enabled = testAttribute(LocalStorageEnabled); - prefs->databases_enabled = testAttribute(LocalStorageEnabled); - prefs->allow_universal_access_from_file_urls = testAttribute(LocalContentCanAccessRemoteUrls); - prefs->spatial_navigation_enabled = testAttribute(SpatialNavigationEnabled); - prefs->allow_file_access_from_file_urls = testAttribute(LocalContentCanAccessFileUrls); - prefs->hyperlink_auditing_enabled = testAttribute(HyperlinkAuditingEnabled); - prefs->enable_scroll_animator = testAttribute(ScrollAnimatorEnabled); - prefs->enable_error_page = testAttribute(ErrorPageEnabled); - prefs->plugins_enabled = testAttribute(PluginsEnabled); - prefs->fullscreen_supported = testAttribute(FullScreenSupportEnabled); - prefs->accelerated_2d_canvas_enabled = testAttribute(Accelerated2dCanvasEnabled); - prefs->webgl1_enabled = prefs->webgl2_enabled = testAttribute(WebGLEnabled); - prefs->should_print_backgrounds = testAttribute(PrintElementBackgrounds); - prefs->allow_running_insecure_content = testAttribute(AllowRunningInsecureContent); - prefs->allow_geolocation_on_insecure_origins = testAttribute(AllowGeolocationOnInsecureOrigins); - prefs->hide_scrollbars = !testAttribute(ShowScrollBars); - if (isAttributeExplicitlySet(PlaybackRequiresUserGesture)) { - prefs->autoplay_policy = testAttribute(PlaybackRequiresUserGesture) + prefs->loads_images_automatically = testAttribute(QWebEngineSettings::AutoLoadImages); + prefs->javascript_enabled = testAttribute(QWebEngineSettings::JavascriptEnabled); + prefs->javascript_can_access_clipboard = + testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard); + prefs->tabs_to_links = testAttribute(QWebEngineSettings::LinksIncludedInFocusChain); + prefs->local_storage_enabled = testAttribute(QWebEngineSettings::LocalStorageEnabled); + prefs->databases_enabled = testAttribute(QWebEngineSettings::LocalStorageEnabled); + prefs->allow_universal_access_from_file_urls = + testAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls); + prefs->spatial_navigation_enabled = testAttribute(QWebEngineSettings::SpatialNavigationEnabled); + prefs->allow_file_access_from_file_urls = + testAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls); + prefs->hyperlink_auditing_enabled = testAttribute(QWebEngineSettings::HyperlinkAuditingEnabled); + prefs->enable_scroll_animator = testAttribute(QWebEngineSettings::ScrollAnimatorEnabled); + prefs->enable_error_page = testAttribute(QWebEngineSettings::ErrorPageEnabled); + prefs->plugins_enabled = testAttribute(QWebEngineSettings::PluginsEnabled); + prefs->fullscreen_supported = testAttribute(QWebEngineSettings::FullScreenSupportEnabled); + prefs->accelerated_2d_canvas_enabled = + testAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled); + prefs->webgl1_enabled = prefs->webgl2_enabled = testAttribute(QWebEngineSettings::WebGLEnabled); + prefs->should_print_backgrounds = testAttribute(QWebEngineSettings::PrintElementBackgrounds); + prefs->allow_running_insecure_content = + testAttribute(QWebEngineSettings::AllowRunningInsecureContent); + prefs->allow_geolocation_on_insecure_origins = + testAttribute(QWebEngineSettings::AllowGeolocationOnInsecureOrigins); + prefs->hide_scrollbars = !testAttribute(QWebEngineSettings::ShowScrollBars); + if (isAttributeExplicitlySet(QWebEngineSettings::PlaybackRequiresUserGesture)) { + prefs->autoplay_policy = testAttribute(QWebEngineSettings::PlaybackRequiresUserGesture) ? blink::web_pref::AutoplayPolicy::kUserGestureRequired : blink::web_pref::AutoplayPolicy::kNoUserGestureRequired; } - prefs->dom_paste_enabled = testAttribute(JavascriptCanPaste); - prefs->dns_prefetching_enabled = testAttribute(DnsPrefetchEnabled); + prefs->dom_paste_enabled = testAttribute(QWebEngineSettings::JavascriptCanPaste); + prefs->dns_prefetching_enabled = testAttribute(QWebEngineSettings::DnsPrefetchEnabled); // Fonts settings. - prefs->standard_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(StandardFont)); - prefs->fixed_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(FixedFont)); - prefs->serif_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(SerifFont)); - prefs->sans_serif_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(SansSerifFont)); - prefs->cursive_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(CursiveFont)); - prefs->fantasy_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(FantasyFont)); - prefs->pictograph_font_family_map[blink::web_pref::kCommonScript] = toString16(fontFamily(PictographFont)); - prefs->default_font_size = fontSize(DefaultFontSize); - prefs->default_fixed_font_size = fontSize(DefaultFixedFontSize); - prefs->minimum_font_size = fontSize(MinimumFontSize); - prefs->minimum_logical_font_size = fontSize(MinimumLogicalFontSize); + prefs->standard_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::StandardFont)); + prefs->fixed_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::FixedFont)); + prefs->serif_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::SerifFont)); + prefs->sans_serif_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::SansSerifFont)); + prefs->cursive_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::CursiveFont)); + prefs->fantasy_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::FantasyFont)); + prefs->pictograph_font_family_map[blink::web_pref::kCommonScript] = + toString16(fontFamily(QWebEngineSettings::PictographFont)); + prefs->default_font_size = fontSize(QWebEngineSettings::DefaultFontSize); + prefs->default_fixed_font_size = fontSize(QWebEngineSettings::DefaultFixedFontSize); + prefs->minimum_font_size = fontSize(QWebEngineSettings::MinimumFontSize); + prefs->minimum_logical_font_size = fontSize(QWebEngineSettings::MinimumLogicalFontSize); prefs->default_encoding = defaultTextEncoding().toStdString(); // Set the theme colors. Based on chrome_content_browser_client.cc: @@ -447,9 +465,10 @@ bool WebEngineSettings::applySettingsToRendererPreferences(blink::mojom::Rendere bool changed = false; #if QT_CONFIG(webengine_webrtc) if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) { - std::string webrtc_ip_handling_policy = testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly) - ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly - : blink::kWebRTCIPHandlingDefault; + std::string webrtc_ip_handling_policy = + testAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly) + ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly + : blink::kWebRTCIPHandlingDefault; if (prefs->webrtc_ip_handling_policy != webrtc_ip_handling_policy) { prefs->webrtc_ip_handling_policy = webrtc_ip_handling_policy; changed = true; @@ -469,7 +488,7 @@ void WebEngineSettings::scheduleApplyRecursively() bool WebEngineSettings::getJavaScriptCanOpenWindowsAutomatically() { - return testAttribute(JavascriptCanOpenWindows); + return testAttribute(QWebEngineSettings::JavascriptCanOpenWindows); } void WebEngineSettings::setParentSettings(WebEngineSettings *_parentSettings) @@ -479,6 +498,7 @@ void WebEngineSettings::setParentSettings(WebEngineSettings *_parentSettings) parentSettings = _parentSettings; if (parentSettings) parentSettings->childSettings.insert(this); + scheduleApplyRecursively(); } } // namespace QtWebEngineCore diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index d97ff5767..8dc98aae4 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -52,7 +52,7 @@ #define WEB_ENGINE_SETTINGS_H #include "qtwebenginecoreglobal_p.h" - +#include "qwebenginesettings.h" #include <QScopedPointer> #include <QHash> #include <QUrl> @@ -75,98 +75,36 @@ namespace QtWebEngineCore { class WebContentsAdapter; -class Q_WEBENGINECORE_PRIVATE_EXPORT WebEngineSettings { +class WebEngineSettings { public: - // Attributes. Names match the ones from the public widgets API. - enum Attribute { - UnsupportedInCoreSettings = -1, - AutoLoadImages, - JavascriptEnabled, - JavascriptCanOpenWindows, - JavascriptCanAccessClipboard, - LinksIncludedInFocusChain, - LocalStorageEnabled, - LocalContentCanAccessRemoteUrls, - XSSAuditingEnabled, - SpatialNavigationEnabled, - LocalContentCanAccessFileUrls, - HyperlinkAuditingEnabled, - ScrollAnimatorEnabled, - ErrorPageEnabled, - PluginsEnabled, - FullScreenSupportEnabled, - ScreenCaptureEnabled, - WebGLEnabled, - Accelerated2dCanvasEnabled, - AutoLoadIconsForPage, - TouchIconsEnabled, - FocusOnNavigationEnabled, - PrintElementBackgrounds, - AllowRunningInsecureContent, - AllowGeolocationOnInsecureOrigins, - AllowWindowActivationFromJavaScript, - ShowScrollBars, - PlaybackRequiresUserGesture, - WebRTCPublicInterfacesOnly, - JavascriptCanPaste, - DnsPrefetchEnabled, - PdfViewerEnabled, - }; - - // Must match the values from the public API in qwebenginesettings.h. - enum FontFamily { - StandardFont, - FixedFont, - SerifFont, - SansSerifFont, - CursiveFont, - FantasyFont, - PictographFont - }; - - // Must match the values from the public API in qwebenginesettings.h. - enum FontSize { - MinimumFontSize, - MinimumLogicalFontSize, - DefaultFontSize, - DefaultFixedFontSize - }; - - // Must match the values from the public API in qwebenginesettings.h. - enum UnknownUrlSchemePolicy { - InheritedUnknownUrlSchemePolicy = 0, - DisallowUnknownUrlSchemes = 1, - AllowUnknownUrlSchemesFromUserInteraction, - AllowAllUnknownUrlSchemes - }; - - explicit WebEngineSettings(WebEngineSettings *parentSettings = 0); + static WebEngineSettings* get(QWebEngineSettings *settings) { return settings->d_ptr.data(); } + + explicit WebEngineSettings(WebEngineSettings *parentSettings = nullptr); ~WebEngineSettings(); void setParentSettings(WebEngineSettings *parentSettings); void overrideWebPreferences(content::WebContents *webContents, blink::web_pref::WebPreferences *prefs); - void setAttribute(Attribute, bool on); - bool testAttribute(Attribute) const; - void resetAttribute(Attribute); - bool isAttributeExplicitlySet(Attribute) const; + void setAttribute(QWebEngineSettings::WebAttribute, bool on); + bool testAttribute(QWebEngineSettings::WebAttribute) const; + void resetAttribute(QWebEngineSettings::WebAttribute); + bool isAttributeExplicitlySet(QWebEngineSettings::WebAttribute) const; - void setFontFamily(FontFamily, const QString &); - QString fontFamily(FontFamily); - void resetFontFamily(FontFamily); + void setFontFamily(QWebEngineSettings::FontFamily, const QString &); + QString fontFamily(QWebEngineSettings::FontFamily); + void resetFontFamily(QWebEngineSettings::FontFamily); - void setFontSize(FontSize type, int size); - int fontSize(FontSize type) const; - void resetFontSize(FontSize type); + void setFontSize(QWebEngineSettings::FontSize type, int size); + int fontSize(QWebEngineSettings::FontSize type) const; + void resetFontSize(QWebEngineSettings::FontSize type); void setDefaultTextEncoding(const QString &encoding); QString defaultTextEncoding() const; - void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); - UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; + void setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy); + QWebEngineSettings::UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; - void initDefaults(); void scheduleApply(); void scheduleApplyRecursively(); @@ -174,15 +112,16 @@ public: bool getJavaScriptCanOpenWindowsAutomatically(); private: + void initDefaults(); void doApply(); void applySettingsToWebPreferences(blink::web_pref::WebPreferences *); bool applySettingsToRendererPreferences(blink::mojom::RendererPreferences *); void setWebContentsAdapter(WebContentsAdapter *adapter) { m_adapter = adapter; } WebContentsAdapter* m_adapter; - QHash<Attribute, bool> m_attributes; - QHash<FontFamily, QString> m_fontFamilies; - QHash<FontSize, int> m_fontSizes; + QHash<QWebEngineSettings::WebAttribute, bool> m_attributes; + QHash<QWebEngineSettings::FontFamily, QString> m_fontFamilies; + QHash<QWebEngineSettings::FontSize, int> m_fontSizes; QString m_defaultEncoding; QScopedPointer<blink::web_pref::WebPreferences> webPreferences; QTimer m_batchTimer; @@ -190,10 +129,10 @@ private: WebEngineSettings *parentSettings; QSet<WebEngineSettings *> childSettings; - static QHash<Attribute, bool> s_defaultAttributes; - static QHash<FontFamily, QString> s_defaultFontFamilies; - static QHash<FontSize, int> s_defaultFontSizes; - UnknownUrlSchemePolicy m_unknownUrlSchemePolicy; + static QHash<QWebEngineSettings::WebAttribute, bool> s_defaultAttributes; + static QHash<QWebEngineSettings::FontFamily, QString> s_defaultFontFamilies; + static QHash<QWebEngineSettings::FontSize, int> s_defaultFontSizes; + QWebEngineSettings::UnknownUrlSchemePolicy m_unknownUrlSchemePolicy; friend class WebContentsAdapter; }; diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 3beb913a7..593acb5e5 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -82,7 +82,7 @@ #include <QMouseEvent> #include <QStyleHints> #if QT_CONFIG(tabletevent) -#include <QTabletEvent> +#include <QPointingDevice> #endif #include <QWheelEvent> @@ -1443,12 +1443,14 @@ static WebInputEvent::Type webEventTypeForEvent(const QEvent* event) static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTabletEvent *ev) { switch (ev->pointerType()) { - case QTabletEvent::UnknownPointer: + case QPointingDevice::PointerType::Unknown: return WebPointerProperties::PointerType::kUnknown; - case QTabletEvent::Pen: + case QPointingDevice::PointerType::Pen: return WebPointerProperties::PointerType::kPen; - case QTabletEvent::Eraser: + case QPointingDevice::PointerType::Eraser: return WebPointerProperties::PointerType::kEraser; + case QPointingDevice::PointerType::Finger: + return WebPointerProperties::PointerType::kTouch; default: return WebPointerProperties::PointerType::kMouse; } @@ -1458,8 +1460,8 @@ static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTablet WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - gfx::PointF(ev->x(), ev->y()), - gfx::PointF(ev->globalX(), ev->globalY()), + gfx::PointF(ev->position().x(), ev->position().y()), + gfx::PointF(ev->globalPosition().x(), ev->globalPosition().y()), mouseButtonForEvent<QMouseEvent>(ev), 0, modifiersForEvent(ev), @@ -1477,9 +1479,9 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev) webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetType(webEventTypeForEvent(ev)); - webKitEvent.SetPositionInWidget(ev->pos().x(), ev->pos().y()); - webKitEvent.movement_x = ev->pos().x() - ev->oldPos().x(); - webKitEvent.movement_y = ev->pos().y() - ev->oldPos().y(); + webKitEvent.SetPositionInWidget(ev->position().x(), ev->position().y()); + webKitEvent.movement_x = ev->position().x() - ev->oldPos().x(); + webKitEvent.movement_y = ev->position().y() - ev->oldPos().y(); webKitEvent.pointer_type = WebPointerProperties::PointerType::kMouse; return webKitEvent; @@ -1489,8 +1491,8 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev) WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - gfx::PointF(ev->x(), ev->y()), - gfx::PointF(ev->globalX(), ev->globalY()), + gfx::PointF(ev->position().x(), ev->position().y()), + gfx::PointF(ev->globalPosition().x(), ev->globalPosition().y()), mouseButtonForEvent<QTabletEvent>(ev), 0, modifiersForEvent(ev), @@ -1523,9 +1525,11 @@ WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev) webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); - webKitEvent.SetPositionInWidget(gfx::PointF(ev->localPos().x(), ev->localPos().y())); + webKitEvent.SetPositionInWidget(gfx::PointF(ev->position().x(), + ev->position().y())); - webKitEvent.SetPositionInScreen(gfx::PointF(ev->screenPos().x(), ev->screenPos().y())); + webKitEvent.SetPositionInScreen(gfx::PointF(ev->globalPosition().x(), + ev->globalPosition().y())); webKitEvent.SetSourceDevice(blink::WebGestureDevice::kTouchpad); |