diff options
Diffstat (limited to 'src/core')
190 files changed, 10816 insertions, 1728 deletions
diff --git a/src/core/accessibility_activation_observer.cpp b/src/core/accessibility_activation_observer.cpp new file mode 100644 index 000000000..75ad90c54 --- /dev/null +++ b/src/core/accessibility_activation_observer.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 "accessibility_activation_observer.h" + +#ifndef QT_NO_ACCESSIBILITY + +#include "content/browser/accessibility/browser_accessibility_state_impl.h" + +namespace QtWebEngineCore { + +namespace { + +bool isAccessibilityEnabled() { + // On Linux accessibility is disabled by default due to performance issues, + // and can be re-enabled by setting the QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment + // variable. For details, see QTBUG-59922. +#ifdef Q_OS_LINUX + static bool accessibility_enabled + = qEnvironmentVariableIsSet("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY"); +#else + const bool accessibility_enabled = true; +#endif + return accessibility_enabled; +} + +} // namespace + +AccessibilityActivationObserver::AccessibilityActivationObserver() +{ + if (isAccessibilityEnabled()) { + QAccessible::installActivationObserver(this); + if (QAccessible::isActive()) + content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); + } +} + +AccessibilityActivationObserver::~AccessibilityActivationObserver() +{ + QAccessible::removeActivationObserver(this); +} + +void AccessibilityActivationObserver::accessibilityActiveChanged(bool active) +{ + if (active) + content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); + else + content::BrowserAccessibilityStateImpl::GetInstance()->DisableAccessibility(); +} + +} // namespace QtWebEngineCore + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/core/net/qrc_protocol_handler_qt.cpp b/src/core/accessibility_activation_observer.h index eb716f182..e42c83eb5 100644 --- a/src/core/net/qrc_protocol_handler_qt.cpp +++ b/src/core/accessibility_activation_observer.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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,27 +37,27 @@ ** ****************************************************************************/ -#include "qrc_protocol_handler_qt.h" -#include "url_request_qrc_job_qt.h" +#ifndef ACCESSIBILITY_ACTIVATION_OBSERVER_H +#define ACCESSIBILITY_ACTIVATION_OBSERVER_H -#include "net/base/net_errors.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_error_job.h" +#ifndef QT_NO_ACCESSIBILITY +#include <QtGui/qaccessible.h> namespace QtWebEngineCore { -const char kQrcSchemeQt[] = "qrc"; +class RenderWidgetHostViewQt; -QrcProtocolHandlerQt::QrcProtocolHandlerQt() +class AccessibilityActivationObserver : public QAccessible::ActivationObserver { -} +public: + AccessibilityActivationObserver(); + ~AccessibilityActivationObserver(); -net::URLRequestJob *QrcProtocolHandlerQt::MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const -{ - if (!networkDelegate) - return new net::URLRequestErrorJob(request, Q_NULLPTR, net::ERR_ACCESS_DENIED); - - return new URLRequestQrcJobQt(request, networkDelegate); -} + void accessibilityActiveChanged(bool active) override; +}; } // namespace QtWebEngineCore + +#endif // QT_NO_ACCESSIBILITY + +#endif // ACCESSIBILITY_ACTIVATION_OBSERVER_H diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index 4b69b348a..326d4481f 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -32,12 +32,14 @@ gcc: QMAKE_CXXFLAGS_WARN_ON = -Wno-unused-parameter HEADERS = \ qwebenginecallback.h \ qwebenginecallback_p.h \ + qwebengineclientcertificatestore.h \ qtwebenginecoreglobal.h \ qtwebenginecoreglobal_p.h \ qwebenginecookiestore.h \ qwebenginecookiestore_p.h \ qwebenginehttprequest.h \ qwebenginemessagepumpscheduler_p.h \ + qwebenginenotification.h \ qwebenginequotarequest.h \ qwebengineregisterprotocolhandlerrequest.h \ qwebengineurlrequestinterceptor.h \ @@ -49,9 +51,11 @@ HEADERS = \ SOURCES = \ qtwebenginecoreglobal.cpp \ + qwebengineclientcertificatestore.cpp \ qwebenginecookiestore.cpp \ qwebenginehttprequest.cpp \ qwebenginemessagepumpscheduler.cpp \ + qwebenginenotification.cpp \ qwebenginequotarequest.cpp \ qwebengineregisterprotocolhandlerrequest.cpp \ qwebengineurlrequestinfo.cpp \ diff --git a/src/core/api/qwebengineclientcertificatestore.cpp b/src/core/api/qwebengineclientcertificatestore.cpp new file mode 100644 index 000000000..cac8fb151 --- /dev/null +++ b/src/core/api/qwebengineclientcertificatestore.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** 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 "qwebengineclientcertificatestore.h" + +#include "net/client_cert_store_data.h" + +#include <QByteArray> +#include <QList> + +QT_BEGIN_NAMESPACE + +#if QT_CONFIG(ssl) + +/*! + \class QWebEngineClientCertificateStore::Entry + \inmodule QtWebEngineCore + \since 5.13 + \brief This structure holds the certificate and the private key. +*/ + +/*! + \class QWebEngineClientCertificateStore + \inmodule QtWebEngineCore + \since 5.13 + \brief The QWebEngineClientCertificateStore class provides an in-memory store for client certificates. + + The class allows to store client certificates in an in-memory store. + When a web site requests an SSL client certificate, the QWebEnginePage::selectClientCertificate + signal is emitted with matching certificates from the native certificate store or the in-memory store. + The getInstance() method can be used to access the single instance of the class. +*/ + +QWebEngineClientCertificateStore::QWebEngineClientCertificateStore(QtWebEngineCore::ClientCertificateStoreData *storeData) + : m_storeData(storeData) +{ +} + +/*! + Destroys this QWebEngineClientCertificateStore object. +*/ + +QWebEngineClientCertificateStore::~QWebEngineClientCertificateStore() +{ + // Just in case user has not deleted in-memory certificates + clear(); +} + +/*! + Adds a \a certificate with the \a privateKey to the in-memory client certificate store. +*/ + +void QWebEngineClientCertificateStore::add(const QSslCertificate &certificate, const QSslKey &privateKey) +{ + m_storeData->add(certificate, privateKey); +} + +/*! + Returns a list of private and public keys of client certificates in the in-memory store. + Returns an empty list if the in-memory store does not contain certificates. +*/ + +QList<QWebEngineClientCertificateStore::Entry> QWebEngineClientCertificateStore::toList() const +{ + QList<Entry> certificateList; + for (auto data : qAsConst(m_storeData->extraCerts)) { + Entry entry; + entry.certificate = data->certificate; + entry.privateKey = data->key; + certificateList.append(entry); + } + return certificateList; +} + +/*! + Deletes all the instances of the client certificate in the in-memory client certificate store + that matches the certificate \a certificate. +*/ + +void QWebEngineClientCertificateStore::remove(const QSslCertificate &certificate) +{ + m_storeData->remove(certificate); +} + +/*! + Clears all the client certificates from the in-memory store. +*/ + +void QWebEngineClientCertificateStore::clear() +{ + m_storeData->clear(); +} + +#endif // QT_CONFIG(ssl) + +QT_END_NAMESPACE diff --git a/src/core/api/qwebengineclientcertificatestore.h b/src/core/api/qwebengineclientcertificatestore.h new file mode 100644 index 000000000..441a5f913 --- /dev/null +++ b/src/core/api/qwebengineclientcertificatestore.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWEBENGINECLIENTCERTIFICATESTORE_H +#define QWEBENGINECLIENTCERTIFICATESTORE_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/qscopedpointer.h> +#include <QtNetwork/qsslcertificate.h> +#include <QtNetwork/qsslkey.h> + +namespace QtWebEngineCore { +struct ClientCertificateStoreData; +class ProfileAdapter; +} + +QT_BEGIN_NAMESPACE + +#if QT_CONFIG(ssl) + +class QWebEngineProfile; +class QWEBENGINECORE_EXPORT QWebEngineClientCertificateStore { + +public: + struct Entry { + QSslKey privateKey; + QSslCertificate certificate; + }; + + void add(const QSslCertificate &certificate, const QSslKey &privateKey); + QList<Entry> toList() const; + void remove(const QSslCertificate &certificate); + void clear(); + +private: + friend class QtWebEngineCore::ProfileAdapter; + Q_DISABLE_COPY(QWebEngineClientCertificateStore) + + QWebEngineClientCertificateStore(QtWebEngineCore::ClientCertificateStoreData *storeData); + ~QWebEngineClientCertificateStore(); + QtWebEngineCore::ClientCertificateStoreData *m_storeData; +}; + +#endif // QT_CONFIG(ssl) + +QT_END_NAMESPACE + +#endif // QWebEngineClientCertificateStore_H diff --git a/src/core/api/qwebenginenotification.cpp b/src/core/api/qwebenginenotification.cpp new file mode 100644 index 000000000..0b91cf273 --- /dev/null +++ b/src/core/api/qwebenginenotification.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** 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 "qwebenginenotification.h" + +#include "user_notification_controller.h" + +#include <QExplicitlySharedDataPointer> + +QT_BEGIN_NAMESPACE + +using QtWebEngineCore::UserNotificationController; + +/*! + \class QWebEngineNotification + \brief The QWebEngineNotification class encapsulates the data of an HTML5 web notification. + \since 5.13 + + \inmodule QtWebEngineCore + + This class contains the information and API for HTML5 desktop and push notifications. +*/ + +class QWebEngineNotificationPrivate : public UserNotificationController::Client { +public: + QWebEngineNotificationPrivate(QWebEngineNotification *q, const QSharedPointer<UserNotificationController> &controller) + : controller(controller) + , q(q) + { + controller->setClient(this); + } + ~QWebEngineNotificationPrivate() override + { + if (controller->client() == this) + controller->setClient(0); + } + + // UserNotificationController::Client: + virtual void notificationClosed(const UserNotificationController *) Q_DECL_OVERRIDE + { + Q_EMIT q->closed(); + } + + QSharedPointer<UserNotificationController> controller; + QWebEngineNotification *q; +}; + + +/*! + Creates a null QWebEngineNotification. + + \sa isNull() +*/ +QWebEngineNotification::QWebEngineNotification() { } + +/*! \internal +*/ +QWebEngineNotification::QWebEngineNotification(const QSharedPointer<UserNotificationController> &controller) + : d_ptr(new QWebEngineNotificationPrivate(this, controller)) +{ } + +/*! \internal +*/ +QWebEngineNotification::QWebEngineNotification(const QWebEngineNotification &other) + : QObject() + , d_ptr(new QWebEngineNotificationPrivate(this, other.d_ptr->controller)) +{ } + +/*! \internal +*/ +QWebEngineNotification::~QWebEngineNotification() +{ +} + +/*! \internal +*/ +const QWebEngineNotification &QWebEngineNotification::operator=(const QWebEngineNotification &other) +{ + d_ptr.reset(new QWebEngineNotificationPrivate(this, other.d_ptr->controller)); + return *this; +} + +/*! + Returns \c true if the two notifications belong to the same message chain. + That is, if their tag() and origin() are the same. This means one is + a replacement or an update of the \a other. + + \sa tag(), origin() +*/ +bool QWebEngineNotification::matches(const QWebEngineNotification &other) const +{ + if (!d_ptr) + return !other.d_ptr; + if (!other.d_ptr) + return false; + return tag() == other.tag() && origin() == other.origin(); +} + +/*! + \property QWebEngineNotification::title + \brief The title of the notification. + \sa message() +*/ +QString QWebEngineNotification::title() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->title() : QString(); +} + +/*! + \property QWebEngineNotification::message + \brief The body of the notification message. + \sa title() +*/ + +QString QWebEngineNotification::message() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->body() : QString(); +} + +/*! + \property QWebEngineNotification::tag + \brief The tag of the notification message. + + New notifications that have the same tag and origin URL as an existing + one should replace or update the old notification with the same tag. + + \sa matches() +*/ +QString QWebEngineNotification::tag() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->tag() : QString(); +} + +/*! + \property QWebEngineNotification::origin + \brief The URL of the page sending the notification. +*/ + +QUrl QWebEngineNotification::origin() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->origin() : QUrl(); +} + +/*! + \property QWebEngineNotification::icon + \brief The icon to be shown with the notification. + + If no icon is set by the sender, an null QIcon is returned. +*/ +QIcon QWebEngineNotification::icon() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->icon() : QIcon(); +} + +/*! + \property QWebEngineNotification::language + \brief The primary language for the notification's title and body. + + Its value is a valid BCP 47 language tag, or the empty string. + + \sa title(), message() +*/ +QString QWebEngineNotification::language() const +{ + Q_D(const QWebEngineNotification); + return d ? d->controller->language() : QString(); +} + +/*! + \property QWebEngineNotification::direction + \brief The text direction for the notification's title and body. + \sa title(), message() +*/ +QWebEngineNotification::Direction QWebEngineNotification::direction() const +{ + Q_D(const QWebEngineNotification); + return d ? static_cast<Direction>(d->controller->direction()) : DirectionAuto; +} + +/*! + Returns \c true if the notification is a default constructed null notification. +*/ +bool QWebEngineNotification::isNull() const +{ + return d_ptr.isNull(); +} + +/*! + Creates and dispatches a JavaScript \e {show event} on notification. + + Should be called by the notification platform when the notification has been shown to user. +*/ +void QWebEngineNotification::show() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationDisplayed(); +} + +/*! + Creates and dispatches a JavaScript \e {click event} on notification. + + Should be called by the notification platform when the notification is activated by the user. +*/ +void QWebEngineNotification::click() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationClicked(); +} + +/*! + Creates and dispatches a JavaScript \e {close event} on notification. + + Should be called by the notification platform when the notification is closed, + either by the underlying platform or by the user. +*/ +void QWebEngineNotification::close() const +{ + Q_D(const QWebEngineNotification); + if (d) + d->controller->notificationClosed(); +} + +/*! + \fn void QWebEngineNotification::closed() + + This signal is emitted when the web page calls close steps for the notification, + and it no longer needs to be shown. +*/ + +QT_END_NAMESPACE + +#include "moc_qwebenginenotification.cpp" diff --git a/src/core/api/qwebenginenotification.h b/src/core/api/qwebenginenotification.h new file mode 100644 index 000000000..b6b7414f9 --- /dev/null +++ b/src/core/api/qwebenginenotification.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWEBENGINENOTIFICATION_H +#define QWEBENGINENOTIFICATION_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> + +#include <QtCore/QObject> +#include <QtCore/QScopedPointer> +#include <QtCore/QSharedPointer> +#include <QtCore/QUrl> +#include <QtGui/QIcon> + +namespace QtWebEngineCore { +class UserNotificationController; +} + +QT_BEGIN_NAMESPACE + +class QWebEngineNotificationPrivate; + +class QWEBENGINECORE_EXPORT QWebEngineNotification : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL) + Q_PROPERTY(QIcon icon READ icon CONSTANT FINAL) + Q_PROPERTY(QString title READ title CONSTANT FINAL) + Q_PROPERTY(QString message READ message CONSTANT FINAL) + Q_PROPERTY(QString tag READ tag CONSTANT FINAL) + Q_PROPERTY(QString language READ language CONSTANT FINAL) + Q_PROPERTY(Direction direction READ direction CONSTANT FINAL) + +public: + QWebEngineNotification(); + QWebEngineNotification(const QWebEngineNotification &); + virtual ~QWebEngineNotification(); + const QWebEngineNotification &operator=(const QWebEngineNotification &); + + enum Direction { + LeftToRight = Qt::LeftToRight, + RightToLeft = Qt::RightToLeft, + DirectionAuto = Qt::LayoutDirectionAuto + }; + Q_ENUM(Direction) + + bool matches(const QWebEngineNotification &) const; + + QUrl origin() const; + QIcon icon() const; + QString title() const; + QString message() const; + QString tag() const; + QString language() const; + Direction direction() const; + + bool isNull() const; + +public Q_SLOTS: + void show() const; + void click() const; + void close() const; + +Q_SIGNALS: + void closed(); + +private: + QWebEngineNotification(const QSharedPointer<QtWebEngineCore::UserNotificationController> &); + Q_DECLARE_PRIVATE(QWebEngineNotification) + QScopedPointer<QWebEngineNotificationPrivate> d_ptr; + friend class QQuickWebEngineProfilePrivate; + friend class QWebEngineProfilePrivate; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINENOTIFICATION_H diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index ea9081fc1..dc2d07740 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -96,8 +96,8 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q interceptor on the profile enables intercepting, blocking, and modifying URL requests before they reach the networking stack of Chromium. - You can install the interceptor on a profile via QWebEngineProfile::setRequestInterceptor() - or QQuickWebEngineProfile::setRequestInterceptor(). + You can install the interceptor on a profile via QWebEngineProfile::setUrlRequestInterceptor() + or QQuickWebEngineProfile::setUrlRequestInterceptor(). When using the \l{Qt WebEngine Widgets Module}, \l{QWebEnginePage::acceptNavigationRequest()} offers further options to accept or block requests. @@ -115,8 +115,7 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q \fn void QWebEngineUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) Reimplementing this virtual function makes it possible to intercept URL - requests. This function is executed on the IO thread, and therefore running - long tasks here will block networking. + requests. This method will be stalling the URL request until handled. \a info contains the information about the URL request and will track internally whether its members have been altered. @@ -140,10 +139,17 @@ QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRe /*! \internal */ +QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfo &&p) + : d_ptr(p.d_ptr.take()) +{ +} + +/*! + \internal +*/ QWebEngineUrlRequestInfo::~QWebEngineUrlRequestInfo() { - } /*! @@ -260,6 +266,14 @@ bool QWebEngineUrlRequestInfo::changed() const } /*! + \internal +*/ +void QWebEngineUrlRequestInfo::resetChanged() +{ + d_ptr->changed = false; +} + +/*! Redirects this request to \a url. It is only possible to redirect requests that do not have payload data, such as GET requests. */ diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h index 68c46dcf4..e1f9ca6ef 100644 --- a/src/core/api/qwebengineurlrequestinfo.h +++ b/src/core/api/qwebengineurlrequestinfo.h @@ -47,6 +47,7 @@ namespace QtWebEngineCore { class NetworkDelegateQt; +class URLRequestNotification; } QT_BEGIN_NAMESPACE @@ -104,10 +105,14 @@ public: private: friend class QtWebEngineCore::NetworkDelegateQt; + friend class QtWebEngineCore::URLRequestNotification; Q_DISABLE_COPY(QWebEngineUrlRequestInfo) Q_DECLARE_PRIVATE(QWebEngineUrlRequestInfo) + void resetChanged(); + QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p); + QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfo &&p); ~QWebEngineUrlRequestInfo(); QScopedPointer<QWebEngineUrlRequestInfoPrivate> d_ptr; }; diff --git a/src/core/api/qwebengineurlrequestinterceptor.h b/src/core/api/qwebengineurlrequestinterceptor.h index dc2a15ee3..2b07681ca 100644 --- a/src/core/api/qwebengineurlrequestinterceptor.h +++ b/src/core/api/qwebengineurlrequestinterceptor.h @@ -55,7 +55,7 @@ class QWEBENGINECORE_EXPORT QWebEngineUrlRequestInterceptor : public QObject Q_OBJECT Q_DISABLE_COPY(QWebEngineUrlRequestInterceptor) public: - explicit QWebEngineUrlRequestInterceptor(QObject *p = Q_NULLPTR) + explicit QWebEngineUrlRequestInterceptor(QObject *p = nullptr) : QObject (p) { } diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp index c3541598b..bc860b3b3 100644 --- a/src/core/api/qwebengineurlrequestjob.cpp +++ b/src/core/api/qwebengineurlrequestjob.cpp @@ -140,6 +140,15 @@ QUrl QWebEngineUrlRequestJob::initiator() const } /*! + \since 5.13 + Returns any HTTP headers added to the request. +*/ +QMap<QByteArray, QByteArray> QWebEngineUrlRequestJob::requestHeaders() const +{ + return d_ptr->requestHeaders(); +} + +/*! Replies to the request with \a device and the MIME type \a contentType. The user has to be aware that \a device will be used on another thread diff --git a/src/core/api/qwebengineurlrequestjob.h b/src/core/api/qwebengineurlrequestjob.h index 7ce8be7ec..b2dd8baa3 100644 --- a/src/core/api/qwebengineurlrequestjob.h +++ b/src/core/api/qwebengineurlrequestjob.h @@ -73,6 +73,7 @@ public: QUrl requestUrl() const; QByteArray requestMethod() const; QUrl initiator() const; + QMap<QByteArray, QByteArray> requestHeaders() const; void reply(const QByteArray &contentType, QIODevice *device); void fail(Error error); diff --git a/src/core/api/qwebengineurlschemehandler.cpp b/src/core/api/qwebengineurlschemehandler.cpp index b5912703d..aecee5044 100644 --- a/src/core/api/qwebengineurlschemehandler.cpp +++ b/src/core/api/qwebengineurlschemehandler.cpp @@ -111,7 +111,6 @@ QWebEngineUrlSchemeHandler::QWebEngineUrlSchemeHandler(QObject *parent) */ QWebEngineUrlSchemeHandler::~QWebEngineUrlSchemeHandler() { - Q_EMIT _q_destroyedUrlSchemeHandler(this); } /*! diff --git a/src/core/api/qwebengineurlschemehandler.h b/src/core/api/qwebengineurlschemehandler.h index 23fee4b95..549778561 100644 --- a/src/core/api/qwebengineurlschemehandler.h +++ b/src/core/api/qwebengineurlschemehandler.h @@ -60,11 +60,6 @@ public: virtual void requestStarted(QWebEngineUrlRequestJob*) = 0; -#ifndef Q_QDOC -Q_SIGNALS: - void _q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*); -#endif - private: Q_DISABLE_COPY(QWebEngineUrlSchemeHandler) }; diff --git a/src/core/authentication_dialog_controller.cpp b/src/core/authentication_dialog_controller.cpp index bd23d1768..1133b0bc1 100644 --- a/src/core/authentication_dialog_controller.cpp +++ b/src/core/authentication_dialog_controller.cpp @@ -40,7 +40,9 @@ #include "authentication_dialog_controller.h" #include "authentication_dialog_controller_p.h" +#include "base/task/post_task.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/browser_task_traits.h" namespace QtWebEngineCore { @@ -51,9 +53,10 @@ AuthenticationDialogControllerPrivate::AuthenticationDialogControllerPrivate(Log void AuthenticationDialogControllerPrivate::dialogFinished(bool accepted, const QString &user, const QString &password) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&LoginDelegateQt::sendAuthToRequester, loginDelegate, accepted, user, password)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&LoginDelegateQt::sendAuthToRequester, + loginDelegate, accepted, user, password)); } AuthenticationDialogController::AuthenticationDialogController(AuthenticationDialogControllerPrivate *dd) diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp index 29fbbc542..75527ea95 100644 --- a/src/core/browser_accessibility_qt.cpp +++ b/src/core/browser_accessibility_qt.cpp @@ -61,6 +61,11 @@ const BrowserAccessibilityQt *ToBrowserAccessibilityQt(const BrowserAccessibilit return static_cast<const BrowserAccessibilityQt *>(obj); } +QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *obj) +{ + return static_cast<BrowserAccessibilityQt *>(obj); +} + BrowserAccessibilityQt::BrowserAccessibilityQt() { QAccessible::registerAccessibleInterface(this); @@ -357,6 +362,8 @@ QAccessible::Role BrowserAccessibilityQt::role() const return QAccessible::EditableText; case ax::mojom::Role::kInputTime: return QAccessible::SpinBox; + case ax::mojom::Role::kKeyboard: + return QAccessible::NoRole; // FIXME case ax::mojom::Role::kLabelText: return QAccessible::StaticText; case ax::mojom::Role::kLayoutTable: diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h index 345ee9862..decfc1e9d 100644 --- a/src/core/browser_accessibility_qt.h +++ b/src/core/browser_accessibility_qt.h @@ -146,6 +146,7 @@ public: }; const BrowserAccessibilityQt *ToBrowserAccessibilityQt(const BrowserAccessibility *obj); +QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *acc); } // namespace content diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp index 3d85c04c4..4dbff086b 100644 --- a/src/core/browser_main_parts_qt.cpp +++ b/src/core/browser_main_parts_qt.cpp @@ -46,7 +46,16 @@ #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_main_parts.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_security_policy.h" #include "content/public/common/service_manager_connection.h" +#include "extensions/buildflags/buildflags.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/common/constants.h" +#include "extensions/common/extensions_client.h" +#include "extensions/extensions_browser_client_qt.h" +#include "extensions/extension_system_factory_qt.h" +#include "common/extensions/extensions_client_qt.h" +#endif //BUILDFLAG(ENABLE_EXTENSIONS) #include "services/resource_coordinator/public/cpp/process_resource_coordinator.h" #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" #include "services/service_manager/public/cpp/connector.h" @@ -57,6 +66,12 @@ #include "web_engine_context.h" #include <QEventLoop> +#include <QtGui/qtgui-config.h> + +#if QT_CONFIG(opengl) +#include "ui/gl/gl_context.h" +#include <QOpenGLContext> +#endif #if defined(OS_MACOSX) #include "ui/base/idle/idle.h" @@ -131,8 +146,55 @@ public: } private: + // Both Qt and Chromium keep track of the current GL context by using + // thread-local variables, and naturally they are completely unaware of each + // other. As a result, when a QOpenGLContext is made current, the previous + // gl::GLContext is not released, and vice-versa. This is fine as long as + // each thread uses exclusively either Qt or Chromium GL bindings, which is + // usually the case. + // + // The only exception is when the GL driver is considered thread-unsafe + // (QOpenGLContext::supportsThreadedOpenGL() is false), in which case we + // have to run all GL operations, including Chromium's GPU service, on the + // UI thread. Now the bindings are being mixed and both Qt and Chromium get + // quite confused regarding the current state of the surface. + // + // To get this to work we have to release the current QOpenGLContext before + // executing any tasks from Chromium's GPU service and the gl::GLContext + // afterwards. Since GPU service just posts tasks to the UI thread task + // runner, we'll have to instrument the entire UI thread message pump. + class ScopedGLContextChecker + { +#if QT_CONFIG(opengl) + public: + ScopedGLContextChecker() + { + if (!m_enabled) + return; + + if (QOpenGLContext *context = QOpenGLContext::currentContext()) + context->doneCurrent(); + } + + ~ScopedGLContextChecker() + { + if (!m_enabled) + return; + + if (gl::GLContext *context = gl::GLContext::GetCurrent()) + context->ReleaseCurrent(nullptr); + } + + private: + bool m_enabled = !QOpenGLContext::supportsThreadedOpenGL(); +#endif // QT_CONFIG(opengl) + }; + + void handleScheduledWork() { + ScopedGLContextChecker glContextChecker; + bool more_work_is_plausible = m_delegate->DoWork(); base::TimeTicks delayed_work_time; @@ -168,6 +230,9 @@ BrowserMainPartsQt::~BrowserMainPartsQt() = default; int BrowserMainPartsQt::PreEarlyInitialization() { +#if BUILDFLAG(ENABLE_EXTENSIONS) + content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(extensions::kExtensionScheme); +#endif //ENABLE_EXTENSIONS base::MessageLoop::InitMessagePumpForUIFactory(messagePumpFactory); return 0; } @@ -176,6 +241,15 @@ void BrowserMainPartsQt::PreMainMessageLoopStart() { } +void BrowserMainPartsQt::PreMainMessageLoopRun() +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionsClient::Set(new extensions::ExtensionsClientQt()); + extensions::ExtensionsBrowserClient::Set(new extensions::ExtensionsBrowserClientQt()); + extensions::ExtensionSystemFactoryQt::GetInstance(); +#endif //ENABLE_EXTENSIONS +} + void BrowserMainPartsQt::PostMainMessageLoopRun() { // The ProfileQt's destructor uses the MessageLoop so it should be deleted @@ -204,11 +278,9 @@ void BrowserMainPartsQt::ServiceManagerConnectionStarted(content::ServiceManager { ServiceQt::GetInstance()->InitConnector(); connection->GetConnector()->StartService(service_manager::Identity("qtwebengine")); - if (resource_coordinator::IsResourceCoordinatorEnabled()) { - m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector()); - m_processResourceCoordinator->SetLaunchTime(base::Time::Now()); - m_processResourceCoordinator->SetPID(base::Process::Current().Pid()); - } + m_processResourceCoordinator = std::make_unique<resource_coordinator::ProcessResourceCoordinator>(connection->GetConnector()); + m_processResourceCoordinator->SetLaunchTime(base::Time::Now()); + m_processResourceCoordinator->SetPID(base::Process::Current().Pid()); } } // namespace QtWebEngineCore diff --git a/src/core/browser_main_parts_qt.h b/src/core/browser_main_parts_qt.h index 04ca9483d..374220c3b 100644 --- a/src/core/browser_main_parts_qt.h +++ b/src/core/browser_main_parts_qt.h @@ -66,6 +66,7 @@ public: int PreEarlyInitialization() override; void PreMainMessageLoopStart() override; + void PreMainMessageLoopRun() override; void PostMainMessageLoopRun() override; int PreCreateThreads() override; void ServiceManagerConnectionStarted(content::ServiceManagerConnection *connection) override; diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp index 841dcf4c9..09058301b 100644 --- a/src/core/chromium_overrides.cpp +++ b/src/core/chromium_overrides.cpp @@ -37,8 +37,6 @@ ** ****************************************************************************/ -#include "chromium_overrides.h" - #include "ozone/gl_context_qt.h" #include "qtwebenginecoreglobal_p.h" #include "web_contents_view_qt.h" @@ -59,6 +57,7 @@ #include <QWindow> #include <QFontDatabase> #include <QStringList> +#include <QLibraryInfo> #if defined(USE_AURA) && !defined(USE_OZONE) #include "ui/base/dragdrop/os_exchange_data.h" @@ -71,27 +70,6 @@ #include "net/ssl/openssl_client_key_store.h" #endif -namespace QtWebEngineCore { -void GetScreenInfoFromNativeWindow(QWindow* window, content::ScreenInfo* results) -{ - QScreen* screen = window->screen(); - if (!screen) - return; - content::ScreenInfo r; - r.device_scale_factor = screen->devicePixelRatio(); - r.depth_per_component = 8; - r.depth = screen->depth(); - r.is_monochrome = (r.depth == 1); - - QRect screenGeometry = screen->geometry(); - r.rect = gfx::Rect(screenGeometry.x(), screenGeometry.y(), screenGeometry.width(), screenGeometry.height()); - QRect available = screen->availableGeometry(); - r.available_rect = gfx::Rect(available.x(), available.y(), available.width(), available.height()); - *results = r; -} - -} // namespace QtWebEngineCore - void *GetQtXDisplay() { return GLContextHelper::getXDisplay(); @@ -112,12 +90,13 @@ WebContentsView* CreateWebContentsView(WebContentsImpl *web_contents, return rv; } -// static -void WebContentsView::GetDefaultScreenInfo(content::ScreenInfo* results) +#if defined(Q_OS_MACOS) +std::string getQtPrefix() { - QWindow dummy; - QtWebEngineCore::GetScreenInfoFromNativeWindow(&dummy, results); + const QString prefix = QLibraryInfo::location(QLibraryInfo::PrefixPath); + return prefix.toStdString(); } +#endif } // namespace content diff --git a/src/core/client_cert_select_controller.cpp b/src/core/client_cert_select_controller.cpp index 7d08d57c1..0baaf2bc5 100644 --- a/src/core/client_cert_select_controller.cpp +++ b/src/core/client_cert_select_controller.cpp @@ -48,6 +48,8 @@ #include "type_conversion.h" +#include <QDebug> + QT_BEGIN_NAMESPACE using namespace QtWebEngineCore; @@ -76,17 +78,40 @@ ClientCertSelectController::~ClientCertSelectController() void ClientCertSelectController::selectNone() { if (m_selected) { - qWarning() << "ClientCertSelectController::selectNone() certicate already selected"; + LOG(WARNING) << "ClientCertSelectController::selectNone() certificate already selected"; return; } m_selected = true; m_delegate->ContinueWithCertificate(nullptr, nullptr); } +void ClientCertSelectController::select(int index) +{ + if (m_selected) { + LOG(WARNING) << "ClientCertSelectController::select() certificate already selected"; + return; + } + for (auto &certInfo : m_clientCerts) { + if (index == 0) { + m_selected = true; + scoped_refptr<net::X509Certificate> cert = certInfo->certificate(); + net::ClientCertIdentity::SelfOwningAcquirePrivateKey( + std::move(certInfo), + base::Bind(&content::ClientCertificateDelegate::ContinueWithCertificate, + base::Passed(std::move(m_delegate)), std::move(cert))); + return; + } + std::vector<std::string> pem_encoded; + if (certInfo->certificate()->GetPEMEncodedChain(&pem_encoded)) + --index; + } + LOG(WARNING) << "ClientCertSelectController::select() index out of range:" << index; +} + void ClientCertSelectController::select(const QSslCertificate &certificate) { if (m_selected) { - qWarning() << "ClientCertSelectController::select() certicate already selected"; + LOG(WARNING) << "ClientCertSelectController::select() certificate already selected"; return; } QByteArray derCertificate = certificate.toDer(); @@ -103,19 +128,20 @@ void ClientCertSelectController::select(const QSslCertificate &certificate) return; } } - qWarning() << "ClientCertSelectController::select() - selected client certificate not recognized." - << " Selected certificate needs to be one of the offered"; + LOG(WARNING) << "ClientCertSelectController::select() - selected client certificate not recognized." + << " Selected certificate needs to be one of the offered"; } QVector<QSslCertificate> ClientCertSelectController::certificates() const { - QVector<QSslCertificate> out; + if (!m_certificates.isEmpty()) + return m_certificates; for (auto &cert : m_clientCerts) { std::vector<std::string> pem_encoded; if (cert->certificate()->GetPEMEncodedChain(&pem_encoded)) - out.append(QSslCertificate(QByteArray::fromStdString(pem_encoded.front()))); + m_certificates.append(QSslCertificate(QByteArray::fromStdString(pem_encoded.front()))); } - return out; + return m_certificates; } #endif // !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) diff --git a/src/core/client_cert_select_controller.h b/src/core/client_cert_select_controller.h index 46324ee90..8f4f78d94 100644 --- a/src/core/client_cert_select_controller.h +++ b/src/core/client_cert_select_controller.h @@ -83,6 +83,7 @@ public: #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 @@ -91,6 +92,7 @@ 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; bool m_selected; }; diff --git a/src/core/color_chooser_controller.cpp b/src/core/color_chooser_controller.cpp index 26d675908..361ff93ba 100644 --- a/src/core/color_chooser_controller.cpp +++ b/src/core/color_chooser_controller.cpp @@ -43,6 +43,9 @@ #include "color_chooser_controller_p.h" #include "type_conversion.h" +#include <QColor> +#include <QVariant> + namespace QtWebEngineCore { ColorChooserControllerPrivate::ColorChooserControllerPrivate(content::WebContents *content, const QColor &color) diff --git a/src/core/color_chooser_controller.h b/src/core/color_chooser_controller.h index 4c1b81a9a..e5daa09a8 100644 --- a/src/core/color_chooser_controller.h +++ b/src/core/color_chooser_controller.h @@ -55,6 +55,9 @@ #include <QObject> +QT_FORWARD_DECLARE_CLASS(QColor) +QT_FORWARD_DECLARE_CLASS(QVariant) + namespace QtWebEngineCore { class ColorChooserControllerPrivate; diff --git a/src/core/command_line_pref_store_qt.cpp b/src/core/command_line_pref_store_qt.cpp new file mode 100644 index 000000000..5c5c82e1a --- /dev/null +++ b/src/core/command_line_pref_store_qt.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "command_line_pref_store_qt.h" + +#include "chrome/common/chrome_switches.h" +#include "components/proxy_config/proxy_config_dictionary.h" +#include "components/proxy_config/proxy_config_pref_names.h" +#include "content/public/common/content_switches.h" +#include <QDebug> + +CommandLinePrefStoreQt::CommandLinePrefStoreQt(const base::CommandLine *commandLine) + : CommandLinePrefStore(commandLine) +{ + + if (commandLine->HasSwitch(switches::kNoProxyServer)) { + SetValue(proxy_config::prefs::kProxy, + std::make_unique<base::Value>(ProxyConfigDictionary::CreateDirect()), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } else if (commandLine->HasSwitch(switches::kProxyPacUrl)) { + std::string pac_script_url = + commandLine->GetSwitchValueASCII(switches::kProxyPacUrl); + SetValue(proxy_config::prefs::kProxy, + std::make_unique<base::Value>(ProxyConfigDictionary::CreatePacScript( + pac_script_url, false)), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } else if (commandLine->HasSwitch(switches::kProxyAutoDetect)) { + SetValue(proxy_config::prefs::kProxy, + std::make_unique<base::Value>( + ProxyConfigDictionary::CreateAutoDetect()), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } else if (commandLine->HasSwitch(switches::kProxyServer)) { + std::string proxy_server = + commandLine->GetSwitchValueASCII(switches::kProxyServer); + std::string bypass_list = + commandLine->GetSwitchValueASCII(switches::kProxyBypassList); + SetValue( + proxy_config::prefs::kProxy, + std::make_unique<base::Value>(ProxyConfigDictionary::CreateFixedServers( + proxy_server, bypass_list)), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + } + + if (commandLine->HasSwitch(switches::kNoProxyServer) && (commandLine->HasSwitch(switches::kProxyAutoDetect) || commandLine->HasSwitch(switches::kProxyServer) || commandLine->HasSwitch(switches::kProxyPacUrl) || commandLine->HasSwitch(switches::kProxyBypassList))) { + qWarning("Additional command-line proxy switches specified when --%s was also specified", + qPrintable(switches::kNoProxyServer)); + } +} + +CommandLinePrefStoreQt::~CommandLinePrefStoreQt() = default; diff --git a/src/core/command_line_pref_store_qt.h b/src/core/command_line_pref_store_qt.h new file mode 100644 index 000000000..a509f8ca9 --- /dev/null +++ b/src/core/command_line_pref_store_qt.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef COMMAND_LINE_PREF_STORE_QT_H +#define COMMAND_LINE_PREF_STORE_QT_H + +#include "base/command_line.h" +#include "components/prefs/command_line_pref_store.h" + +class CommandLinePrefStoreQt : public CommandLinePrefStore +{ +public: + explicit CommandLinePrefStoreQt(const base::CommandLine *commandLine); + +protected: + ~CommandLinePrefStoreQt() override; + DISALLOW_COPY_AND_ASSIGN(CommandLinePrefStoreQt); +}; + +#endif // COMMAND_LINE_PREF_STORE_QT_H diff --git a/src/core/common/extensions/api/qtwebengine_extensions_features.gni b/src/core/common/extensions/api/qtwebengine_extensions_features.gni new file mode 100644 index 000000000..ed7e713c6 --- /dev/null +++ b/src/core/common/extensions/api/qtwebengine_extensions_features.gni @@ -0,0 +1,25 @@ +import("//tools/json_schema_compiler/json_features.gni") + +json_features("qt_api_features") { + feature_type = "APIFeature" + method_name = "AddQtAPIFeatures" + sources = [ + "//extensions/common/api/_webengine_api_features.json" + ] +} + +json_features("qt_permission_features") { + feature_type = "PermissionFeature" + method_name = "AddQtPermissionFeatures" + sources = [ + "//extensions/common/api/_permission_features.json" + ] +} + +group("qtwebengine_extensions_features") { + public_deps = [ + ":qt_api_features", + ":qt_permission_features", + "//extensions/common/api:extensions_features", + ] +} diff --git a/src/core/common/extensions/extensions_api_provider_qt.cpp b/src/core/common/extensions/extensions_api_provider_qt.cpp new file mode 100644 index 000000000..aa746133e --- /dev/null +++ b/src/core/common/extensions/extensions_api_provider_qt.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 "extensions_api_provider_qt.h" + +#include "chrome/grit/common_resources.h" + +#include "extensions/common/api/api_features.h" +#include "extensions/common/api/behavior_features.h" +#include "extensions/common/api/generated_schemas.h" +#include "extensions/common/api/manifest_features.h" +#include "extensions/common/api/permission_features.h" +#include "extensions/common/common_manifest_handlers.h" +#include "extensions/common/features/feature_provider.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/permissions/permissions_info.h" +#include "extensions/grit/extensions_resources.h" + +#include "qt_api_features.h" +//#include "qt_behavior_features.h" +#include "qt_permission_features.h" +//#include "qt_manifest_features.h" + + +namespace extensions { + +ExtensionsAPIProviderQt::ExtensionsAPIProviderQt() +{ + +} + +void ExtensionsAPIProviderQt::RegisterManifestHandlers() +{ + RegisterCommonManifestHandlers(); +} + +void ExtensionsAPIProviderQt::AddAPIFeatures(FeatureProvider *provider) +{ + AddCoreAPIFeatures(provider); + AddQtAPIFeatures(provider); +} + +void ExtensionsAPIProviderQt::AddAPIJSONSources(JSONFeatureProviderSource *json_source) +{ + json_source->LoadJSON(IDR_EXTENSION_API_FEATURES); + json_source->LoadJSON(IDR_CHROME_EXTENSION_API_FEATURES); +} + +void ExtensionsAPIProviderQt::AddPermissionFeatures(FeatureProvider *provider) +{ + AddQtPermissionFeatures(provider); +} + +bool ExtensionsAPIProviderQt::IsAPISchemaGenerated(const std::string &name) +{ + return api::GeneratedSchemas::IsGenerated(name); +} + +base::StringPiece ExtensionsAPIProviderQt::GetAPISchema(const std::string &name) +{ + return api::GeneratedSchemas::Get(name); +} + +void ExtensionsAPIProviderQt::RegisterPermissions(PermissionsInfo* permissions_info) +{ + +} + +} diff --git a/src/core/common/extensions/extensions_api_provider_qt.h b/src/core/common/extensions/extensions_api_provider_qt.h new file mode 100644 index 000000000..8b85e5de2 --- /dev/null +++ b/src/core/common/extensions/extensions_api_provider_qt.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#ifndef EXTENSIONS_API_PROVIDER_QT_H +#define EXTENSIONS_API_PROVIDER_QT_H + +#include "extensions/common/extensions_api_provider.h" + +#include "base/macros.h" + +namespace extensions { + +class ExtensionsAPIProviderQt : public ExtensionsAPIProvider +{ +public: + ExtensionsAPIProviderQt(); + + void RegisterManifestHandlers() override; + void AddAPIFeatures(FeatureProvider *provider) override; + void AddAPIJSONSources(JSONFeatureProviderSource* json_source) override; + void AddPermissionFeatures(FeatureProvider* provider) override; + + bool IsAPISchemaGenerated(const std::string& name) override; + base::StringPiece GetAPISchema(const std::string& name) override; + + + // Adds feature definitions to the given |provider| of the specified type. + void AddManifestFeatures(FeatureProvider* provider) override { } + void AddBehaviorFeatures(FeatureProvider* provider) override { } + + + // Registers permissions for any associated API features. + void RegisterPermissions(PermissionsInfo* permissions_info) override; + +DISALLOW_COPY_AND_ASSIGN(ExtensionsAPIProviderQt); +}; + +} + +#endif // EXTENSIONS_API_PROVIDER_QT_H diff --git a/src/core/common/extensions/extensions_client_qt.cpp b/src/core/common/extensions/extensions_client_qt.cpp new file mode 100644 index 000000000..6c6200eb0 --- /dev/null +++ b/src/core/common/extensions/extensions_client_qt.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_client_qt.h" + +#include "extensions/common/alias.h" +#include "extensions/common/core_extensions_api_provider.h" +#include "extensions/common/extension_urls.h" + +#include "extensions/common/features/simple_feature.h" +#include "extensions/common/permissions/permissions_info.h" + +#include "extensions_api_provider_qt.h" + + +namespace extensions { + +template<class FeatureClass> SimpleFeature *CreateFeature() +{ + return new FeatureClass; +} + +static base::LazyInstance<ExtensionsClientQt>::Leaky g_client = LAZY_INSTANCE_INITIALIZER; + +ExtensionsClientQt *ExtensionsClientQt::GetInstance() +{ + return g_client.Pointer(); +} + +ExtensionsClientQt::ExtensionsClientQt() : ExtensionsClient() +{ + AddAPIProvider(std::make_unique<CoreExtensionsAPIProvider>()); + AddAPIProvider(std::make_unique<ExtensionsAPIProviderQt>()); +} + +// Initializes global state. Not done in the constructor because unit tests +// can create additional ExtensionsClients because the utility thread runs +// in-process. +void ExtensionsClientQt::Initialize() +{ +} + +void ExtensionsClientQt::InitializeWebStoreUrls(base::CommandLine *command_line) +{ +} + +// Returns the global PermissionMessageProvider to use to provide permission +// warning strings. +const PermissionMessageProvider &ExtensionsClientQt::GetPermissionMessageProvider() const +{ + return permission_message_provider_; +} + +// Returns the application name. For example, "Chromium" or "app_shell". +const std::string ExtensionsClientQt::GetProductName() +{ + return "Qt WebEngine"; // return Qt WebEngine for now, consider returning the application name if possible. +} + +// Takes the list of all hosts and filters out those with special +// permission strings. Adds the regular hosts to |new_hosts|, +// and adds any additional permissions to |permissions|. +// TODO(sashab): Split this function in two: One to filter out ignored host +// permissions, and one to get permissions for the given hosts. +void ExtensionsClientQt::FilterHostPermissions(const URLPatternSet &hosts, + URLPatternSet *new_hosts, + PermissionIDSet *permissions) const +{ +} + +// Replaces the scripting whitelist with |whitelist|. Used in the renderer{} +// only used for testing in the browser process. +void ExtensionsClientQt::SetScriptingWhitelist(const ExtensionsClient::ScriptingWhitelist &whitelist) +{ + scripting_whitelist_ = whitelist; +} + +// Return the whitelist of extensions that can run content scripts on +// any origin. +const ExtensionsClient::ScriptingWhitelist &ExtensionsClientQt::GetScriptingWhitelist() const +{ + return scripting_whitelist_; +} + +// Get the set of chrome:// hosts that |extension| can run content scripts on. +URLPatternSet ExtensionsClientQt::GetPermittedChromeSchemeHosts(const Extension *extension, + const APIPermissionSet &api_permissions) const +{ + return URLPatternSet(); +} + +// Returns false if content scripts are forbidden from running on |url|. +bool ExtensionsClientQt::IsScriptableURL(const GURL &url, std::string *error) const +{ + return true; +} + +// Determines if certain fatal extensions errors should be surpressed +// (i.e., only logged) or allowed (i.e., logged before crashing). +bool ExtensionsClientQt::ShouldSuppressFatalErrors() const +{ + return true; +} + +// Records that a fatal error was caught and suppressed. It is expected that +// embedders will only do so if ShouldSuppressFatalErrors at some point +// returned true. +void ExtensionsClientQt::RecordDidSuppressFatalError() +{ +} + +// Returns the base webstore URL prefix. +const GURL &ExtensionsClientQt::GetWebstoreBaseURL() const +{ + if (base_url_.is_empty()) + base_url_ = GURL(extension_urls::kChromeWebstoreBaseURL); + return base_url_; +} + +// Returns the URL to use for update manifest queries. +const GURL &ExtensionsClientQt::GetWebstoreUpdateURL() const +{ + if (update_url_.is_empty()) + update_url_ = GURL(extension_urls::GetWebstoreUpdateUrl()); + return update_url_; +} + +// Returns a flag indicating whether or not a given URL is a valid +// extension blacklist URL. +bool ExtensionsClientQt::IsBlacklistUpdateURL(const GURL &url) const +{ + return true; +} + +// Returns the set of file paths corresponding to any images within an +// extension's contents that may be displayed directly within the browser UI +// or WebUI, such as icons or theme images. This set of paths is used by the +// extension unpacker to determine which assets should be transcoded safely +// within the utility sandbox. +// +// The default implementation returns the images used as icons for the +// extension itself, so implementors of ExtensionsClient overriding this may +// want to call the base class version and then add additional paths to that +// result. +std::set<base::FilePath> ExtensionsClientQt::GetBrowserImagePaths(const Extension *extension) +{ + return ExtensionsClient::GetBrowserImagePaths(extension); +} + +} // namespace extensions diff --git a/src/core/common/extensions/extensions_client_qt.h b/src/core/common/extensions/extensions_client_qt.h new file mode 100644 index 000000000..657487277 --- /dev/null +++ b/src/core/common/extensions/extensions_client_qt.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_CLIENT_QT_H +#define EXTENSIONS_CLIENT_QT_H + +#include "extensions/common/extensions_client.h" + +#include "base/compiler_specific.h" +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" +#include "extensions/common/features/feature_provider.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/permissions/extensions_api_permissions.h" +#include "url/gurl.h" + +namespace extensions { + +// Sets up global state for the extensions system. Should be Set() once in each +// process. This should be implemented by the client of the extensions system. +class ExtensionsClientQt : public ExtensionsClient +{ +public: + ExtensionsClientQt(); + virtual ~ExtensionsClientQt() {} + + // Initializes global state. Not done in the constructor because unit tests + // can create additional ExtensionsClients because the utility thread runs + // in-process. + void Initialize() override; + void InitializeWebStoreUrls(base::CommandLine *command_line) override; + + // Returns the global PermissionMessageProvider to use to provide permission + // warning strings. + const PermissionMessageProvider &GetPermissionMessageProvider() const override; + + // Returns the application name. For example, "Chromium" or "app_shell". + const std::string GetProductName() override; + + // Takes the list of all hosts and filters out those with special + // permission strings. Adds the regular hosts to |new_hosts|, + // and adds any additional permissions to |permissions|. + // TODO(sashab): Split this function in two: One to filter out ignored host + // permissions, and one to get permissions for the given hosts. + void FilterHostPermissions(const URLPatternSet &hosts, + URLPatternSet *new_hosts, + PermissionIDSet *permissions) const override; + + // Replaces the scripting whitelist with |whitelist|. Used in the renderer; + // only used for testing in the browser process. + void SetScriptingWhitelist(const ScriptingWhitelist &whitelist) override; + + // Return the whitelist of extensions that can run content scripts on + // any origin. + const ScriptingWhitelist &GetScriptingWhitelist() const override; + + // Get the set of chrome:// hosts that |extension| can run content scripts on. + URLPatternSet GetPermittedChromeSchemeHosts(const Extension *extension, + const APIPermissionSet &api_permissions) const override; + + // Returns false if content scripts are forbidden from running on |url|. + bool IsScriptableURL(const GURL &url, std::string *error) const override; + + // Determines if certain fatal extensions errors should be surpressed + // (i.e., only logged) or allowed (i.e., logged before crashing). + bool ShouldSuppressFatalErrors() const override; + + // Records that a fatal error was caught and suppressed. It is expected that + // embedders will only do so if ShouldSuppressFatalErrors at some point + // returned true. + void RecordDidSuppressFatalError() override; + + // Returns the base webstore URL prefix. + const GURL &GetWebstoreBaseURL() const override; + + // Returns the URL to use for update manifest queries. + const GURL &GetWebstoreUpdateURL() const override; + + // Returns a flag indicating whether or not a given URL is a valid + // extension blacklist URL. + bool IsBlacklistUpdateURL(const GURL &url) const override; + + // Returns the set of file paths corresponding to any images within an + // extension's contents that may be displayed directly within the browser UI + // or WebUI, such as icons or theme images. This set of paths is used by the + // extension unpacker to determine which assets should be transcoded safely + // within the utility sandbox. + // + // The default implementation returns the images used as icons for the + // extension itself, so implementors of ExtensionsClient overriding this may + // want to call the base class version and then add additional paths to that + // result. + std::set<base::FilePath> GetBrowserImagePaths(const Extension *extension) override; + // Get the LazyInstance for ChromeExtensionsClient. + static ExtensionsClientQt *GetInstance(); + +private: + ScriptingWhitelist scripting_whitelist_; + const ChromePermissionMessageProvider permission_message_provider_; + mutable GURL update_url_; + mutable GURL base_url_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsClientQt); +}; + +} // namespace extensions + +#endif // EXTENSIONS_CLIENT_QT_H diff --git a/src/core/chromium_gpu_helper.cpp b/src/core/compositor/chromium_gpu_helper.cpp index 92a8b13ed..71d0f3687 100644 --- a/src/core/chromium_gpu_helper.cpp +++ b/src/core/compositor/chromium_gpu_helper.cpp @@ -43,10 +43,14 @@ #include "chromium_gpu_helper.h" +// Some headers include the namespace ws, and can not coexist with +// Qt headers that include QTextStream, which includes most QSG headers +// via QMatrix4x4. +#include "content/browser/renderer_host/render_widget_host_impl.h" + // Including gpu/command_buffer headers before content/gpu headers makes sure that // guards are defined to prevent duplicate definition errors with forward declared // GL typedefs cascading through content header includes. -#include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/texture_base.h" @@ -62,12 +66,6 @@ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner() return content::GpuChildThread::instance()->main_thread_runner(); } -gpu::SyncPointManager *sync_point_manager() -{ - gpu::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->gpu_channel_manager(); - return gpuChannelManager->sync_point_manager(); -} - gpu::MailboxManager *mailbox_manager() { gpu::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->gpu_channel_manager(); @@ -85,6 +83,11 @@ unsigned int service_id(gpu::TextureBase *tex) return tex->service_id(); } +void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks ¤t_time) +{ + content::RenderWidgetHostImpl::From(host)->ProgressFlingIfNeeded(current_time); +} + #ifdef Q_OS_QNX EGLStreamData eglstream_connect_consumer(gpu::Texture *tex) { diff --git a/src/core/chromium_gpu_helper.h b/src/core/compositor/chromium_gpu_helper.h index 21b764997..4086d12ab 100644 --- a/src/core/chromium_gpu_helper.h +++ b/src/core/compositor/chromium_gpu_helper.h @@ -46,11 +46,15 @@ namespace base { class SingleThreadTaskRunner; +class TimeTicks; +} + +namespace content { +class RenderWidgetHost; } namespace gpu { struct Mailbox; -class SyncPointManager; class MailboxManager; class TextureBase; } @@ -61,12 +65,13 @@ class TextureBase; // functions should only be forward-declared and considered as opaque types. scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner(); -gpu::SyncPointManager *sync_point_manager(); gpu::MailboxManager *mailbox_manager(); gpu::TextureBase* ConsumeTexture(gpu::MailboxManager *mailboxManager, unsigned target, const gpu::Mailbox& mailbox); unsigned int service_id(gpu::TextureBase *tex); +void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks ¤t_time); + #ifdef Q_OS_QNX typedef void* EGLDisplay; typedef void* EGLStreamKHR; diff --git a/src/core/compositor.cpp b/src/core/compositor/compositor.cpp index f7a5e651c..0660c155b 100644 --- a/src/core/compositor.cpp +++ b/src/core/compositor/compositor.cpp @@ -39,26 +39,27 @@ #include "compositor.h" +#include "compositor_resource_tracker.h" #include "delegated_frame_node.h" -#include "render_widget_host_view_qt.h" +#include "base/task/post_task.h" #include "components/viz/common/resources/returned_resource.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h" namespace QtWebEngineCore { -Compositor::Compositor(RenderWidgetHostViewQt *hostView) - : m_chromiumCompositorData(new ChromiumCompositorData) - , m_view(hostView) +Compositor::Compositor(content::RenderWidgetHost *host) + : m_resourceTracker(new CompositorResourceTracker) + , m_host(host) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::SingleThreadTaskRunner *taskRunner = - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI).get(); + m_taskRunner = base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI}); m_beginFrameSource = std::make_unique<viz::DelayBasedBeginFrameSource>( - std::make_unique<viz::DelayBasedTimeSource>(taskRunner), + std::make_unique<viz::DelayBasedTimeSource>(m_taskRunner.get()), viz::BeginFrameSource::kNotRestartableId); } @@ -67,13 +68,6 @@ Compositor::~Compositor() DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -void Compositor::setViewDelegate(RenderWidgetHostViewQtDelegate *viewDelegate) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - m_viewDelegate = viewDelegate; -} - void Compositor::setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -85,7 +79,7 @@ void Compositor::setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frame // should not be returned. // // TODO(juvaldma): Can there be a pending frame from the old client? - m_resourcesToRelease.clear(); + m_resourceTracker->returnResources(); m_frameSinkClient = frameSinkClient; } @@ -104,21 +98,19 @@ void Compositor::setNeedsBeginFrames(bool needsBeginFrames) m_needsBeginFrames = needsBeginFrames; } -void Compositor::submitFrame(viz::CompositorFrame frame) +void Compositor::submitFrame(viz::CompositorFrame frame, base::OnceClosure callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!m_havePendingFrame); - - m_chromiumCompositorData->frameDevicePixelRatio = frame.metadata.device_scale_factor; - m_chromiumCompositorData->previousFrameData = std::move(m_chromiumCompositorData->frameData); - m_chromiumCompositorData->frameData = std::move(frame); - m_havePendingFrame = true; + DCHECK(!m_submitCallback); - // Tell viewDelegate to call updatePaintNode() soon. - m_viewDelegate->update(); + m_pendingFrame = std::move(frame); + m_submitCallback = std::move(callback); + m_resourceTracker->submitResources( + m_pendingFrame, + base::BindOnce(&Compositor::runSubmitCallback, base::Unretained(this))); } -QSGNode *Compositor::updatePaintNode(QSGNode *oldNode) +QSGNode *Compositor::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *viewDelegate) { // DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // @@ -129,30 +121,42 @@ QSGNode *Compositor::updatePaintNode(QSGNode *oldNode) if (!frameNode) frameNode = new DelegatedFrameNode; - frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_viewDelegate); - - if (m_havePendingFrame) { - m_havePendingFrame = false; - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(&Compositor::notifyFrameCommitted, m_weakPtrFactory.GetWeakPtr())); + if (!m_updatePaintNodeShouldCommit) { + frameNode->commit(m_committedFrame, viz::CompositorFrame(), m_resourceTracker.get(), viewDelegate); + return frameNode; } - if (m_chromiumCompositorData->frameData.metadata.request_presentation_feedback) - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(&Compositor::sendPresentationFeedback, m_weakPtrFactory.GetWeakPtr(), m_chromiumCompositorData->frameData.metadata.frame_token)); + m_updatePaintNodeShouldCommit = false; + + if (m_committedFrame.metadata.request_presentation_feedback) + m_taskRunner->PostTask(FROM_HERE, + base::BindOnce(&Compositor::sendPresentationFeedback, m_weakPtrFactory.GetWeakPtr(), + m_committedFrame.metadata.frame_token)); + m_resourceTracker->commitResources(); + frameNode->commit(m_pendingFrame, m_committedFrame, m_resourceTracker.get(), viewDelegate); + m_committedFrame = std::move(m_pendingFrame); + m_pendingFrame = viz::CompositorFrame(); + + m_taskRunner->PostTask(FROM_HERE, + base::BindOnce(&Compositor::notifyFrameCommitted, m_weakPtrFactory.GetWeakPtr())); return frameNode; } +void Compositor::runSubmitCallback() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + m_updatePaintNodeShouldCommit = true; + std::move(m_submitCallback).Run(); +} + void Compositor::notifyFrameCommitted() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); m_beginFrameSource->DidFinishFrame(this); if (m_frameSinkClient) - m_frameSinkClient->DidReceiveCompositorFrameAck(m_resourcesToRelease); - m_resourcesToRelease.clear(); + m_frameSinkClient->DidReceiveCompositorFrameAck(m_resourceTracker->returnResources()); } void Compositor::sendPresentationFeedback(uint frame_token) @@ -165,7 +169,7 @@ bool Compositor::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - m_view->OnBeginFrame(args.frame_time); + ProgressFlingIfNeeded(m_host, args.frame_time); m_beginFrameSource->OnUpdateVSyncParameters(args.frame_time, args.interval); if (m_frameSinkClient) m_frameSinkClient->OnBeginFrame(args); diff --git a/src/core/compositor.h b/src/core/compositor/compositor.h index 7d7db5d04..69f4a530c 100644 --- a/src/core/compositor.h +++ b/src/core/compositor/compositor.h @@ -42,6 +42,10 @@ #include <base/memory/weak_ptr.h> #include <components/viz/common/frame_sinks/begin_frame_source.h> +#include <components/viz/common/quads/compositor_frame.h> + +#include <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> #include <QtCore/qglobal.h> #include <QtCore/qshareddata.h> @@ -50,8 +54,10 @@ QT_BEGIN_NAMESPACE class QSGNode; QT_END_NAMESPACE +namespace content { +class RenderWidgetHost; +} namespace viz { -class CompositorFrame; struct ReturnedResource; namespace mojom { class CompositorFrameSinkClient; @@ -60,9 +66,8 @@ class CompositorFrameSinkClient; namespace QtWebEngineCore { -class RenderWidgetHostViewQt; +class CompositorResourceTracker; class RenderWidgetHostViewQtDelegate; -class ChromiumCompositorData; // Receives viz::CompositorFrames from child compositors and provides QSGNodes // to the Qt Quick renderer. @@ -72,10 +77,10 @@ class ChromiumCompositorData; // Step 1. A new CompositorFrame is received from child compositors and handed // off to submitFrame(). The new frame will start off in a pending state. // -// Step 2. Once the new frame is ready to be rendered, Compositor will call -// update() on the delegate. +// Step 2. Once the new frame is ready to be rendered, Compositor will notify +// the client by running the callback given to submitFrame(). // -// Step 3. Once the delegate is ready to render, updatePaintNode() should be +// Step 3. Once the client is ready to render, updatePaintNode() should be // called to receive the scene graph for the new frame. This call will commit // the pending frame. Until the next frame is ready, all subsequent calls to // updatePaintNode() will keep using this same committed frame. @@ -85,18 +90,17 @@ class ChromiumCompositorData; class Compositor final : private viz::BeginFrameObserverBase { public: - explicit Compositor(RenderWidgetHostViewQt *hostView); + explicit Compositor(content::RenderWidgetHost *host); ~Compositor() override; - void setViewDelegate(RenderWidgetHostViewQtDelegate *viewDelegate); void setFrameSinkClient(viz::mojom::CompositorFrameSinkClient *frameSinkClient); void setNeedsBeginFrames(bool needsBeginFrames); - void submitFrame(viz::CompositorFrame frame); - - QSGNode *updatePaintNode(QSGNode *oldNode); + void submitFrame(viz::CompositorFrame frame, base::OnceClosure callback); + QSGNode *updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDelegate *viewDelegate); private: + void runSubmitCallback(); void notifyFrameCommitted(); void sendPresentationFeedback(uint frame_token); @@ -104,15 +108,17 @@ private: bool OnBeginFrameDerivedImpl(const viz::BeginFrameArgs &args) override; void OnBeginFrameSourcePausedChanged(bool paused) override; - std::vector<viz::ReturnedResource> m_resourcesToRelease; - QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; - RenderWidgetHostViewQt *m_view; - RenderWidgetHostViewQtDelegate *m_viewDelegate = nullptr; + viz::CompositorFrame m_committedFrame; + viz::CompositorFrame m_pendingFrame; + base::OnceClosure m_submitCallback; + std::unique_ptr<CompositorResourceTracker> m_resourceTracker; + content::RenderWidgetHost *m_host; std::unique_ptr<viz::SyntheticBeginFrameSource> m_beginFrameSource; viz::mojom::CompositorFrameSinkClient *m_frameSinkClient = nullptr; - bool m_havePendingFrame = false; + bool m_updatePaintNodeShouldCommit = false; bool m_needsBeginFrames = false; + scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner; base::WeakPtrFactory<Compositor> m_weakPtrFactory{this}; DISALLOW_COPY_AND_ASSIGN(Compositor); diff --git a/src/core/compositor/compositor_resource.h b/src/core/compositor/compositor_resource.h new file mode 100644 index 000000000..f7df2ab59 --- /dev/null +++ b/src/core/compositor/compositor_resource.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_RESOURCE_H +#define COMPOSITOR_RESOURCE_H + +#include <base/memory/ref_counted.h> +#include <components/viz/common/resources/transferable_resource.h> + +#include <QtCore/qglobal.h> +#include <QtGui/qtgui-config.h> + +#if QT_CONFIG(opengl) +# include "compositor_resource_fence.h" +#endif + +namespace viz { +class SharedBitmap; +} // namespace viz + +namespace QtWebEngineCore { + +using CompositorResourceId = quint32; + +// A resource (OpenGL texture or software shared bitmap). +// +// - Created by the CompositorResourceTracker from a newly submitted +// CompositorFrame's resource_list. +// +// - Until the frame is committed, its resources are in a 'pending' state and +// are inaccessible from outside the CompositorResourceTracker. +// +// - Once the frame is committed, its resources can be found via +// CompositorResourceTracker::findResource. +// +// - A committed resource's fields may not be updated and are safe to use from +// other threads without synchronization (unless noted otherwise). +class CompositorResource : public viz::TransferableResource +{ +public: + CompositorResource(const viz::TransferableResource &tr) : viz::TransferableResource(tr) {} + + // Counts the number of times this resource has been encountered in + // CompositorFrames' resource lists. + // + // Corresponds to viz::ReturnedResource::count. + // + // Updated by CompositorResourceTracker on UI thread. + int import_count = 1; + + // Identifies the last frame that needed this resource. Used by + // CompositorResourceTracker to return unused resources back to child + // compositors. + // + // Updated by CompositorResourceTracker on UI thread. + quint32 last_used_for_frame = 0; + + // Bitmap (if is_software). + std::unique_ptr<viz::SharedBitmap> bitmap; + +#if QT_CONFIG(opengl) + // OpenGL texture id (if !is_software). + quint32 texture_id = 0; + + // Should be waited on before using the texture (non-null if !is_software). + scoped_refptr<CompositorResourceFence> texture_fence; +#endif // QT_CONFIG(opengl) +}; + +inline bool operator<(const CompositorResource &r1, const CompositorResource &r2) +{ + return r1.id < r2.id; +} + +inline bool operator<(const CompositorResource &r, CompositorResourceId id) +{ + return r.id < id; +} + +inline bool operator<(CompositorResourceId id, const CompositorResource &r) +{ + return id < r.id; +} + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_RESOURCE_H diff --git a/src/core/compositor/compositor_resource_fence.cpp b/src/core/compositor/compositor_resource_fence.cpp new file mode 100644 index 000000000..7fc5fbfb2 --- /dev/null +++ b/src/core/compositor/compositor_resource_fence.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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 "compositor_resource_fence.h" + +#include "ui/gl/gl_context.h" + +#include <QtGui/qopenglcontext.h> + +#ifndef GL_TIMEOUT_IGNORED +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + +namespace QtWebEngineCore { + +void CompositorResourceFence::wait() +{ + if (!m_sync) + return; + + QOpenGLContext *context = QOpenGLContext::currentContext(); + Q_ASSERT(context); + + // Chromium uses its own GL bindings and stores in in thread local storage. + // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium + // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. + switch (m_sync.type) { + case gl::TransferableFence::NoSync: + break; + case gl::TransferableFence::EglSync: +#ifdef EGL_KHR_reusable_sync + { + static bool resolved = false; + static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0; + + if (!resolved) { + if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) + eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR"); + resolved = true; + } + + if (eglClientWaitSyncKHR) + // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. + eglClientWaitSyncKHR(m_sync.egl.display, m_sync.egl.sync, 0, EGL_FOREVER_KHR); + } +#endif + break; + case gl::TransferableFence::ArbSync: + typedef void (QOPENGLF_APIENTRYP WaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout); + static WaitSyncPtr glWaitSync_ = 0; + if (!glWaitSync_) { + glWaitSync_ = (WaitSyncPtr)context->getProcAddress("glWaitSync"); + Q_ASSERT(glWaitSync_); + } + glWaitSync_(m_sync.arb.sync, 0, GL_TIMEOUT_IGNORED); + break; + } + + release(); +} + +void CompositorResourceFence::release() +{ + if (!m_sync) + return; + + QOpenGLContext *context = QOpenGLContext::currentContext(); + if (!context) + return; + + // Chromium uses its own GL bindings and stores in in thread local storage. + // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium + // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. + switch (m_sync.type) { + case gl::TransferableFence::NoSync: + break; + case gl::TransferableFence::EglSync: +#ifdef EGL_KHR_reusable_sync + { + static bool resolved = false; + static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; + + if (!resolved) { + if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) + eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); + resolved = true; + } + + if (eglDestroySyncKHR) { + // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. + eglDestroySyncKHR(m_sync.egl.display, m_sync.egl.sync); + m_sync.reset(); + } + } +#endif + break; + case gl::TransferableFence::ArbSync: + typedef void (QOPENGLF_APIENTRYP DeleteSyncPtr)(GLsync sync); + static DeleteSyncPtr glDeleteSync_ = 0; + if (!glDeleteSync_) { + glDeleteSync_ = (DeleteSyncPtr)context->getProcAddress("glDeleteSync"); + Q_ASSERT(glDeleteSync_); + } + glDeleteSync_(m_sync.arb.sync); + m_sync.reset(); + break; + } + // If Chromium was able to create a sync, we should have been able to handle its type here too. + Q_ASSERT(!m_sync); +} + +// static +scoped_refptr<CompositorResourceFence> CompositorResourceFence::create() +{ + if (gl::GLContext::GetCurrent() && gl::GLFence::IsSupported()) { + std::unique_ptr<gl::GLFence> glFence{gl::GLFence::Create()}; + return base::MakeRefCounted<CompositorResourceFence>(glFence->Transfer()); + } + return nullptr; +} + +} // namespace QtWebEngineCore diff --git a/src/core/net/url_request_qrc_job_qt.h b/src/core/compositor/compositor_resource_fence.h index 11c130693..1c2ea3695 100644 --- a/src/core/net/url_request_qrc_job_qt.h +++ b/src/core/compositor/compositor_resource_fence.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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,40 +37,35 @@ ** ****************************************************************************/ -#ifndef URL_REQUEST_QRC_JOB_QT_H_ -#define URL_REQUEST_QRC_JOB_QT_H_ +#ifndef COMPOSITOR_RESOURCE_FENCE_H +#define COMPOSITOR_RESOURCE_FENCE_H -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_job.h" - -#include <QFile> +#include <base/memory/ref_counted.h> +#include <ui/gl/gl_fence.h> namespace QtWebEngineCore { -// A request job that handles reading qrc file URLs -class URLRequestQrcJobQt : public net::URLRequestJob { - +// Sync object created on GPU thread and consumed on render thread. +class CompositorResourceFence final : public base::RefCountedThreadSafe<CompositorResourceFence> +{ public: - URLRequestQrcJobQt(net::URLRequest *request, net::NetworkDelegate *networkDelegate); - void Start() override; - void Kill() override; - int ReadRawData(net::IOBuffer* buf, int buf_size) override;; - bool GetMimeType(std::string *mimeType) const override; + REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); -protected: - virtual ~URLRequestQrcJobQt(); - // Get file mime type and try open file on a background thread. - void startGetHead(); + CompositorResourceFence() {} + CompositorResourceFence(const gl::TransferableFence &sync) : m_sync(sync) {}; + ~CompositorResourceFence() { release(); } -private: - qint64 m_remainingBytes; - QFile m_file; - std::string m_mimeType; - base::WeakPtrFactory<URLRequestQrcJobQt> m_weakFactory; + // May be used only by Qt Quick render thread. + void wait(); + void release(); - DISALLOW_COPY_AND_ASSIGN(URLRequestQrcJobQt); + // May be used only by GPU thread. + static scoped_refptr<CompositorResourceFence> create(); + +private: + gl::TransferableFence m_sync; }; } // namespace QtWebEngineCore -#endif // URL_REQUEST_QRC_JOB_QT_H_ +#endif // !COMPOSITOR_RESOURCE_FENCE_H diff --git a/src/core/compositor/compositor_resource_tracker.cpp b/src/core/compositor/compositor_resource_tracker.cpp new file mode 100644 index 000000000..6530f3249 --- /dev/null +++ b/src/core/compositor/compositor_resource_tracker.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** 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 "compositor_resource_tracker.h" + +#include "chromium_gpu_helper.h" +#include "render_widget_host_view_qt_delegate.h" +#include "web_engine_context.h" + +#include "base/message_loop/message_loop.h" +#include "base/task/post_task.h" +#include "components/viz/common/quads/compositor_frame.h" +#include "components/viz/common/resources/returned_resource.h" +#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" +#include "content/browser/browser_main_loop.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/gpu/content_gpu_client.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/sync_point_manager.h" + +namespace QtWebEngineCore { + +CompositorResourceTracker::CompositorResourceTracker() +{} + +CompositorResourceTracker::~CompositorResourceTracker() +{} + +void CompositorResourceTracker::submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!m_submitCallback); + DCHECK(m_pendingResources.empty()); + DCHECK(m_pendingImports.empty()); + DCHECK(m_pendingResourceUpdates == 0); + + m_submitCallback = std::move(callback); + + m_pendingResources.reserve(frame.resource_list.size()); + m_pendingImports.reserve(frame.resource_list.size()); + + for (const viz::TransferableResource &transferableResource : frame.resource_list) { + auto it = m_committedResources.find(transferableResource.id); + if (it != m_committedResources.end()) + m_pendingImports.push_back(&*it); + else + m_pendingResources.emplace_back(transferableResource); + } + + if (m_pendingResources.empty()) { + scheduleRunSubmitCallback(); + return; + } + + m_pendingResourceUpdates = m_pendingResources.size(); + + std::vector<CompositorResource *> batch; + batch.reserve(m_pendingResources.size()); + + for (CompositorResource &resource : m_pendingResources) { + if (resource.is_software) + updateBitmap(&resource); + else if (!scheduleUpdateMailbox(&resource)) + batch.push_back(&resource); + } + + if (!batch.empty()) + scheduleUpdateMailboxes(std::move(batch)); +} + +void CompositorResourceTracker::commitResources() +{ + // DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // + // This might be called from a Qt Quick render thread, but the UI thread + // will still be blocked for the duration of this call. + + DCHECK(m_pendingResourceUpdates == 0); + + for (CompositorResource *resource : m_pendingImports) + resource->import_count++; + m_pendingImports.clear(); + + m_committedResources.insert(std::make_move_iterator(m_pendingResources.begin()), + std::make_move_iterator(m_pendingResources.end())); + m_pendingResources.clear(); + + ++m_committedFrameId; +} + +std::vector<viz::ReturnedResource> CompositorResourceTracker::returnResources() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + std::vector<viz::ReturnedResource> returnedResources; + base::EraseIf(m_committedResources, [&](const CompositorResource &resource) { + if (resource.last_used_for_frame != m_committedFrameId) { + viz::ReturnedResource returnedResource; + returnedResource.id = resource.id; + returnedResource.count = resource.import_count; + returnedResources.push_back(std::move(returnedResource)); + return true; + } + return false; + }); + return returnedResources; +} + +const CompositorResource *CompositorResourceTracker::findResource(CompositorResourceId id) const +{ + auto it = m_committedResources.find(id); + DCHECK(it != m_committedResources.end()); + + const_cast<CompositorResource &>(*it).last_used_for_frame = m_committedFrameId; + + return &*it; +} + +void CompositorResourceTracker::updateBitmap(CompositorResource *resource) +{ + content::BrowserMainLoop *browserMainLoop = content::BrowserMainLoop::GetInstance(); + viz::ServerSharedBitmapManager *bitmapManager = browserMainLoop->GetServerSharedBitmapManager(); + + resource->bitmap = bitmapManager->GetSharedBitmapFromId( + resource->size, + viz::BGRA_8888, + resource->mailbox_holder.mailbox); + + if (--m_pendingResourceUpdates == 0) + scheduleRunSubmitCallback(); +} + +quint32 CompositorResourceTracker::consumeMailbox(const gpu::MailboxHolder &mailboxHolder) +{ +#if QT_CONFIG(opengl) + gpu::MailboxManager *mailboxManager = mailbox_manager(); + DCHECK(mailboxManager); + if (mailboxHolder.sync_token.HasData()) + mailboxManager->PullTextureUpdates(mailboxHolder.sync_token); + return service_id(mailboxManager->ConsumeTexture(mailboxHolder.mailbox)); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +bool CompositorResourceTracker::scheduleUpdateMailbox(CompositorResource *resource) +{ +#if QT_CONFIG(opengl) + gpu::SyncPointManager *syncPointManager = WebEngineContext::syncPointManager(); + DCHECK(syncPointManager); + return syncPointManager->WaitOutOfOrder( + resource->mailbox_holder.sync_token, + base::BindOnce(&CompositorResourceTracker::updateMailbox, + m_weakPtrFactory.GetWeakPtr(), + resource)); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::updateMailbox(CompositorResource *resource) +{ +#if QT_CONFIG(opengl) + resource->texture_id = consumeMailbox(resource->mailbox_holder); + resource->texture_fence = CompositorResourceFence::create(); + + if (--m_pendingResourceUpdates == 0) + scheduleRunSubmitCallback(); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::scheduleUpdateMailboxes(std::vector<CompositorResource *> resources) +{ +#if QT_CONFIG(opengl) + scoped_refptr<base::SingleThreadTaskRunner> gpuTaskRunner = gpu_task_runner(); + DCHECK(gpuTaskRunner); + gpuTaskRunner->PostTask( + FROM_HERE, + base::BindOnce(&CompositorResourceTracker::updateMailboxes, + m_weakPtrFactory.GetWeakPtr(), + std::move(resources))); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::updateMailboxes(std::vector<CompositorResource *> resources) +{ +#if QT_CONFIG(opengl) + for (CompositorResource *resource : resources) + resource->texture_id = consumeMailbox(resource->mailbox_holder); + + scoped_refptr<CompositorResourceFence> fence = CompositorResourceFence::create(); + + for (CompositorResource *resource : resources) + resource->texture_fence = fence; + + if ((m_pendingResourceUpdates -= resources.size()) == 0) + scheduleRunSubmitCallback(); +#else + NOTREACHED(); +#endif // QT_CONFIG(OPENGL) +} + +void CompositorResourceTracker::scheduleRunSubmitCallback() +{ + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&CompositorResourceTracker::runSubmitCallback, + m_weakPtrFactory.GetWeakPtr())); +} + +void CompositorResourceTracker::runSubmitCallback() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + std::move(m_submitCallback).Run(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/compositor/compositor_resource_tracker.h b/src/core/compositor/compositor_resource_tracker.h new file mode 100644 index 000000000..887309395 --- /dev/null +++ b/src/core/compositor/compositor_resource_tracker.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef COMPOSITOR_RESOURCE_TRACKER_H +#define COMPOSITOR_RESOURCE_TRACKER_H + +#include "compositor_resource.h" +#include "locked_ptr.h" + +#include <base/callback.h> +#include <base/containers/flat_set.h> + +#include <atomic> +#include <vector> + +namespace viz { +class CompositorFrame; +struct ReturnedResource; +} // namespace viz + +namespace gpu { +struct MailboxHolder; +} // namespace gpu + +namespace QtWebEngineCore { + +// Ensures resources are not used before they are ready. +// +// The life cycle of a frame's resources: +// +// Step 1. A new CompositorFrame is received and given to submitResources(). +// The frame's resources will extracted and initialized to a pending state. +// +// Step 2. Once the new resources are ready to be committed, +// CompositorResourceTracker will notify the client by running the callback +// given to submitResources(). +// +// Step 3. Once the client is ready to render, commitResources() should be +// called. This will commit all the pending resources, making them available +// via findResource(). +// +// Step 4. Once all the resources have been used (via findResource()), +// returnResources() may be called to return a list of all the resources which +// were *not* used since the last commitResources(). Go to step 1. +class CompositorResourceTracker final +{ +public: + CompositorResourceTracker(); + ~CompositorResourceTracker(); + + void submitResources(const viz::CompositorFrame &frame, base::OnceClosure callback); + void commitResources(); + std::vector<viz::ReturnedResource> returnResources(); + + // The returned pointer is invalidated by the next call to commitFrame() or + // returnResources(). It should therefore not be stored in data structures + // but used immediately. + // + // Do not ask for resources which do not exist. + const CompositorResource *findResource(CompositorResourceId id) const; + +private: + void updateBitmap(CompositorResource *resource); + + quint32 consumeMailbox(const gpu::MailboxHolder &mailboxHolder); + + bool scheduleUpdateMailbox(CompositorResource *resource); + void updateMailbox(CompositorResource *resource); + + void scheduleUpdateMailboxes(std::vector<CompositorResource *> resources); + void updateMailboxes(std::vector<CompositorResource *> resources); + + void scheduleRunSubmitCallback(); + void runSubmitCallback(); + + base::flat_set<CompositorResource> m_committedResources; + std::vector<CompositorResource> m_pendingResources; + std::vector<CompositorResource *> m_pendingImports; + base::OnceClosure m_submitCallback; + std::atomic<size_t> m_pendingResourceUpdates{0}; + quint32 m_committedFrameId = 0; + + base::LockedPtrFactory<CompositorResourceTracker> m_weakPtrFactory{this}; + + DISALLOW_COPY_AND_ASSIGN(CompositorResourceTracker); +}; + +} // namespace QtWebEngineCore + +#endif // !COMPOSITOR_RESOURCE_TRACKER_H diff --git a/src/core/compositor/content_gpu_client_qt.cpp b/src/core/compositor/content_gpu_client_qt.cpp new file mode 100644 index 000000000..f934979a0 --- /dev/null +++ b/src/core/compositor/content_gpu_client_qt.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 "content_gpu_client_qt.h" + +#include "web_engine_context.h" + +namespace QtWebEngineCore { + +ContentGpuClientQt::ContentGpuClientQt() +{ +} + +ContentGpuClientQt::~ContentGpuClientQt() +{ +} + +gpu::SyncPointManager *ContentGpuClientQt::GetSyncPointManager() +{ + return WebEngineContext::syncPointManager(); +} + +} // namespace diff --git a/src/core/compositor/content_gpu_client_qt.h b/src/core/compositor/content_gpu_client_qt.h new file mode 100644 index 000000000..d7ad43881 --- /dev/null +++ b/src/core/compositor/content_gpu_client_qt.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#ifndef CONTENT_GPU_CLIENT_QT_H +#define CONTENT_GPU_CLIENT_QT_H + +#include "content/public/gpu/content_gpu_client.h" + +namespace QtWebEngineCore { + +class ContentGpuClientQt : public content::ContentGpuClient { +public: + explicit ContentGpuClientQt(); + ~ContentGpuClientQt() override; + + // content::ContentGpuClient implementation. + gpu::SyncPointManager *GetSyncPointManager() override; +}; + +} + +#endif // CONTENT_GPU_CLIENT_QT_H diff --git a/src/core/delegated_frame_node.cpp b/src/core/compositor/delegated_frame_node.cpp index 8ac82dbf1..4fb05051b 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/compositor/delegated_frame_node.cpp @@ -49,17 +49,14 @@ #include "delegated_frame_node.h" #include "chromium_gpu_helper.h" -#include "ozone/gl_surface_qt.h" #include "stream_video_node.h" #include "type_conversion.h" #include "yuv_video_node.h" +#include "compositor_resource_tracker.h" #include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_task_runner_handle.h" #include "cc/base/math_util.h" #include "components/viz/common/quads/compositor_frame.h" -#include "components/viz/common/quads/compositor_frame_metadata.h" #include "components/viz/common/quads/debug_border_draw_quad.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/render_pass_draw_quad.h" @@ -68,14 +65,8 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/common/quads/yuv_video_draw_quad.h" -#include "components/viz/common/resources/returned_resource.h" -#include "components/viz/common/resources/transferable_resource.h" #include "components/viz/service/display/bsp_tree.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" -#include "content/browser/browser_main_loop.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_fence.h" #ifndef QT_NO_OPENGL # include <QOpenGLContext> @@ -93,10 +84,6 @@ #include <EGL/eglext.h> #endif -#ifndef GL_TIMEOUT_IGNORED -#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull -#endif - #ifndef GL_TEXTURE_RECTANGLE #define GL_TEXTURE_RECTANGLE 0x84F5 #endif @@ -131,7 +118,7 @@ namespace QtWebEngineCore { #ifndef QT_NO_OPENGL class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { public: - MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize); + MailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target = -1); ~MailboxTexture(); // QSGTexture: int textureId() const override { return m_textureId; } @@ -140,14 +127,9 @@ public: bool hasMipmaps() const override { return false; } void bind() override; - void setHasAlphaChannel(bool hasAlpha) { m_hasAlpha = hasAlpha; } - gpu::MailboxHolder &mailboxHolder() { return m_mailboxHolder; } - void fetchTexture(gpu::MailboxManager *mailboxManager); - void setTarget(GLenum target); - private: - gpu::MailboxHolder m_mailboxHolder; int m_textureId; + scoped_refptr<CompositorResourceFence> m_fence; QSize m_textureSize; bool m_hasAlpha; GLenum m_target; @@ -160,20 +142,6 @@ private: friend class DelegatedFrameNode; }; #endif // QT_NO_OPENGL -class ResourceHolder { -public: - ResourceHolder(const viz::TransferableResource &resource); - QSharedPointer<QSGTexture> initTexture(bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); - QSGTexture *texture() const { return m_texture.data(); } - viz::ReturnedResource returnResource(); - void incImportCount() { ++m_importCount; } - bool needsToFetch() const { return !m_resource.is_software && m_texture && !m_texture.data()->textureId(); } - -private: - QWeakPointer<QSGTexture> m_texture; - viz::TransferableResource m_resource; - int m_importCount; -}; class RectClipNode : public QSGClipNode { @@ -443,7 +411,9 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const viz::SharedQuadState } if (!layerState->quad_to_target_transform.IsIdentity()) { QSGTransformNode *transformNode = new QSGTransformNode; - transformNode->setMatrix(toQt(layerState->quad_to_target_transform.matrix())); + QMatrix4x4 qMatrix; + convertToQt(layerState->quad_to_target_transform.matrix(), qMatrix); + transformNode->setMatrix(qMatrix); layerChain->appendChildNode(transformNode); layerChain = transformNode; } @@ -457,99 +427,12 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const viz::SharedQuadState } #ifndef QT_NO_OPENGL -static void waitChromiumSync(gl::TransferableFence *sync) -{ - // Chromium uses its own GL bindings and stores in in thread local storage. - // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium - // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. - switch (sync->type) { - case gl::TransferableFence::NoSync: - break; - case gl::TransferableFence::EglSync: -#ifdef EGL_KHR_reusable_sync - { - static bool resolved = false; - static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0; - - if (!resolved) { - if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR"); - } - resolved = true; - } - - if (eglClientWaitSyncKHR) - // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. - eglClientWaitSyncKHR(sync->egl.display, sync->egl.sync, 0, EGL_FOREVER_KHR); - } -#endif - break; - case gl::TransferableFence::ArbSync: - typedef void (QOPENGLF_APIENTRYP WaitSyncPtr)(GLsync sync, GLbitfield flags, GLuint64 timeout); - static WaitSyncPtr glWaitSync_ = 0; - if (!glWaitSync_) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - glWaitSync_ = (WaitSyncPtr)context->getProcAddress("glWaitSync"); - Q_ASSERT(glWaitSync_); - } - glWaitSync_(sync->arb.sync, 0, GL_TIMEOUT_IGNORED); - break; - } -} - -static void deleteChromiumSync(gl::TransferableFence *sync) -{ - // Chromium uses its own GL bindings and stores in in thread local storage. - // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium - // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. - switch (sync->type) { - case gl::TransferableFence::NoSync: - break; - case gl::TransferableFence::EglSync: -#ifdef EGL_KHR_reusable_sync - { - static bool resolved = false; - static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; - - if (!resolved) { - if (gl::GLSurfaceQt::HasEGLExtension("EGL_KHR_fence_sync")) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); - } - resolved = true; - } - - if (eglDestroySyncKHR) { - // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. - eglDestroySyncKHR(sync->egl.display, sync->egl.sync); - sync->reset(); - } - } -#endif - break; - case gl::TransferableFence::ArbSync: - typedef void (QOPENGLF_APIENTRYP DeleteSyncPtr)(GLsync sync); - static DeleteSyncPtr glDeleteSync_ = 0; - if (!glDeleteSync_) { - QOpenGLContext *context = QOpenGLContext::currentContext(); - glDeleteSync_ = (DeleteSyncPtr)context->getProcAddress("glDeleteSync"); - Q_ASSERT(glDeleteSync_); - } - glDeleteSync_(sync->arb.sync); - sync->reset(); - break; - } - // If Chromium was able to create a sync, we should have been able to handle its type here too. - Q_ASSERT(!*sync); -} - -MailboxTexture::MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize) - : m_mailboxHolder(mailboxHolder) - , m_textureId(0) - , m_textureSize(textureSize) - , m_hasAlpha(false) - , m_target(GL_TEXTURE_2D) +MailboxTexture::MailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target) + : m_textureId(resource->texture_id) + , m_fence(resource->texture_fence) + , m_textureSize(toQt(resource->size)) + , m_hasAlpha(hasAlphaChannel) + , m_target(target >= 0 ? target : GL_TEXTURE_2D) #if defined(USE_OZONE) , m_ownsTexture(false) #endif @@ -580,6 +463,8 @@ MailboxTexture::~MailboxTexture() void MailboxTexture::bind() { + if (m_fence) + m_fence->wait(); glBindTexture(m_target, m_textureId); #ifdef Q_OS_QNX if (m_target == GL_TEXTURE_EXTERNAL_OES) { @@ -596,96 +481,7 @@ void MailboxTexture::bind() } #endif } - -void MailboxTexture::setTarget(GLenum target) -{ - m_target = target; -} - -void MailboxTexture::fetchTexture(gpu::MailboxManager *mailboxManager) -{ - gpu::TextureBase *tex = ConsumeTexture(mailboxManager, m_target, m_mailboxHolder.mailbox); - - // The texture might already have been deleted (e.g. when navigating away from a page). - if (tex) { - m_textureId = service_id(tex); -#ifdef Q_OS_QNX - if (m_target == GL_TEXTURE_EXTERNAL_OES) { - m_eglStreamData = eglstream_connect_consumer(tex); - } -#endif - } -} -#endif //QT_NO_OPENGL - -ResourceHolder::ResourceHolder(const viz::TransferableResource &resource) - : m_resource(resource) - , m_importCount(1) -{ -} - -QSharedPointer<QSGTexture> ResourceHolder::initTexture(bool quadNeedsBlending, RenderWidgetHostViewQtDelegate *apiDelegate) -{ - QSharedPointer<QSGTexture> texture = m_texture.toStrongRef(); - if (!texture) { - if (m_resource.is_software) { - Q_ASSERT(apiDelegate); - std::unique_ptr<viz::SharedBitmap> sharedBitmap = - content::BrowserMainLoop::GetInstance()->GetServerSharedBitmapManager()->GetSharedBitmapFromId( - m_resource.size, viz::BGRA_8888, m_resource.mailbox_holder.mailbox); - // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending - // to draw it but Chromium keeps this information in the quads. - // The input format is currently always Format_ARGB32_Premultiplied, so assume that all - // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion - // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to - // return false. - QImage::Format format = quadNeedsBlending ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - QImage image = sharedBitmap - ? QImage(sharedBitmap->pixels(), m_resource.size.width(), m_resource.size.height(), format) - : QImage(m_resource.size.width(), m_resource.size.height(), format); - texture.reset(apiDelegate->createTextureFromImage(image.copy())); - } else { -#ifndef QT_NO_OPENGL - texture.reset(new MailboxTexture(m_resource.mailbox_holder, toQt(m_resource.size))); - static_cast<MailboxTexture *>(texture.data())->setHasAlphaChannel(quadNeedsBlending); -#else - Q_UNREACHABLE(); -#endif - } - if (m_resource.filter == GL_NEAREST) - texture->setFiltering(QSGTexture::Nearest); - else if (m_resource.filter == GL_LINEAR) - texture->setFiltering(QSGTexture::Linear); - else { - // Depends on qtdeclarative fix, see QTBUG-71322 -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 1) - texture->setFiltering(QSGTexture::Linear); -#else - texture->setFiltering(QSGTexture::Nearest); -#endif - } - m_texture = texture; - } - // All quads using a resource should request the same blending state. - Q_ASSERT(texture->hasAlphaChannel() || !quadNeedsBlending); - return texture; -} - -viz::ReturnedResource ResourceHolder::returnResource() -{ - viz::ReturnedResource returned; - // The ResourceProvider ensures that the resource isn't used by the parent compositor's GL - // context in the GPU process by inserting a sync point to be waited for by the child - // compositor's GL context. We don't need this since we are triggering the delegated frame - // ack directly from our rendering thread. At this point (in updatePaintNode) we know that - // a frame that was compositing any of those resources has already been swapped and we thus - // don't need to use this mechanism. - returned.id = m_resource.id; - returned.count = m_importCount; - m_importCount = 0; - return returned; -} - +#endif // !QT_NO_OPENGL RectClipNode::RectClipNode(const QRectF &rect) : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) @@ -697,9 +493,8 @@ RectClipNode::RectClipNode(const QRectF &rect) } DelegatedFrameNode::DelegatedFrameNode() - : m_numPendingSyncPoints(0) #if defined(USE_OZONE) && !defined(QT_NO_OPENGL) - , m_contextShared(true) + : m_contextShared(true) #endif { setFlag(UsePreprocess); @@ -725,22 +520,6 @@ DelegatedFrameNode::~DelegatedFrameNode() void DelegatedFrameNode::preprocess() { -#ifndef QT_NO_OPENGL - // With the threaded render loop the GUI thread has been unlocked at this point. - // We can now wait for the Chromium GPU thread to produce textures that will be - // rendered on our quads and fetch the IDs from the mailboxes we were given. - QList<MailboxTexture *> mailboxesToFetch; - typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator ResourceHolderIterator; - ResourceHolderIterator end = m_chromiumCompositorData->resourceHolders.constEnd(); - for (ResourceHolderIterator it = m_chromiumCompositorData->resourceHolders.constBegin(); it != end ; ++it) { - if ((*it)->needsToFetch()) - mailboxesToFetch.append(static_cast<MailboxTexture *>((*it)->texture())); - } - - if (!mailboxesToFetch.isEmpty()) - fetchAndSyncMailboxes(mailboxesToFetch); -#endif - // Then render any intermediate RenderPass in order. typedef QPair<int, QSharedPointer<QSGLayer> > Pair; for (const Pair &pair : qAsConst(m_sgObjects.renderPassLayers)) { @@ -767,8 +546,8 @@ static bool areSharedQuadStatesEqual(const viz::SharedQuadState *layerState, // Compares if the frame data that we got from the Chromium Compositor is // *structurally* equivalent to the one of the previous frame. // If it is, we will just reuse and update the old nodes where necessary. -static bool areRenderPassStructuresEqual(viz::CompositorFrame *frameData, - viz::CompositorFrame *previousFrameData) +static bool areRenderPassStructuresEqual(const viz::CompositorFrame *frameData, + const viz::CompositorFrame *previousFrameData) { if (!previousFrameData) return false; @@ -820,12 +599,12 @@ static bool areRenderPassStructuresEqual(viz::CompositorFrame *frameData, return true; } -void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, - std::vector<viz::ReturnedResource> *resourcesToRelease, +void DelegatedFrameNode::commit(const viz::CompositorFrame &pendingFrame, + const viz::CompositorFrame &committedFrame, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { - m_chromiumCompositorData = chromiumCompositorData; - viz::CompositorFrame* frameData = &m_chromiumCompositorData->frameData; + const viz::CompositorFrame* frameData = &pendingFrame; if (frameData->render_pass_list.empty()) return; @@ -833,30 +612,14 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - const float devicePixelRatio = m_chromiumCompositorData->frameDevicePixelRatio; + const float devicePixelRatio = frameData->metadata.device_scale_factor; matrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio); if (QSGTransformNode::matrix() != matrix) setMatrix(matrix); - QHash<unsigned, QSharedPointer<ResourceHolder> > resourceCandidates; - qSwap(m_chromiumCompositorData->resourceHolders, resourceCandidates); - - // A frame's resource_list only contains the new resources to be added to the scene. Quads can - // still reference resources that were added in previous frames. Add them to the list of - // candidates to be picked up by quads, it's then our responsibility to return unused resources - // to the producing child compositor. - for (unsigned i = 0; i < frameData->resource_list.size(); ++i) { - const viz::TransferableResource &res = frameData->resource_list.at(i); - if (QSharedPointer<ResourceHolder> resource = resourceCandidates.value(res.id)) - resource->incImportCount(); - else - resourceCandidates[res.id] = QSharedPointer<ResourceHolder>(new ResourceHolder(res)); - } - - frameData->resource_list.clear(); QScopedPointer<DelegatedNodeTreeHandler> nodeHandler; - const QSizeF viewportSizeInPt = apiDelegate->screenRect().size(); + const QSizeF viewportSizeInPt = apiDelegate->viewGeometry().size(); const QSizeF viewportSizeF = viewportSizeInPt * devicePixelRatio; const QSize viewportSize(std::ceil(viewportSizeF.width()), std::ceil(viewportSizeF.height())); @@ -867,26 +630,22 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // Additionally, because we clip (i.e. don't build scene graph nodes for) quads outside // of the visible area, we also have to rebuild the tree whenever the window is resized. const bool buildNewTree = - !areRenderPassStructuresEqual(frameData, &m_chromiumCompositorData->previousFrameData) || + !areRenderPassStructuresEqual(frameData, &committedFrame) || m_sceneGraphNodes.empty() || viewportSize != m_previousViewportSize; - m_chromiumCompositorData->previousFrameData = viz::CompositorFrame(); - SGObjects previousSGObjects; - QVector<QSharedPointer<QSGTexture> > textureStrongRefs; if (buildNewTree) { // Keep the old objects in scope to hold a ref on layers, resources and textures // that we can re-use. Destroy the remaining objects before returning. - qSwap(m_sgObjects, previousSGObjects); + qSwap(m_sgObjects, m_previousSGObjects); // Discard the scene graph nodes from the previous frame. while (QSGNode *oldChain = firstChild()) delete oldChain; m_sceneGraphNodes.clear(); nodeHandler.reset(new DelegatedNodeTreeCreator(&m_sceneGraphNodes, apiDelegate)); } else { - // Save the texture strong refs so they only go out of scope when the method returns and - // the new vector of texture strong refs has been filled. - qSwap(m_sgObjects.textureStrongRefs, textureStrongRefs); + qSwap(m_sgObjects.bitmapTextures, m_previousSGObjects.bitmapTextures); + qSwap(m_sgObjects.mailboxTextures, m_previousSGObjects.mailboxTextures); nodeHandler.reset(new DelegatedNodeTreeUpdater(&m_sceneGraphNodes)); } // The RenderPasses list is actually a tree where a parent RenderPass is connected @@ -906,7 +665,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, if (pass != rootRenderPass) { QSharedPointer<QSGLayer> rpLayer; if (buildNewTree) { - rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers); + rpLayer = findRenderPassLayer(pass->id, m_previousSGObjects.renderPassLayers); if (!rpLayer) { rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); // Avoid any premature texture update since we need to wait @@ -935,7 +694,7 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, } if (scissorRect.IsEmpty()) { - holdResources(pass, resourceCandidates); + holdResources(pass, resourceTracker); continue; } @@ -961,13 +720,13 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, targetRect.Intersect(quadState->clip_rect); targetRect.Intersect(scissorRect); if (targetRect.IsEmpty()) { - holdResources(quad, resourceCandidates); + holdResources(quad, resourceTracker); continue; } if (quadState->sorting_context_id != currentSortingContextId) { flushPolygons(&polygonQueue, renderPassChain, - nodeHandler.data(), resourceCandidates, apiDelegate); + nodeHandler.data(), resourceTracker, apiDelegate); currentSortingContextId = quadState->sorting_context_id; } @@ -989,28 +748,23 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, } handleQuad(quad, currentLayerChain, - nodeHandler.data(), resourceCandidates, apiDelegate); + nodeHandler.data(), resourceTracker, apiDelegate); } flushPolygons(&polygonQueue, renderPassChain, - nodeHandler.data(), resourceCandidates, apiDelegate); + nodeHandler.data(), resourceTracker, apiDelegate); } - // Send resources of remaining candidates back to the child compositors so that - // they can be freed or reused. - typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator - ResourceHolderIterator; - ResourceHolderIterator end = resourceCandidates.constEnd(); - for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it) - resourcesToRelease->push_back((*it)->returnResource()); + copyMailboxTextures(); m_previousViewportSize = viewportSize; + m_previousSGObjects = SGObjects(); } void DelegatedFrameNode::flushPolygons( base::circular_deque<std::unique_ptr<viz::DrawPolygon>> *polygonQueue, QSGNode *renderPassChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { if (polygonQueue->empty()) @@ -1030,7 +784,7 @@ void DelegatedFrameNode::flushPolygons( polygon->TransformToLayerSpace(inverseTransform); handlePolygon(polygon, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); }; viz::BspTree(polygonQueue).TraverseWithActionHandler(&actionHandler); @@ -1040,20 +794,20 @@ void DelegatedFrameNode::handlePolygon( const viz::DrawPolygon *polygon, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { const viz::DrawQuad *quad = polygon->original_ref(); if (!polygon->is_split()) { handleQuad(quad, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); } else { std::vector<gfx::QuadF> clipRegionList; polygon->ToQuads2D(&clipRegionList); for (const auto & clipRegion : clipRegionList) handleClippedQuad(quad, clipRegion, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); } } @@ -1062,7 +816,7 @@ void DelegatedFrameNode::handleClippedQuad( const gfx::QuadF &clipRegion, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { if (currentLayerChain) { @@ -1080,21 +834,21 @@ void DelegatedFrameNode::handleClippedQuad( currentLayerChain = clipNode; } handleQuad(quad, currentLayerChain, - nodeHandler, resourceCandidates, apiDelegate); + nodeHandler, resourceTracker, apiDelegate); } void DelegatedFrameNode::handleQuad( const viz::DrawQuad *quad, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate) { switch (quad->material) { case viz::DrawQuad::RENDER_PASS: { const viz::RenderPassDrawQuad *renderPassQuad = viz::RenderPassDrawQuad::MaterialCast(quad); if (!renderPassQuad->mask_texture_size.IsEmpty()) { - ResourceHolder *resource = findAndHoldResource(renderPassQuad->mask_resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(renderPassQuad->mask_resource_id(), resourceTracker); Q_UNUSED(resource); // FIXME: QTBUG-67652 } QSGLayer *layer = @@ -1107,7 +861,7 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::TEXTURE_CONTENT: { const viz::TextureDrawQuad *tquad = viz::TextureDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(tquad->resource_id(), resourceTracker); QSGTexture *texture = initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate); QSizeF textureSize; @@ -1158,7 +912,7 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::TILED_CONTENT: { const viz::TileDrawQuad *tquad = viz::TileDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(tquad->resource_id(), resourceTracker); nodeHandler->setupTextureContentNode( initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate), toQt(quad->rect), toQt(tquad->tex_coord_rect), @@ -1168,17 +922,17 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::YUV_VIDEO_CONTENT: { const viz::YUVVideoDrawQuad *vquad = viz::YUVVideoDrawQuad::MaterialCast(quad); - ResourceHolder *yResource = - findAndHoldResource(vquad->y_plane_resource_id(), resourceCandidates); - ResourceHolder *uResource = - findAndHoldResource(vquad->u_plane_resource_id(), resourceCandidates); - ResourceHolder *vResource = - findAndHoldResource(vquad->v_plane_resource_id(), resourceCandidates); - ResourceHolder *aResource = 0; + const CompositorResource *yResource = + findAndHoldResource(vquad->y_plane_resource_id(), resourceTracker); + const CompositorResource *uResource = + findAndHoldResource(vquad->u_plane_resource_id(), resourceTracker); + const CompositorResource *vResource = + findAndHoldResource(vquad->v_plane_resource_id(), resourceTracker); + const CompositorResource *aResource = nullptr; // This currently requires --enable-vp8-alpha-playback and // needs a video with alpha data to be triggered. if (vquad->a_plane_resource_id()) - aResource = findAndHoldResource(vquad->a_plane_resource_id(), resourceCandidates); + aResource = findAndHoldResource(vquad->a_plane_resource_id(), resourceTracker); nodeHandler->setupYUVVideoNode( initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), @@ -1194,14 +948,13 @@ void DelegatedFrameNode::handleQuad( } case viz::DrawQuad::STREAM_VIDEO_CONTENT: { const viz::StreamVideoDrawQuad *squad = viz::StreamVideoDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(squad->resource_id(), resourceCandidates); + const CompositorResource *resource = findAndHoldResource(squad->resource_id(), resourceTracker); MailboxTexture *texture = static_cast<MailboxTexture *>( - initAndHoldTexture(resource, quad->ShouldDrawWithBlending())); - // since this is not default TEXTURE_2D type - texture->setTarget(GL_TEXTURE_EXTERNAL_OES); + initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate, GL_TEXTURE_EXTERNAL_OES)); - nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), toQt(squad->matrix.matrix()), - currentLayerChain); + QMatrix4x4 qMatrix; + convertToQt(squad->matrix.matrix(), qMatrix); + nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), qMatrix, currentLayerChain); break; #endif // GL_OES_EGL_image_external #endif // QT_NO_OPENGL @@ -1213,75 +966,100 @@ void DelegatedFrameNode::handleQuad( } } -ResourceHolder *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +const CompositorResource *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, const CompositorResourceTracker *resourceTracker) { - // ResourceHolders must survive when the scene graph destroys our node branch - QSharedPointer<ResourceHolder> &resource = m_chromiumCompositorData->resourceHolders[resourceId]; - if (!resource) - resource = candidates.take(resourceId); - Q_ASSERT(resource); - return resource.data(); + return resourceTracker->findResource(resourceId); } -void DelegatedFrameNode::holdResources(const viz::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +void DelegatedFrameNode::holdResources(const viz::DrawQuad *quad, const CompositorResourceTracker *resourceTracker) { for (auto resource : quad->resources) - findAndHoldResource(resource, candidates); + findAndHoldResource(resource, resourceTracker); } -void DelegatedFrameNode::holdResources(const viz::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +void DelegatedFrameNode::holdResources(const viz::RenderPass *pass, const CompositorResourceTracker *resourceTracker) { for (const auto &quad : pass->quad_list) - holdResources(quad, candidates); + holdResources(quad, resourceTracker); } -QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate) +template<class Container, class Key> +inline auto &findTexture(Container &map, Container &previousMap, const Key &key) { - // QSGTextures must be destroyed in the scene graph thread as part of the QSGNode tree, - // so we can't store them with the ResourceHolder in m_chromiumCompositorData. - // Hold them through a QSharedPointer solely on the root DelegatedFrameNode of the web view - // and access them through a QWeakPointer from the resource holder to find them later. - m_sgObjects.textureStrongRefs.append(resource->initTexture(quadIsAllOpaque, apiDelegate)); - return m_sgObjects.textureStrongRefs.last().data(); + auto &value = map[key]; + if (value) + return value; + value = previousMap[key]; + return value; } -void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxesToFetch) +QSGTexture *DelegatedFrameNode::initAndHoldTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate, int target) { -#ifndef QT_NO_OPENGL - QList<gl::TransferableFence> transferredFences; - { - QMutexLocker lock(&m_mutex); - QVector<MailboxTexture *> mailboxesToPull; - mailboxesToPull.reserve(mailboxesToFetch.size()); - - gpu::SyncPointManager *syncPointManager = sync_point_manager(); - scoped_refptr<base::SingleThreadTaskRunner> gpuTaskRunner = gpu_task_runner(); - Q_ASSERT(m_numPendingSyncPoints == 0); - m_numPendingSyncPoints = mailboxesToFetch.count(); - for (MailboxTexture *mailboxTexture : qAsConst(mailboxesToFetch)) { - gpu::SyncToken &syncToken = mailboxTexture->mailboxHolder().sync_token; - const auto task = base::Bind(&DelegatedFrameNode::pullTexture, this, mailboxTexture); - if (!syncPointManager->WaitOutOfOrder(syncToken, std::move(task))) - mailboxesToPull.append(mailboxTexture); - } - if (!mailboxesToPull.isEmpty()) { - auto task = base::BindOnce(&DelegatedFrameNode::pullTextures, this, std::move(mailboxesToPull)); - gpuTaskRunner->PostTask(FROM_HERE, std::move(task)); - } - - m_mailboxesFetchedWaitCond.wait(&m_mutex); - m_textureFences.swap(transferredFences); + QSGTexture::Filtering filtering; + + if (resource->filter == GL_NEAREST) + filtering = QSGTexture::Nearest; + else if (resource->filter == GL_LINEAR) + filtering = QSGTexture::Linear; + else { + // Depends on qtdeclarative fix, see QTBUG-71322 +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 1) + filtering = QSGTexture::Linear; +#else + filtering = QSGTexture::Nearest; +#endif } - for (gl::TransferableFence sync : qAsConst(transferredFences)) { - // We need to wait on the fences on the Qt current context, and - // can therefore not use GLFence routines that uses a different - // concept of current context. - waitChromiumSync(&sync); - deleteChromiumSync(&sync); + if (resource->is_software) { + QSharedPointer<QSGTexture> &texture = + findTexture(m_sgObjects.bitmapTextures, m_previousSGObjects.bitmapTextures, resource->id); + if (texture) + return texture.data(); + texture = createBitmapTexture(resource, hasAlphaChannel, apiDelegate); + texture->setFiltering(filtering); + return texture.data(); + } else { + QSharedPointer<MailboxTexture> &texture = + findTexture(m_sgObjects.mailboxTextures, m_previousSGObjects.mailboxTextures, resource->id); + if (texture) + return texture.data(); + texture = createMailboxTexture(resource, hasAlphaChannel, target); + texture->setFiltering(filtering); + return texture.data(); } +} -#if defined(USE_OZONE) && !defined(QT_NO_OPENGL) +QSharedPointer<QSGTexture> DelegatedFrameNode::createBitmapTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate) +{ + Q_ASSERT(apiDelegate); + viz::SharedBitmap *sharedBitmap = resource->bitmap.get(); + gfx::Size size = resource->size; + + // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending + // to draw it but Chromium keeps this information in the quads. + // The input format is currently always Format_ARGB32_Premultiplied, so assume that all + // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion + // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to + // return false. + QImage::Format format = hasAlphaChannel ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + QImage image = sharedBitmap + ? QImage(sharedBitmap->pixels(), size.width(), size.height(), format) + : QImage(size.width(), size.height(), format); + return QSharedPointer<QSGTexture>(apiDelegate->createTextureFromImage(image.copy())); +} + +QSharedPointer<MailboxTexture> DelegatedFrameNode::createMailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target) +{ +#ifndef QT_NO_OPENGL + return QSharedPointer<MailboxTexture>::create(resource, hasAlphaChannel, target); +#else + Q_UNREACHABLE(); +#endif +} + +void DelegatedFrameNode::copyMailboxTextures() +{ +#if !defined(QT_NO_OPENGL) && defined(USE_OZONE) // Workaround when context is not shared QTBUG-48969 // Make slow copy between two contexts. if (!m_contextShared) { @@ -1296,13 +1074,17 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe GLuint fbo = 0; funcs->glGenFramebuffers(1, &fbo); - for (MailboxTexture *mailboxTexture : qAsConst(mailboxesToFetch)) { + for (const QSharedPointer<MailboxTexture> &mailboxTexture : qAsConst(m_sgObjects.mailboxTextures)) { + if (mailboxTexture->m_ownsTexture) + continue; + // Read texture into QImage from shared context. // Switch to shared context. sharedContext->makeCurrent(m_offsurface.data()); funcs = sharedContext->functions(); QImage img(mailboxTexture->textureSize(), QImage::Format_RGBA8888_Premultiplied); funcs->glBindFramebuffer(GL_FRAMEBUFFER, fbo); + mailboxTexture->m_fence->wait(); funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mailboxTexture->m_textureId, 0); GLenum status = funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -1336,69 +1118,6 @@ void DelegatedFrameNode::fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxe currentContext->makeCurrent(surface); } #endif -#else - Q_UNUSED(mailboxesToFetch) -#endif //QT_NO_OPENGL -} - - -void DelegatedFrameNode::pullTextures(DelegatedFrameNode *frameNode, const QVector<MailboxTexture *> textures) -{ -#ifndef QT_NO_OPENGL - gpu::MailboxManager *mailboxManager = mailbox_manager(); - for (MailboxTexture *texture : textures) { - gpu::SyncToken &syncToken = texture->mailboxHolder().sync_token; - if (syncToken.HasData()) - mailboxManager->PullTextureUpdates(syncToken); - texture->fetchTexture(mailboxManager); - --frameNode->m_numPendingSyncPoints; - } - - fenceAndUnlockQt(frameNode); -#else - Q_UNUSED(frameNode) - Q_UNUSED(textures) -#endif -} - -void DelegatedFrameNode::pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *texture) -{ -#ifndef QT_NO_OPENGL - gpu::MailboxManager *mailboxManager = mailbox_manager(); - gpu::SyncToken &syncToken = texture->mailboxHolder().sync_token; - if (syncToken.HasData()) - mailboxManager->PullTextureUpdates(syncToken); - texture->fetchTexture(mailboxManager); - --frameNode->m_numPendingSyncPoints; - - fenceAndUnlockQt(frameNode); -#else - Q_UNUSED(frameNode) - Q_UNUSED(texture) -#endif -} - -void DelegatedFrameNode::fenceAndUnlockQt(DelegatedFrameNode *frameNode) -{ -#ifndef QT_NO_OPENGL - if (!!gl::GLContext::GetCurrent() && gl::GLFence::IsSupported()) { - // Create a fence on the Chromium GPU-thread and context - std::unique_ptr<gl::GLFence> fence = gl::GLFence::Create(); - // But transfer it to something generic since we need to read it using Qt's OpenGL. - frameNode->m_textureFences.append(fence->Transfer()); - } - if (frameNode->m_numPendingSyncPoints == 0) - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::unlockQt, frameNode)); -#else - Q_UNUSED(frameNode) -#endif -} - -void DelegatedFrameNode::unlockQt(DelegatedFrameNode *frameNode) -{ - QMutexLocker lock(&frameNode->m_mutex); - // Signal preprocess() the textures are ready - frameNode->m_mailboxesFetchedWaitCond.wakeOne(); } } // namespace QtWebEngineCore diff --git a/src/core/delegated_frame_node.h b/src/core/compositor/delegated_frame_node.h index e37ad08a3..34e4ba029 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/compositor/delegated_frame_node.h @@ -43,15 +43,10 @@ #include "base/containers/circular_deque.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/render_pass.h" -#include "components/viz/common/resources/transferable_resource.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "ui/gl/gl_fence.h" -#include <QMutex> -#include <QSGNode> -#include <QSharedData> -#include <QSharedPointer> -#include <QWaitCondition> + +#include <QtCore/QSharedPointer> #include <QtGui/QOffscreenSurface> +#include <QtQuick/QSGTransformNode> #include "chromium_gpu_helper.h" #include "render_widget_host_view_qt_delegate.h" @@ -72,77 +67,60 @@ class DrawPolygon; namespace QtWebEngineCore { +class CompositorResource; +class CompositorResourceTracker; class DelegatedNodeTreeHandler; class MailboxTexture; -class ResourceHolder; - -// Separating this data allows another DelegatedFrameNode to reconstruct the QSGNode tree from the mailbox textures -// and render pass information. -class ChromiumCompositorData : public QSharedData { -public: - ChromiumCompositorData() : frameDevicePixelRatio(1) { } - QHash<unsigned, QSharedPointer<ResourceHolder> > resourceHolders; - viz::CompositorFrame frameData; - viz::CompositorFrame previousFrameData; - qreal frameDevicePixelRatio; -}; class DelegatedFrameNode : public QSGTransformNode { public: DelegatedFrameNode(); ~DelegatedFrameNode(); - void preprocess(); - void commit(ChromiumCompositorData *chromiumCompositorData, std::vector<viz::ReturnedResource> *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate); + void preprocess() override; + void commit(const viz::CompositorFrame &pendingFrame, const viz::CompositorFrame &committedFrame, const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); private: void flushPolygons(base::circular_deque<std::unique_ptr<viz::DrawPolygon> > *polygonQueue, QSGNode *renderPassChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); void handlePolygon( const viz::DrawPolygon *polygon, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); void handleClippedQuad( const viz::DrawQuad *quad, const gfx::QuadF &clipRegion, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); void handleQuad( const viz::DrawQuad *quad, QSGNode *currentLayerChain, DelegatedNodeTreeHandler *nodeHandler, - QHash<unsigned, QSharedPointer<ResourceHolder> > &resourceCandidates, + const CompositorResourceTracker *resourceTracker, RenderWidgetHostViewQtDelegate *apiDelegate); - void fetchAndSyncMailboxes(QList<MailboxTexture *> &mailboxesToFetch); - // Making those callbacks static bypasses base::Bind's ref-counting requirement - // of the this pointer when the callback is a method. - static void pullTexture(DelegatedFrameNode *frameNode, MailboxTexture *mailbox); - static void pullTextures(DelegatedFrameNode *frameNode, const QVector<MailboxTexture *> mailboxes); - static void fenceAndUnlockQt(DelegatedFrameNode *frameNode); - static void unlockQt(DelegatedFrameNode *frameNode); - - ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); - void holdResources(const viz::DrawQuad *quad, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); - void holdResources(const viz::RenderPass *pass, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); - QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); - - QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; + + const CompositorResource *findAndHoldResource(unsigned resourceId, const CompositorResourceTracker *resourceTracker); + void holdResources(const viz::DrawQuad *quad, const CompositorResourceTracker *resourceTracker); + void holdResources(const viz::RenderPass *pass, const CompositorResourceTracker *resourceTracker); + QSGTexture *initAndHoldTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate = 0, int target = -1); + QSharedPointer<QSGTexture> createBitmapTexture(const CompositorResource *resource, bool hasAlphaChannel, RenderWidgetHostViewQtDelegate *apiDelegate); + QSharedPointer<MailboxTexture> createMailboxTexture(const CompositorResource *resource, bool hasAlphaChannel, int target); + + void copyMailboxTextures(); + struct SGObjects { QVector<QPair<int, QSharedPointer<QSGLayer> > > renderPassLayers; QVector<QSharedPointer<QSGRootNode> > renderPassRootNodes; - QVector<QSharedPointer<QSGTexture> > textureStrongRefs; - } m_sgObjects; + QHash<unsigned, QSharedPointer<QSGTexture> > bitmapTextures; + QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextures; + } m_sgObjects, m_previousSGObjects; QVector<QSGNode*> m_sceneGraphNodes; - int m_numPendingSyncPoints; - QWaitCondition m_mailboxesFetchedWaitCond; - QMutex m_mutex; - QList<gl::TransferableFence> m_textureFences; #if defined(USE_OZONE) bool m_contextShared; QScopedPointer<QOffscreenSurface> m_offsurface; diff --git a/src/core/stream_video_node.cpp b/src/core/compositor/stream_video_node.cpp index 29922f866..29922f866 100644 --- a/src/core/stream_video_node.cpp +++ b/src/core/compositor/stream_video_node.cpp diff --git a/src/core/stream_video_node.h b/src/core/compositor/stream_video_node.h index 9d937791f..9d937791f 100644 --- a/src/core/stream_video_node.h +++ b/src/core/compositor/stream_video_node.h diff --git a/src/core/yuv_video_node.cpp b/src/core/compositor/yuv_video_node.cpp index 4a436d952..4a436d952 100644 --- a/src/core/yuv_video_node.cpp +++ b/src/core/compositor/yuv_video_node.cpp diff --git a/src/core/yuv_video_node.h b/src/core/compositor/yuv_video_node.h index dca8fa5e2..dca8fa5e2 100644 --- a/src/core/yuv_video_node.h +++ b/src/core/compositor/yuv_video_node.h diff --git a/src/core/config/common.pri b/src/core/config/common.pri index ddb4ca4bf..85940977a 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -4,6 +4,7 @@ QT_FOR_CONFIG += webenginecore gn_args += \ use_qt=true \ + closure_compile=false \ is_component_build=false \ is_shared=true \ enable_message_center=false \ @@ -11,15 +12,20 @@ gn_args += \ enable_nacl=false \ enable_remoting=false \ enable_reporting=false \ + enable_swiftshader=false \ + enable_web_auth=false \ enable_web_speech=false \ enable_widevine=true \ has_native_accessibility=false \ use_allocator_shim=false \ use_allocator=\"none\" \ + use_custom_libcxx=false \ v8_use_external_startup_data=false \ + toolkit_views=false \ treat_warnings_as_errors=false \ - enable_swiftshader=false \ - use_custom_libcxx=false + safe_browsing_mode=0 \ + optimize_webui=false \ + closure_compile=false !win32: gn_args += \ use_jumbo_build=true \ @@ -54,6 +60,12 @@ qtConfig(webengine-webrtc) { qtConfig(webengine-proprietary-codecs): gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\" +qtConfig(webengine-extensions) { + gn_args += enable_extensions=true +} else { + gn_args += enable_extensions=false +} + precompile_header { gn_args += enable_precompiled_headers=true } else { @@ -84,7 +96,6 @@ optimize_size: gn_args += optimize_for_size=true # We don't want to apply sanitizer options to the build tools (GN, dict convert, etc). !host_build { - sanitizer: gn_args += sanitizer_keep_symbols=true sanitize_address: gn_args += is_asan=true sanitize_thread: gn_args += is_tsan=true sanitize_memory: gn_args += is_msan=true diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index 85b948db2..04c9eca89 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -19,11 +19,14 @@ gn_args += \ qtConfig(webengine-embedded-build) { gn_args += is_desktop_linux=false - gn_args += use_gold=false -} else { - !use_gold_linker: gn_args += use_gold=false } +use_gold_linker: gn_args += use_gold=true +else: gn_args += use_gold=false + +use_lld_linker: gn_args += use_lld=true +else: gn_args += use_lld=false + clang { clang_full_path = $$which($${QMAKE_CXX}) # Remove the "/bin/clang++" part. diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 4426901cf..e49df90e7 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -28,8 +28,6 @@ gn_args += \ clang_use_chrome_plugins=false \ mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" \ - mac_views_browser=false \ - toolkit_views=false \ use_external_popup_menu=false qtConfig(webengine-spellchecker) { diff --git a/src/core/configure.json b/src/core/configure.json index 044d85527..f111247e4 100644 --- a/src/core/configure.json +++ b/src/core/configure.json @@ -20,11 +20,14 @@ "webengine-pulseaudio": "boolean", "webengine-spellchecker": "boolean", "webengine-native-spellchecker": "boolean", + "webengine-extensions": "boolean", "webengine-webrtc": "boolean", "webengine-geolocation": "boolean", "webengine-v8-snapshot": "boolean", "webengine-webchannel": "boolean", "webengine-kerberos": "boolean", + "webengine-widgets": "boolean", + "webengine-qml": "boolean", "alsa": { "type": "boolean", "name": "webengine-alsa" }, "pulseaudio": { "type": "boolean", "name": "webengine-pulseaudio" }, "ffmpeg": { "type": "enum", "name": "webengine-system-ffmpeg", "values": { "system": "yes", "qt": "no" } }, @@ -34,6 +37,7 @@ "printing-and-pdf": { "type": "boolean", "name": "webengine-printing-and-pdf" }, "proprietary-codecs": { "type": "boolean", "name": "webengine-proprietary-codecs" }, "spellchecker": { "type": "boolean", "name": "webengine-spellchecker" }, + "extensions": { "type": "boolean", "name": "webengine-extensions" }, "webrtc": { "type": "boolean", "name": "webengine-webrtc" } } }, @@ -82,9 +86,9 @@ ] }, "webengine-harfbuzz": { - "label": "harfbuzz >= 1.4.2", + "label": "harfbuzz >= 2.0.0", "sources": [ - { "type": "pkgConfig", "args": "harfbuzz >= 1.4.2" } + { "type": "pkgConfig", "args": "harfbuzz >= 2.0.0" } ] }, "webengine-glib": { @@ -326,6 +330,10 @@ "webengine-arm-thumb" : { "label": "thumb instruction set", "type": "hasThumbFlag" + }, + "webengine-extensions-gcc-version" : { + "label": "GCC 6 or newer", + "type": "hasGcc6OrNewer" } }, @@ -546,14 +554,13 @@ "condition": "config.macos && features.webengine-spellchecker", "output": [ "publicFeature" ] }, - "webengine-ui-delegates": { - "label": "UI Delegates", - "output": [ "privateFeature" ] - }, - "webengine-testsupport": { - "label": "Test Support", - "autoDetect": "features.private_tests || call.isTestsInBuildParts", - "output": [ "privateFeature" ] + "webengine-extensions": { + "label": "Extensions", + "purpose": "Enables Chromium extensions within certain limits. Currently used for enabling the pdf viewer.", + "section": "WebEngine", + "condition": "features.webengine-printing-and-pdf && (tests.webengine-extensions-gcc-version || config.clang || !config.gcc)", + "autoDetect": "features.webengine-printing-and-pdf", + "output": [ "publicFeature" ] }, "webengine-webrtc": { "label": "WebRTC", @@ -657,6 +664,19 @@ "label": "Thumb instruction set", "condition": "config.linux && features.webengine-embedded-build && arch.arm && tests.webengine-arm-thumb", "output": [ "privateFeature" ] + }, + "webengine-widgets": { + "label": "Qt WebEngine Widgets", + "purpose": "Provides WebEngine Widgets support.", + "section": "WebEngine", + "condition": "module.widgets", + "output": [ "privateFeature" ] + }, + "webengine-qml": { + "label": "Qt WebEngine Qml", + "purpose": "Provides WebEngine Qml support.", + "section": "WebEngine", + "output": [ "privateFeature" ] } }, @@ -705,8 +725,10 @@ "summary": [ { - "section": "Qt WebEngine", + "section": "Qt WebEngineCore", "entries": [ + "webengine-widgets", + "webengine-qml", "webengine-embedded-build", "webengine-pepper-plugins", "webengine-printing-and-pdf", @@ -719,6 +741,7 @@ "webengine-webchannel", "webengine-v8-snapshot", "webengine-kerberos", + "webengine-extensions", { "type": "feature", "args": "webengine-v8-snapshot-support", diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 0a51cc261..7440771cb 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -42,12 +42,17 @@ #include "base/json/json_reader.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/message_loop/message_loop.h" +#include "base/task/post_task.h" +#include "base/threading/thread_restrictions.h" #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" #endif +#include "components/guest_view/browser/guest_view_base.h" #include "components/network_hints/browser/network_hints_message_filter.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/common/url_schemes.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/client_certificate_delegate.h" @@ -66,10 +71,12 @@ #include "content/public/common/service_names.mojom.h" #include "content/public/common/url_constants.h" #include "media/media_buildflags.h" +#include "extensions/buildflags/buildflags.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "printing/buildflags/buildflags.h" #include "net/ssl/client_cert_identity.h" +#include "net/ssl/client_cert_store.h" #include "services/proxy_resolver/proxy_resolver_service.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/service.h" @@ -95,12 +102,13 @@ #include "login_delegate_qt.h" #include "media_capture_devices_dispatcher.h" #include "net/network_delegate_qt.h" -#include "net/qrc_protocol_handler_qt.h" #include "net/url_request_context_getter_qt.h" +#include "platform_notification_service_qt.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "printing/printing_message_filter_qt.h" #endif #include "profile_qt.h" +#include "profile_io_data_qt.h" #include "quota_permission_context_qt.h" #include "renderer_host/user_resource_controller_host.h" #include "service/service_qt.h" @@ -114,18 +122,6 @@ #include "ui/base/resource/resource_bundle.h" #endif -#if defined(USE_NSS_CERTS) -#include "net/ssl/client_cert_store_nss.h" -#endif - -#if defined(OS_WIN) -#include "net/ssl/client_cert_store_win.h" -#endif - -#if defined(OS_MACOSX) -#include "net/ssl/client_cert_store_mac.h" -#endif - #if QT_CONFIG(webengine_pepper_plugins) #include "content/public/browser/browser_ppapi_host.h" #include "ppapi/host/ppapi_host.h" @@ -136,6 +132,16 @@ #include "location_provider_qt.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/extensions_browser_client_qt.h" +#include "extensions/browser/extension_message_filter.h" +#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h" +#include "extensions/browser/io_thread_extension_message_filter.h" +#include "extensions/common/constants.h" +#include "common/extensions/extensions_client_qt.h" +#include "renderer_host/resource_dispatcher_host_delegate_qt.h" +#endif + #include <QGuiApplication> #include <QLocale> #ifndef QT_NO_OPENGL @@ -157,7 +163,7 @@ public: { QString platform = qApp->platformName().toLower(); QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); - if (platform == QLatin1String("xcb")) { + if (platform == QLatin1String("xcb") || platform == QLatin1String("offscreen")) { if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); else @@ -248,10 +254,10 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* { const int id = host->GetID(); Profile *profile = Profile::FromBrowserContext(host->GetBrowserContext()); - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&net::URLRequestContextGetter::GetURLRequestContext, base::Unretained(profile->GetRequestContext())), - base::Bind(&ContentBrowserClientQt::AddNetworkHintsMessageFilter, base::Unretained(this), id)); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&net::URLRequestContextGetter::GetURLRequestContext, base::Unretained(profile->GetRequestContext())), + base::BindOnce(&ContentBrowserClientQt::AddNetworkHintsMessageFilter, base::Unretained(this), id)); // FIXME: Add a settings variable to enable/disable the file scheme. content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestScheme(id, url::kFileScheme); @@ -260,6 +266,11 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* #if QT_CONFIG(webengine_printing_and_pdf) host->AddFilter(new PrintingMessageFilterQt(host->GetID())); #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + host->AddFilter(new extensions::ExtensionMessageFilter(host->GetID(), host->GetBrowserContext())); + host->AddFilter(new extensions::IOThreadExtensionMessageFilter(host->GetID(), host->GetBrowserContext())); + host->AddFilter(new extensions::ExtensionsGuestViewMessageFilter(host->GetID(), host->GetBrowserContext())); +#endif //ENABLE_EXTENSIONS service_manager::mojom::ServicePtr service; *service_request = mojo::MakeRequest(&service); @@ -274,7 +285,11 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* void ContentBrowserClientQt::ResourceDispatcherHostCreated() { +#if BUILDFLAG(ENABLE_EXTENSIONS) + m_resourceDispatcherHostDelegate.reset(new ResourceDispatcherHostDelegateQt); +#else m_resourceDispatcherHostDelegate.reset(new content::ResourceDispatcherHostDelegate); +#endif content::ResourceDispatcherHost::Get()->SetDelegate(m_resourceDispatcherHostDelegate.get()); } @@ -293,6 +308,10 @@ content::MediaObserver *ContentBrowserClientQt::GetMediaObserver() void ContentBrowserClientQt::OverrideWebkitPrefs(content::RenderViewHost *rvh, content::WebPreferences *web_prefs) { if (content::WebContents *webContents = rvh->GetDelegate()->GetAsWebContents()) { +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (guest_view::GuestViewBase::IsGuest(webContents)) + return; +#endif // BUILDFLAG(ENABLE_EXTENSIONS) WebContentsDelegateQt* delegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); if (delegate) delegate->overrideWebPreferences(webContents, web_prefs); @@ -382,17 +401,8 @@ std::unique_ptr<net::ClientCertStore> ContentBrowserClientQt::CreateClientCertSt { if (!resource_context) return nullptr; -#if defined(USE_NSS_CERTS) - // FIXME: Give it a proper callback for a password delegate. - return std::unique_ptr<net::ClientCertStore>( - new net::ClientCertStoreNSS(net::ClientCertStoreNSS::PasswordDelegateFactory())); -#elif defined(OS_WIN) - return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin()); -#elif defined(OS_MACOSX) - return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac()); -#else - return nullptr; -#endif + + return ProfileIODataQt::FromResourceContext(resource_context)->CreateClientCertStore(); } std::string ContentBrowserClientQt::GetApplicationLocale() @@ -421,6 +431,11 @@ void ContentBrowserClientQt::GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes->push_back(content::kChromeDevToolsScheme); } +void ContentBrowserClientQt::GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes) +{ + additional_schemes->push_back(content::kChromeDevToolsScheme); +} + #if defined(Q_OS_LINUX) void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings) { @@ -441,7 +456,7 @@ void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base: void ContentBrowserClientQt::DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) { browser_host->GetPpapiHost()->AddHostFactoryFilter( - base::WrapUnique(new QtWebEngineCore::PepperHostFactoryQt(browser_host))); + std::make_unique<QtWebEngineCore::PepperHostFactoryQt>(browser_host)); } #endif @@ -450,6 +465,13 @@ content::DevToolsManagerDelegate* ContentBrowserClientQt::GetDevToolsManagerDele return new DevToolsManagerDelegateQt; } +content::PlatformNotificationService *ContentBrowserClientQt::GetPlatformNotificationService() +{ + if (!m_platformNotificationService) + m_platformNotificationService = std::make_unique<PlatformNotificationServiceQt>(); + return m_platformNotificationService.get(); +} + // This is a really complicated way of doing absolutely nothing, but Mojo demands it: class ServiceDriver : public blink::mojom::InsecureInputService @@ -618,11 +640,18 @@ void ContentBrowserClientQt::AddNetworkHintsMessageFilter(int render_process_id, if (!host) return; - content::BrowserMessageFilter *network_hints_message_filter( - new network_hints::NetworkHintsMessageFilter(context->host_resolver())); + content::BrowserMessageFilter *network_hints_message_filter = + new network_hints::NetworkHintsMessageFilter(render_process_id); host->AddFilter(network_hints_message_filter); } +bool ContentBrowserClientQt::ShouldEnableStrictSiteIsolation() +{ + // mirroring AwContentBrowserClient, CastContentBrowserClient and + // HeadlessContentBrowserClient + return false; +} + bool ContentBrowserClientQt::AllowGetCookie(const GURL &url, const GURL &first_party, const net::CookieList & /*cookie_list*/, @@ -671,7 +700,7 @@ bool ContentBrowserClientQt::AllowServiceWorker(const GURL &scope, // We control worker access to FS and indexed-db using cookie permissions, this is mirroring Chromium's logic. void ContentBrowserClientQt::AllowWorkerFileSystem(const GURL &url, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &/*render_frames*/, + const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/, base::Callback<void(bool)> callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -682,7 +711,7 @@ void ContentBrowserClientQt::AllowWorkerFileSystem(const GURL &url, bool ContentBrowserClientQt::AllowWorkerIndexedDB(const GURL &url, const base::string16 &/*name*/, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &/*render_frames*/) + const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate()); @@ -715,15 +744,13 @@ bool ContentBrowserClientQt::HandleExternalProtocol( Q_UNUSED(child_id); Q_UNUSED(navigation_data); - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&LaunchURL, - url, - web_contents_getter, - page_transition, - is_main_frame, - has_user_gesture)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&LaunchURL, + url, + web_contents_getter, + page_transition, + is_main_frame, + has_user_gesture)); return true; } @@ -737,9 +764,24 @@ scoped_refptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegat bool first_auth_attempt, LoginAuthRequiredCallback auth_required_callback) { - return base::MakeRefCounted<LoginDelegateQt>(authInfo, web_contents_getter, url, first_auth_attempt, std::move(auth_required_callback)); + auto loginDelegate = base::MakeRefCounted<LoginDelegateQt>(authInfo, web_contents_getter, url, first_auth_attempt, std::move(auth_required_callback)); + loginDelegate->triggerDialog(); + return loginDelegate; } -} // namespace QtWebEngineCore +bool ContentBrowserClientQt::ShouldIsolateErrorPage(bool in_main_frame) +{ + Q_UNUSED(in_main_frame); + return false; +} + +bool ContentBrowserClientQt::ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (effective_url.SchemeIs(extensions::kExtensionScheme)) + return true; +#endif + return ContentBrowserClient::ShouldUseProcessPerSite(browser_context, effective_url); +} -DEFINE_WEB_CONTENTS_USER_DATA_KEY(QtWebEngineCore::ServiceDriver); +} // namespace QtWebEngineCore diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index b2761b311..403ff3a9d 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -108,10 +108,13 @@ public: std::unique_ptr<content::ClientCertificateDelegate> delegate) override; std::unique_ptr<net::ClientCertStore> CreateClientCertStore(content::ResourceContext *resource_context) override; content::DevToolsManagerDelegate *GetDevToolsManagerDelegate() override; + content::PlatformNotificationService *GetPlatformNotificationService() override; std::string GetApplicationLocale() override; std::string GetAcceptLangs(content::BrowserContext* context) override; void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) override; + + void GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes) override; void GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes) override; void BindInterfaceRequestFromFrame(content::RenderFrameHost* render_frame_host, @@ -135,6 +138,7 @@ public: bool user_gesture, bool opener_suppressed, bool* no_javascript_access) override; + bool ShouldEnableStrictSiteIsolation() override; bool AllowGetCookie(const GURL& url, const GURL& first_party, @@ -161,17 +165,19 @@ public: void AllowWorkerFileSystem(const GURL &url, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &render_frames, + const std::vector<content::GlobalFrameRoutingId> &render_frames, base::Callback<void(bool)> callback) override; bool AllowWorkerIndexedDB(const GURL &url, const base::string16 &name, content::ResourceContext *context, - const std::vector<std::pair<int, int> > &render_frames) override; + const std::vector<content::GlobalFrameRoutingId> &render_frames) override; #if QT_CONFIG(webengine_geolocation) std::unique_ptr<device::LocationProvider> OverrideSystemLocationProvider() override; #endif + bool ShouldIsolateErrorPage(bool in_main_frame) override; + bool ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) override; #if defined(Q_OS_LINUX) void GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings) override; @@ -205,6 +211,7 @@ private: BrowserMainPartsQt* m_browserMainParts; std::unique_ptr<content::ResourceDispatcherHostDelegate> m_resourceDispatcherHostDelegate; + std::unique_ptr<content::PlatformNotificationService> m_platformNotificationService; scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick; std::unique_ptr<service_manager::BinderRegistry> m_frameInterfaces; std::unique_ptr<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>> m_frameInterfacesParameterized; diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp index df1bc303d..9bfc8eede 100644 --- a/src/core/content_client_qt.cpp +++ b/src/core/content_client_qt.cpp @@ -56,7 +56,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "net/qrc_protocol_handler_qt.h" #include "type_conversion.h" #include <QCoreApplication> @@ -85,6 +84,14 @@ const char kWidevineCdmFileName[] = #endif #endif +#if QT_CONFIG(webengine_printing_and_pdf) +#include "pdf/pdf.h" +#include "pdf/pdf_ppapi.h" +const char kPdfPluginMimeType[] = "application/x-google-chrome-pdf"; +const char kPdfPluginPath[] = "internal-pdf-viewer/"; +const char kPdfPluginSrc[] = "src"; +#endif // QT_CONFIG(webengine_printing_and_pdf) + static QString webenginePluginsPath() { // Look for plugins in /plugins/webengine or application dir. @@ -99,7 +106,6 @@ static QString webenginePluginsPath() } #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) - #if defined(Q_OS_WIN) #include <shlobj.h> static QString getLocalAppDataDir() @@ -235,10 +241,30 @@ void AddPepperFlashFromCommandLine(std::vector<content::PepperPluginInfo>* plugi plugins->push_back(CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); } +void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) +{ +#if QT_CONFIG(webengine_printing_and_pdf) + content::PepperPluginInfo pdf_info; + pdf_info.is_internal = true; + pdf_info.is_out_of_process = true; + pdf_info.name = "Chromium PDF Viewer"; + pdf_info.description = "Portable Document Format"; + pdf_info.path = base::FilePath::FromUTF8Unsafe(kPdfPluginPath); + content::WebPluginMimeType pdf_mime_type(kPdfPluginMimeType, "pdf", "Portable Document Format"); + pdf_info.mime_types.push_back(pdf_mime_type); + pdf_info.internal_entry_points.get_interface = chrome_pdf::PPP_GetInterface; + pdf_info.internal_entry_points.initialize_module = chrome_pdf::PPP_InitializeModule; + pdf_info.internal_entry_points.shutdown_module = chrome_pdf::PPP_ShutdownModule; + pdf_info.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV | ppapi::PERMISSION_PDF; + plugins->push_back(pdf_info); +#endif // QT_CONFIG(webengine_printing_and_pdf) +} + namespace QtWebEngineCore { void ContentClientQt::AddPepperPlugins(std::vector<content::PepperPluginInfo>* plugins) { + ComputeBuiltInPlugins(plugins); AddPepperFlashFromSystem(plugins); AddPepperFlashFromCommandLine(plugins); } @@ -330,7 +356,6 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path, } #endif // defined(WIDEVINE_CDM_AVAILABLE_NOT_COMPONENT) - void ContentClientQt::AddContentDecryptionModules(std::vector<content::CdmInfo> *cdms, std::vector<media::CdmHostFilePath> *cdm_host_file_paths) { @@ -386,6 +411,11 @@ void ContentClientQt::AddContentDecryptionModules(std::vector<content::CdmInfo> } } +void ContentClientQt::AddAdditionalSchemes(Schemes* schemes) +{ + schemes->standard_schemes.push_back("chrome-extension"); +} + std::string ContentClientQt::getUserAgent() { // Mention the Chromium version we're based on to get passed stupid UA-string-based feature detection (several WebRTC demos need this) @@ -401,6 +431,11 @@ base::RefCountedMemory *ContentClientQt::GetDataResourceBytes(int resource_id) c return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(resource_id); } +gfx::Image &ContentClientQt::GetNativeImageNamed(int resource_id) const +{ + return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); +} + base::string16 ContentClientQt::GetLocalizedString(int message_id) const { return l10n_util::GetStringUTF16(message_id); diff --git a/src/core/content_client_qt.h b/src/core/content_client_qt.h index fbafa6a4b..bee79986c 100644 --- a/src/core/content_client_qt.h +++ b/src/core/content_client_qt.h @@ -56,9 +56,11 @@ public: #endif void AddContentDecryptionModules(std::vector<content::CdmInfo> *cdms, std::vector<media::CdmHostFilePath> *cdm_host_file_paths) override; + void AddAdditionalSchemes(Schemes* schemes) override; base::StringPiece GetDataResource(int, ui::ScaleFactor) const override; - base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override; + base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override; + gfx::Image &GetNativeImageNamed(int resource_id) const override; std::string GetUserAgent() const override { return getUserAgent(); } base::string16 GetLocalizedString(int message_id) const override; std::string GetProduct() const override; diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 2811d5545..dc32bb8c1 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -40,17 +40,18 @@ #include "content_main_delegate_qt.h" #include "base/command_line.h" -#include <base/i18n/rtl.h> +#include "base/i18n/rtl.h" #include "base/logging.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" -#include <chrome/grit/generated_resources.h> +#include "chrome/grit/generated_resources.h" +#include "content/public/browser/browser_main_runner.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_paths.h" #include "ui/base/resource/resource_bundle.h" -#include <ui/base/webui/jstemplate_builder.h> +#include "ui/base/webui/jstemplate_builder.h" #include "net/grit/net_resources.h" #include "net/base/net_module.h" #include "services/service_manager/sandbox/switches.h" @@ -59,6 +60,7 @@ #include "content_client_qt.h" #include "renderer/content_renderer_client_qt.h" #include "type_conversion.h" +#include "web_engine_context.h" #include "web_engine_library_info.h" #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) @@ -71,6 +73,10 @@ #include <QtCore/qcoreapplication.h> +namespace content { +ContentClient *GetContentClient(); +} + namespace QtWebEngineCore { // The logic of this function is based on chrome/common/net/net_resource_provider.cc @@ -167,6 +173,12 @@ content::ContentBrowserClient *ContentMainDelegateQt::CreateContentBrowserClient return m_browserClient.get(); } +content::ContentGpuClient *ContentMainDelegateQt::CreateContentGpuClient() +{ + m_gpuClient.reset(new ContentGpuClientQt); + return m_gpuClient.get(); +} + content::ContentRendererClient *ContentMainDelegateQt::CreateContentRendererClient() { #if defined(OS_LINUX) @@ -221,7 +233,8 @@ bool ContentMainDelegateQt::BasicStartupComplete(int *exit_code) #if QT_CONFIG(webengine_spellchecker) SafeOverridePath(base::DIR_APP_DICTIONARIES, WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES)); #endif - SetContentClient(new ContentClientQt); + if (!content::GetContentClient()) + content::SetContentClient(new ContentClientQt); url::CustomScheme::LoadSchemes(base::CommandLine::ForCurrentProcess()); diff --git a/src/core/content_main_delegate_qt.h b/src/core/content_main_delegate_qt.h index c06afb0fb..4d2f33792 100644 --- a/src/core/content_main_delegate_qt.h +++ b/src/core/content_main_delegate_qt.h @@ -42,6 +42,7 @@ #include "content/public/app/content_main_delegate.h" +#include "compositor/content_gpu_client_qt.h" #include "content_browser_client_qt.h" #include "content_utility_client_qt.h" @@ -56,12 +57,14 @@ public: void PreSandboxStartup() override; content::ContentBrowserClient* CreateContentBrowserClient() override; + content::ContentGpuClient* CreateContentGpuClient() override; content::ContentRendererClient* CreateContentRendererClient() override; content::ContentUtilityClient* CreateContentUtilityClient() override; bool BasicStartupComplete(int* /*exit_code*/) override; private: std::unique_ptr<ContentBrowserClientQt> m_browserClient; + std::unique_ptr<ContentGpuClientQt> m_gpuClient; std::unique_ptr<ContentUtilityClientQt> m_utilityClient; }; diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri index e92dd60ff..f4cb8c9da 100644 --- a/src/core/core_chromium.pri +++ b/src/core/core_chromium.pri @@ -38,6 +38,7 @@ qtConfig(egl): CONFIG += egl INCLUDEPATH += $$PWD $$PWD/api SOURCES = \ + accessibility_activation_observer.cpp \ accessibility_tree_formatter_qt.cpp \ authentication_dialog_controller.cpp \ browser_accessibility_manager_qt.cpp \ @@ -46,21 +47,24 @@ SOURCES = \ browser_main_parts_qt.cpp \ browser_message_filter_qt.cpp \ certificate_error_controller.cpp \ - chromium_gpu_helper.cpp \ chromium_overrides.cpp \ client_cert_select_controller.cpp \ clipboard_qt.cpp \ color_chooser_qt.cpp \ color_chooser_controller.cpp \ + command_line_pref_store_qt.cpp \ common/qt_ipc_logging.cpp \ common/qt_messages.cpp \ common/user_script_data.cpp \ - compositor.cpp \ + compositor/chromium_gpu_helper.cpp \ + compositor/compositor.cpp \ + compositor/compositor_resource_tracker.cpp \ + compositor/content_gpu_client_qt.cpp \ + compositor/delegated_frame_node.cpp \ content_client_qt.cpp \ content_browser_client_qt.cpp \ content_main_delegate_qt.cpp \ content_utility_client_qt.cpp \ - delegated_frame_node.cpp \ desktop_screen_qt.cpp \ devtools_frontend_qt.cpp \ devtools_manager_delegate_qt.cpp \ @@ -72,17 +76,19 @@ SOURCES = \ login_delegate_qt.cpp \ media_capture_devices_dispatcher.cpp \ native_web_keyboard_event_qt.cpp \ + net/client_cert_override.cpp \ + net/client_cert_store_data.cpp \ net/cookie_monster_delegate_qt.cpp \ net/custom_protocol_handler.cpp \ net/network_delegate_qt.cpp \ net/proxy_config_service_qt.cpp \ - net/qrc_protocol_handler_qt.cpp \ + net/qrc_url_scheme_handler.cpp \ net/ssl_host_state_delegate_qt.cpp \ net/url_request_context_getter_qt.cpp \ net/url_request_custom_job.cpp \ net/url_request_custom_job_delegate.cpp \ net/url_request_custom_job_proxy.cpp \ - net/url_request_qrc_job_qt.cpp \ + net/url_request_notification.cpp \ net/webui_controller_factory_qt.cpp \ ozone/gl_context_qt.cpp \ ozone/gl_ozone_egl_qt.cpp \ @@ -93,6 +99,7 @@ SOURCES = \ ozone/platform_window_qt.cpp \ ozone/surface_factory_qt.cpp \ permission_manager_qt.cpp \ + platform_notification_service_qt.cpp \ process_main.cpp \ profile_adapter.cpp \ profile_adapter_client.cpp \ @@ -113,19 +120,25 @@ SOURCES = \ resource_bundle_qt.cpp \ resource_context_qt.cpp \ service/service_qt.cpp \ + touch_handle_drawable_qt.cpp \ + touch_selection_controller_client_qt.cpp \ + touch_selection_menu_controller.cpp \ type_conversion.cpp \ + user_notification_controller.cpp \ user_script.cpp \ visited_links_manager_qt.cpp \ web_contents_adapter.cpp \ web_contents_delegate_qt.cpp \ web_contents_view_qt.cpp \ web_engine_context.cpp \ + web_engine_context_threads.cpp \ web_engine_error.cpp \ web_engine_library_info.cpp \ web_engine_settings.cpp \ web_event_factory.cpp HEADERS = \ + accessibility_activation_observer.h \ authentication_dialog_controller_p.h \ authentication_dialog_controller.h \ build_config_qt.h \ @@ -136,43 +149,49 @@ HEADERS = \ browser_message_filter_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ - chromium_overrides.h \ client_cert_select_controller.h \ clipboard_qt.h \ + command_line_pref_store_qt.h \ color_chooser_qt.h \ color_chooser_controller_p.h \ color_chooser_controller.h \ common/qt_messages.h \ common/user_script_data.h \ - compositor.h \ + compositor/chromium_gpu_helper.h \ + compositor/compositor.h \ + compositor/compositor_resource.h \ + compositor/compositor_resource_tracker.h \ + compositor/content_gpu_client_qt.h \ + compositor/delegated_frame_node.h \ content_client_qt.h \ content_browser_client_qt.h \ content_main_delegate_qt.h \ content_utility_client_qt.h \ - delegated_frame_node.h \ desktop_screen_qt.h \ devtools_frontend_qt.h \ devtools_manager_delegate_qt.h \ download_manager_delegate_qt.h \ - chromium_gpu_helper.h \ favicon_manager.h \ file_picker_controller.h \ global_descriptors_qt.h \ javascript_dialog_controller_p.h \ javascript_dialog_controller.h \ javascript_dialog_manager_qt.h \ + locked_ptr.h \ login_delegate_qt.h \ media_capture_devices_dispatcher.h \ + net/client_cert_override.h \ + net/client_cert_store_data.h \ net/cookie_monster_delegate_qt.h \ net/custom_protocol_handler.h \ net/network_delegate_qt.h \ - net/qrc_protocol_handler_qt.h \ + net/qrc_url_scheme_handler.h \ net/ssl_host_state_delegate_qt.h \ net/url_request_context_getter_qt.h \ net/url_request_custom_job.h \ net/url_request_custom_job_delegate.h \ net/url_request_custom_job_proxy.h \ - net/url_request_qrc_job_qt.h \ + net/url_request_notification.h \ net/webui_controller_factory_qt.h \ ozone/gl_context_qt.h \ ozone/gl_ozone_egl_qt.h \ @@ -183,6 +202,7 @@ HEADERS = \ ozone/platform_window_qt.h \ ozone/surface_factory_qt.h \ permission_manager_qt.h \ + platform_notification_service_qt.h \ process_main.h \ profile_adapter.h \ profile_adapter_client.h \ @@ -207,7 +227,12 @@ HEADERS = \ request_controller.h \ resource_context_qt.h \ service/service_qt.h \ + touch_handle_drawable_client.h \ + touch_handle_drawable_qt.h \ + touch_selection_controller_client_qt.h \ + touch_selection_menu_controller.h \ type_conversion.h \ + user_notification_controller.h \ user_script.h \ visited_links_manager_qt.h \ web_contents_adapter.h \ @@ -266,12 +291,14 @@ qtConfig(webengine-printing-and-pdf) { contains(QT_CONFIG, opengl) { SOURCES += \ - yuv_video_node.cpp \ - stream_video_node.cpp + compositor/compositor_resource_fence.cpp \ + compositor/stream_video_node.cpp \ + compositor/yuv_video_node.cpp HEADERS += \ - yuv_video_node.h \ - stream_video_node.h + compositor/compositor_resource_fence.h \ + compositor/stream_video_node.h \ + compositor/yuv_video_node.h } qtConfig(webengine-geolocation) { @@ -286,3 +313,39 @@ qtConfig(webengine-webchannel) { SOURCES += renderer/web_channel_ipc_transport.cpp \ renderer_host/web_channel_ipc_transport_host.cpp } + +qtConfig(webengine-extensions) { + SOURCES += \ + common/extensions/extensions_api_provider_qt.cpp \ + common/extensions/extensions_client_qt.cpp \ + extensions/component_extension_resource_manager_qt.cpp \ + extensions/extension_system_qt.cpp \ + extensions/extension_system_factory_qt.cpp \ + extensions/extension_web_contents_observer_qt.cpp \ + extensions/extensions_api_client_qt.cpp \ + extensions/extensions_browser_api_provider_qt.cpp \ + extensions/extensions_browser_client_qt.cpp \ + extensions/mime_handler_view_guest_delegate_qt.cpp \ + renderer/extensions/extensions_dispatcher_delegate_qt.cpp \ + renderer/extensions/extensions_renderer_client_qt.cpp \ + renderer/extensions/renderer_permissions_policy_delegate_qt.cpp \ + renderer/extensions/resource_request_policy_qt.cpp \ + renderer_host/resource_dispatcher_host_delegate_qt.cpp + + HEADERS += \ + common/extensions/extensions_api_provider_qt.h \ + common/extensions/extensions_client_qt.h \ + extensions/component_extension_resource_manager_qt.h \ + extensions/extension_system_qt.h \ + extensions/extension_system_factory_qt.h \ + extensions/extension_web_contents_observer_qt.h \ + extensions/extensions_api_client_qt.h \ + extensions/extensions_browser_api_provider_qt.h \ + extensions/extensions_browser_client_qt.h \ + extensions/mime_handler_view_guest_delegate_qt.h \ + renderer/extensions/extensions_dispatcher_delegate_qt.h \ + renderer/extensions/extensions_renderer_client_qt.h \ + renderer/extensions/renderer_permissions_policy_delegate_qt.h \ + renderer/extensions/resource_request_policy_qt.h \ + renderer_host/resource_dispatcher_host_delegate_qt.h +} diff --git a/src/core/core_common.pri b/src/core/core_common.pri index 5f9f3c4f6..8375d89e5 100644 --- a/src/core/core_common.pri +++ b/src/core/core_common.pri @@ -13,3 +13,7 @@ CONFIG -= ltcg # Chromium requires C++14 CONFIG += c++14 + +#QTBUG-73216 ci has to be updated with latest yocto +boot2qt: CONFIG -= use_gold_linker + diff --git a/src/core/core_gn_config.pri b/src/core/core_gn_config.pri index 9b0145dfc..b76cdc81a 100644 --- a/src/core/core_gn_config.pri +++ b/src/core/core_gn_config.pri @@ -1,11 +1,19 @@ +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) +QT_FOR_CONFIG += webenginecore webenginecore-private + CONFIG = gn_generator $$CONFIG GN_SRC_DIR = $$PWD GN_FILE = $$OUT_PWD/$$getConfigDir()/BUILD.gn GN_FIND_MOCABLES_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_find_mocables.py) GN_RUN_BINARY_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_run_binary.py) GN_IMPORTS = $$PWD/qtwebengine.gni -GN_INCLUDES = $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni +qtConfig (webengine-extensions) { + GN_INCLUDES += $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni $$PWD/common/extensions/api/qtwebengine_extensions_features.gni +} else { + GN_INCLUDES = $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni +} GN_CORE_INCLUDE_DIRS = $$PWD/service GN_CREATE_PRI = true QMAKE_INTERNAL_INCLUDED_FILES = $$GN_IMPORTS $$GN_INCLUDES $$GN_FILE + diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp index bd9e0ebe7..40e30e008 100644 --- a/src/core/devtools_frontend_qt.cpp +++ b/src/core/devtools_frontend_qt.cpp @@ -56,11 +56,13 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/post_task.h" #include "base/values.h" #include "chrome/common/url_constants.h" #include "components/prefs/in_memory_pref_store.h" #include "components/prefs/json_pref_store.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_handle.h" @@ -109,9 +111,9 @@ public: ~ResponseWriter() override; // URLFetcherResponseWriter overrides: - int Initialize(const net::CompletionCallback &callback) override; - int Write(net::IOBuffer *buffer, int num_bytes, const net::CompletionCallback &callback) override; - int Finish(int net_error, const net::CompletionCallback &callback) override; + int Initialize(net::CompletionOnceCallback callback) override; + int Write(net::IOBuffer *buffer, int num_bytes, net::CompletionOnceCallback callback) override; + int Finish(int net_error, net::CompletionOnceCallback callback) override; private: base::WeakPtr<DevToolsFrontendQt> shell_devtools_; @@ -126,12 +128,12 @@ ResponseWriter::ResponseWriter(base::WeakPtr<DevToolsFrontendQt> shell_devtools, ResponseWriter::~ResponseWriter() {} -int ResponseWriter::Initialize(const net::CompletionCallback& callback) +int ResponseWriter::Initialize(net::CompletionOnceCallback callback) { return net::OK; } -int ResponseWriter::Write(net::IOBuffer *buffer, int num_bytes, const net::CompletionCallback &callback) +int ResponseWriter::Write(net::IOBuffer *buffer, int num_bytes, net::CompletionOnceCallback callback) { std::string chunk = std::string(buffer->data(), num_bytes); if (!base::IsStringUTF8(chunk)) @@ -140,15 +142,15 @@ int ResponseWriter::Write(net::IOBuffer *buffer, int num_bytes, const net::Compl base::Value *id = new base::Value(stream_id_); base::Value *chunkValue = new base::Value(chunk); - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&DevToolsFrontendQt::CallClientFunction, shell_devtools_, "DevToolsAPI.streamWrite", base::Owned(id), base::Owned(chunkValue), nullptr)); return num_bytes; } -int ResponseWriter::Finish(int net_error, const net::CompletionCallback &callback) +int ResponseWriter::Finish(int net_error, net::CompletionOnceCallback callback) { return net::OK; } diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index f0f0c93b9..c8b75a893 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -166,7 +166,7 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem* suggestedFilename += QStringLiteral(".") + mimeType.preferredSuffix(); } - QDir defaultDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + QDir defaultDownloadDirectory(m_profileAdapter->downloadPath()); QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(suggestedFilename)); QString suggestedFilePath = suggestedFile.absoluteFilePath(); diff --git a/src/core/extensions/component_extension_resource_manager_qt.cpp b/src/core/extensions/component_extension_resource_manager_qt.cpp new file mode 100644 index 000000000..d8326400e --- /dev/null +++ b/src/core/extensions/component_extension_resource_manager_qt.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// based on chrome/browser/extensions/chrome_component_extension_resource_manager.cc: +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "component_extension_resource_manager_qt.h" + +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/grit/component_extension_resources_map.h" + +namespace extensions { + +ComponentExtensionResourceManagerQt::ComponentExtensionResourceManagerQt() +{ + AddComponentResourceEntries(kComponentExtensionResources, + kComponentExtensionResourcesSize); +} + +ComponentExtensionResourceManagerQt::~ComponentExtensionResourceManagerQt() {} + +bool ComponentExtensionResourceManagerQt::IsComponentExtensionResource(const base::FilePath &extension_path, + const base::FilePath &resource_path, + int *resource_id) const +{ + base::FilePath directory_path = extension_path; + base::FilePath resources_dir; + base::FilePath relative_path; + if (!base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_dir) + || !resources_dir.AppendRelativePath(directory_path, &relative_path)) { + return false; + } + + relative_path = relative_path.Append(resource_path); + relative_path = relative_path.NormalizePathSeparators(); + + std::map<base::FilePath, int>::const_iterator entry = path_to_resource_id_.find(relative_path); + if (entry != path_to_resource_id_.end()) + *resource_id = entry->second; + + return entry != path_to_resource_id_.end(); +} + +void ComponentExtensionResourceManagerQt::AddComponentResourceEntries(const GritResourceMap *entries, size_t size) +{ + for (size_t i = 0; i < size; ++i) { + base::FilePath resource_path = base::FilePath().AppendASCII(entries[i].name); + resource_path = resource_path.NormalizePathSeparators(); + + DCHECK(path_to_resource_id_.find(resource_path) == path_to_resource_id_.end()); + path_to_resource_id_[resource_path] = entries[i].value; + } +} + +} // namespace extensions diff --git a/src/core/extensions/component_extension_resource_manager_qt.h b/src/core/extensions/component_extension_resource_manager_qt.h new file mode 100644 index 000000000..f12edf61e --- /dev/null +++ b/src/core/extensions/component_extension_resource_manager_qt.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENT_EXTENSION_RESOURCE_MANAGER_QT_H_ +#define COMPONENT_EXTENSION_RESOURCE_MANAGER_QT_H_ + +#include <map> + +#include "base/files/file_path.h" +#include "extensions/browser/component_extension_resource_manager.h" + +struct GritResourceMap; + +namespace extensions { + +class ComponentExtensionResourceManagerQt : public ComponentExtensionResourceManager +{ +public: + ComponentExtensionResourceManagerQt(); + ~ComponentExtensionResourceManagerQt() override; + + // Overridden from ComponentExtensionResourceManager: + bool IsComponentExtensionResource(const base::FilePath &extension_path, + const base::FilePath &resource_path, + int *resource_id) const override; + +private: + void AddComponentResourceEntries(const GritResourceMap* entries, size_t size); + + // A map from a resource path to the resource ID. Used by + // IsComponentExtensionResource. + std::map<base::FilePath, int> path_to_resource_id_; + + DISALLOW_COPY_AND_ASSIGN(ComponentExtensionResourceManagerQt); +}; + +} // namespace extensions + +#endif // COMPONENT_EXTENSION_RESOURCE_MANAGER_QT_H_ diff --git a/src/core/extensions/extension_system_factory_qt.cpp b/src/core/extensions/extension_system_factory_qt.cpp new file mode 100644 index 000000000..41ba31214 --- /dev/null +++ b/src/core/extensions/extension_system_factory_qt.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extension_system_factory_qt.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/declarative_user_script_manager_factory.h" +#include "extensions/browser/event_router_factory.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry_factory.h" +#include "extensions/browser/extension_system.h" +#include "extensions/browser/extensions_browser_client.h" +#include "extensions/browser/process_manager_factory.h" +#include "extensions/browser/renderer_startup_helper.h" + +namespace extensions { + +// static +ExtensionSystem *ExtensionSystemFactoryQt::GetForBrowserContext(content::BrowserContext *context) +{ + return static_cast<ExtensionSystem *>(GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +ExtensionSystemFactoryQt *ExtensionSystemFactoryQt::GetInstance() +{ + return base::Singleton<ExtensionSystemFactoryQt>::get(); +} + +ExtensionSystemFactoryQt::ExtensionSystemFactoryQt() + : ExtensionSystemProvider("ExtensionSystem", BrowserContextDependencyManager::GetInstance()) +{ + DCHECK(ExtensionsBrowserClient::Get()) << "ExtensionSystemFactory must be initialized after BrowserProcess"; + DependsOn(ExtensionPrefsFactory::GetInstance()); + DependsOn(ExtensionRegistryFactory::GetInstance()); +} + +ExtensionSystemFactoryQt::~ExtensionSystemFactoryQt() +{ +} + +KeyedService *ExtensionSystemFactoryQt::BuildServiceInstanceFor(content::BrowserContext *context) const +{ + return new ExtensionSystemQt(context); +} + +content::BrowserContext *ExtensionSystemFactoryQt::GetBrowserContextToUse(content::BrowserContext *context) const +{ + // Separate instance in incognito. + return context; +} + +bool ExtensionSystemFactoryQt::ServiceIsCreatedWithBrowserContext() const +{ + return true; +} + +} // namespace extensions diff --git a/src/core/extensions/extension_system_factory_qt.h b/src/core/extensions/extension_system_factory_qt.h new file mode 100644 index 000000000..6e840b6d6 --- /dev/null +++ b/src/core/extensions/extension_system_factory_qt.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSION_SYSTEM_FACTORY_QT_H_ +#define EXTENSION_SYSTEM_FACTORY_QT_H_ + +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "extensions/browser/extension_system_provider.h" +#include "extension_system_qt.h" + +namespace extensions { +class ExtensionSystem; + +// BrowserContextKeyedServiceFactory for ExtensionSystemImpl. +// TODO(yoz): Rename to ExtensionSystemImplFactory. +class ExtensionSystemFactoryQt : public ExtensionSystemProvider +{ +public: + // ExtensionSystem provider implementation: + ExtensionSystem *GetForBrowserContext(content::BrowserContext *context) override; + + static ExtensionSystemFactoryQt *GetInstance(); + +private: + friend struct base::DefaultSingletonTraits<ExtensionSystemFactoryQt>; + + ExtensionSystemFactoryQt(); + ~ExtensionSystemFactoryQt() override; + + // BrowserContextKeyedServiceFactory implementation: + KeyedService *BuildServiceInstanceFor(content::BrowserContext *context) const override; + content::BrowserContext *GetBrowserContextToUse(content::BrowserContext *context) const override; + bool ServiceIsCreatedWithBrowserContext() const override; + + DISALLOW_COPY_AND_ASSIGN(ExtensionSystemFactoryQt); +}; + +} // namespace extensions + +#endif // EXTENSION_SYSTEM_FACTORY_QT_H_ diff --git a/src/core/extensions/extension_system_qt.cpp b/src/core/extensions/extension_system_qt.cpp new file mode 100644 index 000000000..4ca407421 --- /dev/null +++ b/src/core/extensions/extension_system_qt.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extension_system_qt.h" + +#include <algorithm> + +#include "base/base_paths.h" +#include "base/base_switches.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/json/json_string_value_serializer.h" +#include "base/memory/ptr_util.h" +#include "base/memory/weak_ptr.h" +#include "base/path_service.h" +#include "base/strings/string_tokenizer.h" +#include "base/strings/utf_string_conversions.h" +#include "base/task/post_task.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "build/build_config.h" +#include "components/crx_file/id_util.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/plugin_service.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/url_data_source.h" +#include "content/public/common/webplugininfo.h" +#include "extensions/browser/content_verifier.h" +#include "extensions/browser/content_verifier_delegate.h" +#include "extensions/browser/extension_pref_store.h" +#include "extensions/browser/extension_pref_value_map.h" +#include "extensions/browser/extension_pref_value_map_factory.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/info_map.h" +#include "extensions/browser/notification_types.h" +#include "extensions/browser/null_app_sorting.h" +#include "extensions/browser/quota_service.h" +#include "extensions/browser/renderer_startup_helper.h" +#include "extensions/browser/runtime_data.h" +#include "extensions/browser/shared_user_script_master.h" +#include "extensions/browser/service_worker_manager.h" +#include "extensions/browser/value_store/value_store_factory_impl.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension_messages.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/manifest_handlers/mime_types_handler.h" +#include "extensions/common/manifest_url_handlers.h" +#include "ui/base/resource/resource_bundle.h" +#include "chrome/grit/component_extension_resources.h" +#include "chrome/grit/browser_resources.h" +#include "net/base/mime_util.h" + +using content::BrowserThread; + +namespace extensions { + +namespace { + +std::string GenerateId(const base::DictionaryValue *manifest, + const base::FilePath &path) +{ + std::string raw_key; + std::string id_input; + CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key)); + CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input)); + std::string id = crx_file::id_util::GenerateId(id_input); + return id; +} + +// Implementation based on ComponentLoader::ParseManifest. +std::unique_ptr<base::DictionaryValue> ParseManifest(const std::string &manifest_contents) +{ + JSONStringValueDeserializer deserializer(manifest_contents); + std::unique_ptr<base::Value> manifest(deserializer.Deserialize(NULL, NULL)); + + if (!manifest.get() || !manifest->is_dict()) { + LOG(ERROR) << "Failed to parse extension manifest."; + return NULL; + } + // Transfer ownership to the caller. + return base::DictionaryValue::From(std::move(manifest)); +} + +} // namespace + +// Dummy Content Verifier Delegate. Added to prevent crashes. +class ContentVerifierDelegateQt + : public ContentVerifierDelegate { + public: + ~ContentVerifierDelegateQt() override {} + + // This should return what verification mode is appropriate for the given + // extension, if any. + Mode ShouldBeVerified(const Extension& extension) override { + return NONE; + } + + // Should return the public key to use for validating signatures via the two + // out parameters. + ContentVerifierKey GetPublicKey() override { + return ContentVerifierKey(); + } + // This should return a URL that can be used to fetch the + // verified_contents.json containing signatures for the given extension + // id/version pair. + GURL GetSignatureFetchUrl(const std::string& extension_id, + const base::Version& version) override { + return GURL(); + } + + // This should return the set of file paths for images used within the + // browser process. (These may get transcoded during the install process). + std::set<base::FilePath> GetBrowserImagePaths( + const extensions::Extension* extension) override { + return std::set<base::FilePath>(); + } + + // Called when the content verifier detects that a read of a file inside + // an extension did not match its expected hash. + void VerifyFailed(const std::string& extension_id, + ContentVerifyJob::FailureReason reason) override { + + } + + // Called when ExtensionSystem is shutting down. + void Shutdown() override { + + } +}; + +void ExtensionSystemQt::LoadExtension(std::string extension_id, std::unique_ptr<base::DictionaryValue> manifest, const base::FilePath &directory) +{ + int flags = Extension::REQUIRE_KEY; + std::string error; + scoped_refptr<const Extension> extension = Extension::Create( + directory, + Manifest::COMPONENT, + *manifest, + flags, + &error); + if (!extension.get()) + LOG(ERROR) << error; + + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::Bind(&InfoMap::AddExtension, + base::Unretained(info_map()), + base::RetainedRef(extension), + base::Time::Now(), + true, + false)); + extension_registry_->AddEnabled(extension.get()); + + NotifyExtensionLoaded(extension.get()); +} + +void ExtensionSystemQt::OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension) +{ + extension_registry_->AddReady(extension); + if (extension_registry_->enabled_extensions().Contains(extension->id())) + extension_registry_->TriggerOnReady(extension.get()); +} + +// Implementation based on ExtensionService::NotifyExtensionLoaded. +void ExtensionSystemQt::NotifyExtensionLoaded(const Extension *extension) +{ + // The URLRequestContexts need to be first to know that the extension + // was loaded, otherwise a race can arise where a renderer that is created + // for the extension may try to load an extension URL with an extension id + // that the request context doesn't yet know about. The profile is responsible + // for ensuring its URLRequestContexts appropriately discover the loaded + // extension. + RegisterExtensionWithRequestContexts( + extension, + base::Bind(&ExtensionSystemQt::OnExtensionRegisteredWithRequestContexts, + weak_ptr_factory_.GetWeakPtr(), + base::WrapRefCounted(extension))); + + // Tell renderers about the loaded extension. + renderer_helper_->OnExtensionLoaded(*extension); + + // Tell subsystems that use the ExtensionRegistryObserver::OnExtensionLoaded + // about the new extension. + // + // NOTE: It is important that this happen after notifying the renderers about + // the new extensions so that if we navigate to an extension URL in + // ExtensionRegistryObserver::OnExtensionLoaded the renderer is guaranteed to + // know about it. + extension_registry_->TriggerOnLoaded(extension); + + // Register plugins included with the extension. + // Implementation based on PluginManager::OnExtensionLoaded. + const MimeTypesHandler *handler = MimeTypesHandler::GetHandler(extension); + if (handler && !handler->handler_url().empty()) { + content::WebPluginInfo info; + info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN; + info.name = base::UTF8ToUTF16(extension->name()); + info.path = base::FilePath::FromUTF8Unsafe(extension->url().spec()); + for (std::set<std::string>::const_iterator mime_type = handler->mime_type_set().begin(); + mime_type != handler->mime_type_set().end(); ++mime_type) { + content::WebPluginMimeType mime_type_info; + mime_type_info.mime_type = *mime_type; + base::FilePath::StringType file_extension; + if (net::GetPreferredExtensionForMimeType(*mime_type, &file_extension)) { + mime_type_info.file_extensions.push_back( + base::FilePath(file_extension).AsUTF8Unsafe()); + } + info.mime_types.push_back(mime_type_info); + } + content::PluginService *plugin_service = + content::PluginService::GetInstance(); + plugin_service->RefreshPlugins(); + plugin_service->RegisterInternalPlugin(info, true); + } +} + +bool ExtensionSystemQt::FinishDelayedInstallationIfReady(const std::string &extension_id, bool install_immediately) +{ + // TODO mibrunin + return false; +} + +void ExtensionSystemQt::Shutdown() +{ + if (content_verifier_.get()) + content_verifier_->Shutdown(); +} + +ServiceWorkerManager *ExtensionSystemQt::service_worker_manager() +{ + return service_worker_manager_.get(); +} + +ExtensionService *ExtensionSystemQt::extension_service() +{ + return nullptr; +} + +RuntimeData *ExtensionSystemQt::runtime_data() +{ + return runtime_data_.get(); +} + +ManagementPolicy *ExtensionSystemQt::management_policy() +{ + return nullptr; +} + +SharedUserScriptMaster *ExtensionSystemQt::shared_user_script_master() +{ + return shared_user_script_master_.get(); +} + +StateStore *ExtensionSystemQt::state_store() +{ + return nullptr; +} + +StateStore *ExtensionSystemQt::rules_store() +{ + return nullptr; +} + +scoped_refptr<ValueStoreFactory> ExtensionSystemQt::store_factory() +{ + return store_factory_; +} + +InfoMap *ExtensionSystemQt::info_map() +{ + if (!info_map_.get()) + info_map_ = new InfoMap; + return info_map_.get(); +} + +QuotaService *ExtensionSystemQt::quota_service() +{ + return quota_service_.get(); +} + +AppSorting *ExtensionSystemQt::app_sorting() +{ + return app_sorting_.get(); +} + +ContentVerifier *ExtensionSystemQt::content_verifier() +{ + if (!content_verifier_.get()) { + content_verifier_ = new ContentVerifier(browser_context_, std::make_unique<ContentVerifierDelegateQt>()); + } + return content_verifier_.get(); +} + +ExtensionSystemQt::ExtensionSystemQt(content::BrowserContext *browserContext) + : browser_context_(browserContext) + , store_factory_(new ValueStoreFactoryImpl(browserContext->GetPath())) + , extension_registry_(ExtensionRegistry::Get(browserContext)) + , renderer_helper_(extensions::RendererStartupHelperFactory::GetForBrowserContext(browserContext)) + , initialized_(false) + , weak_ptr_factory_(this) +{ +} + +ExtensionSystemQt::~ExtensionSystemQt() +{ +} + +void ExtensionSystemQt::Init(bool extensions_enabled) +{ + if (initialized_) + return; + + initialized_ = true; + + service_worker_manager_.reset(new ServiceWorkerManager(browser_context_)); + runtime_data_.reset(new RuntimeData(extension_registry_)); + quota_service_.reset(new QuotaService); + app_sorting_.reset(new NullAppSorting); + + shared_user_script_master_ = + std::make_unique<SharedUserScriptMaster>(browser_context_); + + // Make the chrome://extension-icon/ resource available. + // content::URLDataSource::Add(browser_context_, new ExtensionIconSource(browser_context_)); + + if (extensions_enabled) { + // Inform the rest of the extensions system to start. + ready_.Signal(); + content::NotificationService::current()->Notify( + NOTIFICATION_EXTENSIONS_READY_DEPRECATED, + content::Source<content::BrowserContext>(browser_context_), + content::NotificationService::NoDetails()); + + std::string pdf_manifest = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PDF_MANIFEST).as_string(); + base::ReplaceFirstSubstringAfterOffset(&pdf_manifest, 0, "<NAME>", "chromium-pdf"); + + std::unique_ptr<base::DictionaryValue> pdfManifestDict = ParseManifest(pdf_manifest); + base::FilePath path; + base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &path); + path = path.Append(base::FilePath(FILE_PATH_LITERAL("pdf"))); + std::string id = GenerateId(pdfManifestDict.get(), path); + LoadExtension(id, std::move(pdfManifestDict), path); + } +} + +void ExtensionSystemQt::InitForRegularProfile(bool extensions_enabled) +{ + if (initialized_) + return; // Already initialized. + // The InfoMap needs to be created before the ProcessManager. + info_map(); + + Init(extensions_enabled); +} + +void ExtensionSystemQt::InitForIncognitoProfile() +{ + NOTIMPLEMENTED(); +} + +std::unique_ptr<ExtensionSet> ExtensionSystemQt::GetDependentExtensions(const Extension *extension) +{ + return base::WrapUnique(new ExtensionSet()); +} + +#if !defined(TOOLKIT_QT) +void ExtensionSystemQt::InstallUpdate(const std::string &extension_id, + const std::string &public_key, + const base::FilePath &unpacked_dir, + bool install_immediately, + InstallUpdateCallback install_update_callback) +{ + NOTREACHED() << "Not yet implemented"; + base::DeleteFile(unpacked_dir, true /* recursive */); + std::move(install_update_callback).Run(CrxInstallError(CrxInstallErrorType::DECLINED, CrxInstallErrorDetail::DISALLOWED_BY_POLICY)); +} +#endif + +void ExtensionSystemQt::RegisterExtensionWithRequestContexts(const Extension *extension, + const base::Closure &callback) +{ + base::Time install_time = base::Time::Now(); + + bool incognito_enabled = false; + bool notifications_disabled = false; + + base::PostTaskWithTraitsAndReply( + FROM_HERE, {BrowserThread::IO}, + base::Bind(&InfoMap::AddExtension, info_map(), + base::RetainedRef(extension), install_time, incognito_enabled, + notifications_disabled), + callback); +} + +void ExtensionSystemQt::UnregisterExtensionWithRequestContexts(const std::string &extension_id, + const UnloadedExtensionReason reason) +{ + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::Bind(&InfoMap::RemoveExtension, info_map(), extension_id, reason)); +} +} // namespace extensions diff --git a/src/core/extensions/extension_system_qt.h b/src/core/extensions/extension_system_qt.h new file mode 100644 index 000000000..0ebe1d044 --- /dev/null +++ b/src/core/extensions/extension_system_qt.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Large parts of this file are based on the source code from the file +// chrome/browser/extensions/extension_system_impl.h from the Chromium sources. + +#ifndef EXTENSION_SYSTEM_QT_H +#define EXTENSION_SYSTEM_QT_H + +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "build/build_config.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/extension_set.h" +#include "extensions/common/one_shot_event.h" + +namespace extensions { + +class ExtensionRegistry; +class InfoMap; +class RendererStartupHelper; +class ServiceWorkerManager; +class StateStoreNotificationObserver; +class ValueStoreFactory; +class ValueStoreFactoryImpl; + +// The ExtensionSystem for ProfileImpl and OffTheRecordProfileImpl. +// Implementation details: non-shared services are owned by +// ExtensionSystemImpl, a KeyedService with separate incognito +// instances. A private Shared class (also a KeyedService, +// but with a shared instance for incognito) keeps the common services. +class ExtensionSystemQt : public ExtensionSystem +{ +public: + explicit ExtensionSystemQt(content::BrowserContext *browserContext); + ~ExtensionSystemQt() override; + + // Initializes the extension system. + void Initialize(); + + // KeyedService implementation: + void Shutdown() override; + + // ExtensionSystem implementation: + void InitForRegularProfile(bool extensions_enabled) override; + void InitForIncognitoProfile() override; + ExtensionService *extension_service() override; + RuntimeData *runtime_data() override; + ManagementPolicy *management_policy() override; + ServiceWorkerManager *service_worker_manager() override; + SharedUserScriptMaster *shared_user_script_master() override; + StateStore* state_store() override; + StateStore* rules_store() override; + scoped_refptr<ValueStoreFactory> store_factory() override; + InfoMap *info_map() override; + QuotaService *quota_service() override; + AppSorting *app_sorting() override; + + void RegisterExtensionWithRequestContexts(const Extension *extension, + const base::Closure &callback) override; + + void UnregisterExtensionWithRequestContexts(const std::string &extension_id, + const UnloadedExtensionReason reason) override; + + ContentVerifier *content_verifier() override; + std::unique_ptr<ExtensionSet> GetDependentExtensions(const Extension *extension) override; + +#if !defined(TOOLKIT_QT) + void InstallUpdate(const std::string &extension_id, + const std::string &public_key, + const base::FilePath &unpacked_dir, + bool install_immediately, + InstallUpdateCallback install_update_callback) override; +#endif // TOOLKIT_QT + //friend class ExtensionSystemSharedFactory; + + bool FinishDelayedInstallationIfReady(const std::string &extension_id, bool install_immediately) override; + + void Init(bool extensions_enabled); + + const OneShotEvent &ready() const override { return ready_; } + +private: + void OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension); + + void NotifyExtensionLoaded(const Extension *extension); + void LoadExtension(std::string extension_id, std::unique_ptr<base::DictionaryValue> manifest, const base::FilePath &directory); + // The services that are shared between normal and incognito profiles. + + // Data to be accessed on the IO thread. Must outlive process_manager_. + scoped_refptr<InfoMap> info_map_; + + std::unique_ptr<ServiceWorkerManager> service_worker_manager_; + std::unique_ptr<RuntimeData> runtime_data_; + std::unique_ptr<QuotaService> quota_service_; + std::unique_ptr<AppSorting> app_sorting_; + std::unique_ptr<SharedUserScriptMaster> shared_user_script_master_; + + + // For verifying the contents of extensions read from disk. + scoped_refptr<ContentVerifier> content_verifier_; + OneShotEvent ready_; + + content::BrowserContext *browser_context_; + scoped_refptr<ValueStoreFactory> store_factory_; + ExtensionRegistry *extension_registry_; + extensions::RendererStartupHelper *renderer_helper_; + bool initialized_; + + base::WeakPtrFactory<ExtensionSystemQt> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ExtensionSystemQt); +}; + +} // namespace extensions + +#endif // EXTENSION_SYSTEM_QT_H diff --git a/src/core/extensions/extension_web_contents_observer_qt.cpp b/src/core/extensions/extension_web_contents_observer_qt.cpp new file mode 100644 index 000000000..1eb2298ca --- /dev/null +++ b/src/core/extensions/extension_web_contents_observer_qt.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$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extension_web_contents_observer_qt.h" + +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/common/url_constants.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/manifest.h" + +namespace extensions { + +ExtensionWebContentsObserverQt::ExtensionWebContentsObserverQt(content::WebContents *web_contents) + : ExtensionWebContentsObserver(web_contents) +{ +} + +ExtensionWebContentsObserverQt::~ExtensionWebContentsObserverQt() +{ +} + +// static +void ExtensionWebContentsObserverQt::CreateForWebContents(content::WebContents *web_contents) +{ + content::WebContentsUserData<ExtensionWebContentsObserverQt>::CreateForWebContents(web_contents); + + // Initialize this instance if necessary. + FromWebContents(web_contents)->Initialize(); +} + +std::string ExtensionWebContentsObserverQt::GetExtensionIdFromFrame(content::RenderFrameHost *render_frame_host) const +{ + const GURL &site = render_frame_host->GetSiteInstance()->GetSiteURL(); + if (!site.SchemeIs(kExtensionScheme)) + return std::string(); + + return site.host(); +} + +const Extension *ExtensionWebContentsObserverQt::GetExtensionFromFrame(content::RenderFrameHost *render_frame_host, bool verify_url) const +{ + std::string extension_id = GetExtensionIdFromFrame(render_frame_host); + if (extension_id.empty()) + return nullptr; + + content::BrowserContext *browser_context = + render_frame_host->GetProcess()->GetBrowserContext(); + const Extension *extension = ExtensionRegistry::Get(browser_context) + ->enabled_extensions() + .GetByID(extension_id); + if (!extension) + return nullptr; + + if (verify_url) { + const url::Origin &origin(render_frame_host->GetLastCommittedOrigin()); + // Without site isolation, this check is needed to eliminate non-extension + // schemes. With site isolation, this is still needed to exclude sandboxed + // extension frames with a unique origin. + const GURL site_url(render_frame_host->GetSiteInstance()->GetSiteURL()); + if (origin.opaque() || site_url != content::SiteInstance::GetSiteForURL(browser_context, origin.GetURL())) + return nullptr; + } + + return extension; +} + +void ExtensionWebContentsObserverQt::RenderFrameCreated(content::RenderFrameHost *render_frame_host) +{ + ExtensionWebContentsObserver::RenderFrameCreated(render_frame_host); + + const Extension *extension = GetExtensionFromFrame(render_frame_host, false); + if (!extension) + return; + + int process_id = render_frame_host->GetProcess()->GetID(); + auto *policy = content::ChildProcessSecurityPolicy::GetInstance(); + + if (extension->is_extension() && Manifest::IsComponentLocation(extension->location())) + policy->GrantRequestOrigin(process_id, url::Origin::Create(GURL(content::kChromeUIResourcesURL))); +} + +} // namespace extensions diff --git a/src/core/extensions/extension_web_contents_observer_qt.h b/src/core/extensions/extension_web_contents_observer_qt.h new file mode 100644 index 000000000..043b9d4fa --- /dev/null +++ b/src/core/extensions/extension_web_contents_observer_qt.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSION_WEB_CONTENTS_OBSERVER_QT_H_ +#define EXTENSION_WEB_CONTENTS_OBSERVER_QT_H_ + +#include "content/public/browser/web_contents_user_data.h" +#include "extensions/browser/extension_web_contents_observer.h" + +namespace extensions { + +class ExtensionWebContentsObserverQt + : public ExtensionWebContentsObserver, + public content::WebContentsUserData<ExtensionWebContentsObserverQt> +{ +public: + explicit ExtensionWebContentsObserverQt(content::WebContents *web_contents); + ~ExtensionWebContentsObserverQt() override; + + static void CreateForWebContents(content::WebContents *web_contents); + + std::string GetExtensionIdFromFrame(content::RenderFrameHost *) const; + const Extension *GetExtensionFromFrame(content::RenderFrameHost *, bool) const; + + // content::WebContentsObserver overrides. + void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override; + +private: + friend class content::WebContentsUserData<ExtensionWebContentsObserverQt>; + DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserverQt); +}; + +} // namespace extensions + +#endif // EXTENSION_WEB_CONTENTS_OBSERVER_QT_H_ diff --git a/src/core/extensions/extensions_api_client_qt.cpp b/src/core/extensions/extensions_api_client_qt.cpp new file mode 100644 index 000000000..731b79a63 --- /dev/null +++ b/src/core/extensions/extensions_api_client_qt.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_api_client_qt.h" + +#include <memory> +//#include "base/memory/ptr_util.h" +#include "extension_web_contents_observer_qt.h" +#include "components/pdf/browser/pdf_web_contents_helper.h" +#include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h" +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" +#include "printing/print_view_manager_qt.h" + +namespace extensions { + +ExtensionsAPIClientQt::ExtensionsAPIClientQt() +{ +} + +AppViewGuestDelegate *ExtensionsAPIClientQt::CreateAppViewGuestDelegate() const +{ + // TODO(extensions): Implement to support Apps. + NOTREACHED(); + return nullptr; +} + +std::unique_ptr<guest_view::GuestViewManagerDelegate> ExtensionsAPIClientQt::CreateGuestViewManagerDelegate(content::BrowserContext *context) const +{ + return std::make_unique<guest_view::GuestViewManagerDelegate>(); +} + +std::unique_ptr<MimeHandlerViewGuestDelegate> ExtensionsAPIClientQt::CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest *guest) const +{ + return std::make_unique<MimeHandlerViewGuestDelegate>(); +} + +void ExtensionsAPIClientQt::AttachWebContentsHelpers(content::WebContents *web_contents) const +{ + // PrefsTabHelper::CreateForWebContents(web_contents); + QtWebEngineCore::PrintViewManagerQt::CreateForWebContents(web_contents); + ExtensionWebContentsObserverQt::CreateForWebContents(web_contents); +} + +} // namespace extensions diff --git a/src/core/extensions/extensions_api_client_qt.h b/src/core/extensions/extensions_api_client_qt.h new file mode 100644 index 000000000..2fa69f539 --- /dev/null +++ b/src/core/extensions/extensions_api_client_qt.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_API_CLIENT_QT_H_ +#define EXTENSIONS_API_CLIENT_QT_H_ + +#include "extensions/browser/api/extensions_api_client.h" + +namespace extensions { + +class ExtensionsAPIClientQt : public ExtensionsAPIClient +{ +public: + ExtensionsAPIClientQt(); + + // ExtensionsAPIClient implementation. + AppViewGuestDelegate *CreateAppViewGuestDelegate() const override; + std::unique_ptr<guest_view::GuestViewManagerDelegate> + CreateGuestViewManagerDelegate(content::BrowserContext *context) const override; + std::unique_ptr<MimeHandlerViewGuestDelegate> + CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest *guest) const override; + void AttachWebContentsHelpers(content::WebContents *web_contents) const override; +}; + +} // namespace extensions + +#endif // EXTENSIONS_API_CLIENT_QT_H_ diff --git a/src/core/extensions/extensions_browser_api_provider_qt.cpp b/src/core/extensions/extensions_browser_api_provider_qt.cpp new file mode 100644 index 000000000..cc1932c64 --- /dev/null +++ b/src/core/extensions/extensions_browser_api_provider_qt.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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 "extensions_browser_api_provider_qt.h" + +#include "extensions/browser/api/generated_api_registration.h" + +namespace extensions { +ExtensionsBrowserAPIProviderQt::ExtensionsBrowserAPIProviderQt() = + default; +ExtensionsBrowserAPIProviderQt::~ExtensionsBrowserAPIProviderQt() = + default; + +void ExtensionsBrowserAPIProviderQt::RegisterExtensionFunctions( + ExtensionFunctionRegistry* registry) { + api::GeneratedFunctionRegistry::RegisterAll(registry); +} + + +} + diff --git a/src/core/extensions/extensions_browser_api_provider_qt.h b/src/core/extensions/extensions_browser_api_provider_qt.h new file mode 100644 index 000000000..612df3825 --- /dev/null +++ b/src/core/extensions/extensions_browser_api_provider_qt.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef EXTENSIONS_API_PROVIDER_QT_H +#define EXTENSIONS_API_PROVIDER_QT_H + +#include "extensions/browser/extensions_browser_api_provider.h" +#include "base/macros.h" + +namespace extensions { + +class ExtensionsBrowserAPIProviderQt : public ExtensionsBrowserAPIProvider { +public: + ExtensionsBrowserAPIProviderQt(); + ~ExtensionsBrowserAPIProviderQt() override; + + void RegisterExtensionFunctions(ExtensionFunctionRegistry *registry) override; + +private: + DISALLOW_COPY_AND_ASSIGN(ExtensionsBrowserAPIProviderQt); +}; + +} + +#endif // EXTENSIONS_API_PROVIDER_QT_H diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp new file mode 100644 index 000000000..8bba4128f --- /dev/null +++ b/src/core/extensions/extensions_browser_client_qt.cpp @@ -0,0 +1,499 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_browser_client_qt.h" + +#include <utility> + +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/path_service.h" +#include "base/strings/stringprintf.h" +#include "base/task/post_task.h" +#include "base/memory/ref_counted_memory.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" +#include "extensions/browser/app_sorting.h" +#include "extensions/browser/core_extensions_browser_api_provider.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_host_delegate.h" +#include "extensions/browser/extension_protocols.h" +#include "extensions/browser/mojo/interface_registration.h" +#include "extensions/browser/url_request_util.h" +#include "extensions/common/file_util.h" +#include "net/base/completion_once_callback.h" +#include "net/base/mime_util.h" +#include "net/url_request/url_request_simple_job.h" +#include "ui/base/resource/resource_bundle.h" + +#include "component_extension_resource_manager_qt.h" +#include "extension_system_factory_qt.h" +#include "extension_web_contents_observer_qt.h" +#include "extensions_api_client_qt.h" +#include "extensions_browser_api_provider_qt.h" +#include "extensions_browser_client_qt.h" +#include "web_engine_library_info.h" + +using content::BrowserContext; +using content::BrowserThread; + +namespace { + +// helpers based on implementation in chrome_url_request_util.cc: +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +void DetermineCharset(const std::string &mime_type, + const base::RefCountedMemory *data, + std::string *out_charset) +{ + if (base::StartsWith(mime_type, "text/", base::CompareCase::INSENSITIVE_ASCII)) { + // All of our HTML files should be UTF-8 and for other resource types + // (like images), charset doesn't matter. + DCHECK(base::IsStringUTF8(base::StringPiece(reinterpret_cast<const char*>(data->front()), data->size()))); + *out_charset = "utf-8"; + } +} + +// A request for an extension resource in a Chrome .pak file. These are used +// by component extensions. +class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { +public: + URLRequestResourceBundleJob(net::URLRequest *request, + net::NetworkDelegate *network_delegate, + const base::FilePath &filename, + int resource_id, + const std::string &content_security_policy, + bool send_cors_header) + : net::URLRequestSimpleJob(request, network_delegate) + , filename_(filename) + , resource_id_(resource_id) + , weak_factory_(this) + { + // Leave cache headers out of resource bundle requests. + response_info_.headers = extensions::BuildHttpHeaders(content_security_policy, send_cors_header, base::Time()); + } + int GetRefCountedData(std::string* mime_type, + std::string* charset, + scoped_refptr<base::RefCountedMemory>* data, + net::CompletionOnceCallback callback) const override + { + const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + *data = rb.LoadDataResourceBytes(resource_id_); + + // Add the Content-Length header now that we know the resource length. + response_info_.headers->AddHeader( + base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentLength, + base::NumberToString((*data)->size()).c_str())); + + std::string* read_mime_type = new std::string; + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&net::GetMimeTypeFromFile, filename_, + base::Unretained(read_mime_type)), + base::BindOnce(&URLRequestResourceBundleJob::OnMimeTypeRead, + weak_factory_.GetWeakPtr(), mime_type, charset, *data, + base::Owned(read_mime_type), std::move(callback))); + + return net::ERR_IO_PENDING; + } + + void GetResponseInfo(net::HttpResponseInfo* info) override + { + *info = response_info_; + } + +private: + ~URLRequestResourceBundleJob() override {} + + void OnMimeTypeRead(std::string *out_mime_type, + std::string *charset, + scoped_refptr<base::RefCountedMemory> data, + std::string *read_mime_type, + net::CompletionOnceCallback callback, + bool read_result) + { + response_info_.headers->AddHeader( + base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType, + read_mime_type->c_str())); + *out_mime_type = *read_mime_type; + DetermineCharset(*read_mime_type, data.get(), charset); + int result = read_result ? net::OK : net::ERR_INVALID_URL; + std::move(callback).Run(result); + } + + // We need the filename of the resource to determine the mime type. + base::FilePath filename_; + + // The resource bundle id to load. + int resource_id_; + + net::HttpResponseInfo response_info_; + + mutable base::WeakPtrFactory<URLRequestResourceBundleJob> weak_factory_; +}; + +} // namespace + +namespace extensions { + +ExtensionsBrowserClientQt::ExtensionsBrowserClientQt() + : api_client_(new ExtensionsAPIClientQt) + , resource_manager_(new ComponentExtensionResourceManagerQt) +{ + AddAPIProvider(std::make_unique<CoreExtensionsBrowserAPIProvider>()); + AddAPIProvider(std::make_unique<ExtensionsBrowserAPIProviderQt>()); +} + +ExtensionsBrowserClientQt::~ExtensionsBrowserClientQt() +{ +} + +bool ExtensionsBrowserClientQt::IsShuttingDown() +{ + return false; +} + +bool ExtensionsBrowserClientQt::AreExtensionsDisabled(const base::CommandLine &command_line, BrowserContext *context) +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsValidContext(BrowserContext *context) +{ + return true; +} + +bool ExtensionsBrowserClientQt::IsSameContext(BrowserContext *first, + BrowserContext *second) +{ + return first == second; +} + +bool ExtensionsBrowserClientQt::HasOffTheRecordContext(BrowserContext *context) +{ + return false; +} + +BrowserContext *ExtensionsBrowserClientQt::GetOffTheRecordContext(BrowserContext *context) +{ + // TODO(extensions): Do we need to support this? + return nullptr; +} + +BrowserContext *ExtensionsBrowserClientQt::GetOriginalContext(BrowserContext *context) +{ + return context; +} + +bool ExtensionsBrowserClientQt::IsGuestSession(BrowserContext *context) const +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsExtensionIncognitoEnabled(const std::string &extension_id, + content::BrowserContext *context) const +{ + return false; +} + +bool ExtensionsBrowserClientQt::CanExtensionCrossIncognito(const Extension *extension, + content::BrowserContext *context) const +{ + return false; +} + +net::URLRequestJob *ExtensionsBrowserClientQt::MaybeCreateResourceBundleRequestJob(net::URLRequest *request, + net::NetworkDelegate *network_delegate, + const base::FilePath &directory_path, + const std::string &content_security_policy, + bool send_cors_header) +{ + base::FilePath resources_path; + base::FilePath relative_path; + // Try to load extension resources from chrome resource file if + // directory_path is a descendant of resources_path. resources_path + // corresponds to src/chrome/browser/resources in source tree. + if (base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_path) && + // Since component extension resources are included in + // component_extension_resources.pak file in resources_path, calculate + // extension relative path against resources_path. + resources_path.AppendRelativePath(directory_path, &relative_path)) { + base::FilePath request_path = extensions::file_util::ExtensionURLToRelativeFilePath(request->url()); + int resource_id = 0; + if (GetComponentExtensionResourceManager()->IsComponentExtensionResource(directory_path, request_path, &resource_id)) { + relative_path = relative_path.Append(request_path); + relative_path = relative_path.NormalizePathSeparators(); + return new URLRequestResourceBundleJob(request, + network_delegate, + relative_path, + resource_id, + content_security_policy, + send_cors_header); + } + } + return nullptr; +} + +// Return the resource relative path and id for the given request. +base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::ResourceRequest &request, + const base::FilePath &extension_resources_path, + int *resource_id) const +{ + *resource_id = 0; + // |chrome_resources_path| corresponds to src/chrome/browser/resources in + // source tree. + base::FilePath resources_path; + if (!base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_path)) + return base::FilePath(); + + // Since component extension resources are included in + // component_extension_resources.pak file in |chrome_resources_path|, + // calculate the extension |request_relative_path| against + // |chrome_resources_path|. + if (!resources_path.IsParent(extension_resources_path)) + return base::FilePath(); + + const base::FilePath request_relative_path = + extensions::file_util::ExtensionURLToRelativeFilePath(request.url); + if (!ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->IsComponentExtensionResource( + extension_resources_path, request_relative_path, resource_id)) { + return base::FilePath(); + } + DCHECK_NE(0, *resource_id); + + return request_relative_path; +} + +// Creates and starts a URLLoader to load an extension resource from the +// embedder's resource bundle (.pak) files. Used for component extensions. +void ExtensionsBrowserClientQt::LoadResourceFromResourceBundle(const network::ResourceRequest &request, + network::mojom::URLLoaderRequest loader, + const base::FilePath &resource_relative_path, + int resource_id, + const std::string &content_security_policy, + network::mojom::URLLoaderClientPtr client, + bool send_cors_header) +{ + NOTIMPLEMENTED(); +} + + +bool ExtensionsBrowserClientQt::AllowCrossRendererResourceLoad(const GURL &url, + content::ResourceType resource_type, + ui::PageTransition page_transition, + int child_id, + bool is_incognito, + const Extension *extension, + const ExtensionSet &extensions, + const ProcessMap &process_map) +{ + + if (extension && extension->id() == extension_misc::kPdfExtensionId) + return true; + + bool allowed = false; + if (url_request_util::AllowCrossRendererResourceLoad(url, resource_type, + page_transition, child_id, + is_incognito, extension, extensions, + process_map, &allowed)) { + return allowed; + } + // Couldn't determine if resource is allowed. Block the load. + return false; +} + +PrefService *ExtensionsBrowserClientQt::GetPrefServiceForContext(BrowserContext *context) +{ + return static_cast<Profile *>(context)->GetPrefs(); +} + +void ExtensionsBrowserClientQt::GetEarlyExtensionPrefsObservers(content::BrowserContext *context, + std::vector<ExtensionPrefsObserver *> *observers) const +{ +} + +ProcessManagerDelegate *ExtensionsBrowserClientQt::GetProcessManagerDelegate() const +{ + return nullptr; +} + +std::unique_ptr<ExtensionHostDelegate> ExtensionsBrowserClientQt::CreateExtensionHostDelegate() +{ + // TODO(extensions): Implement to support Apps. + NOTREACHED(); + return std::unique_ptr<ExtensionHostDelegate>(); +} + +bool ExtensionsBrowserClientQt::DidVersionUpdate(BrowserContext *context) +{ + // TODO(jamescook): We might want to tell extensions when app_shell updates. + return false; +} + +void ExtensionsBrowserClientQt::PermitExternalProtocolHandler() +{ +} + +bool ExtensionsBrowserClientQt::IsRunningInForcedAppMode() +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsLoggedInAsPublicAccount() +{ + return false; +} + +ExtensionSystemProvider *ExtensionsBrowserClientQt::GetExtensionSystemFactory() +{ + return ExtensionSystemFactoryQt::GetInstance(); +} + +// void ExtensionsBrowserClientQt::RegisterExtensionFunctions(ExtensionFunctionRegistry *registry) const +//{ +// // Register core extension-system APIs. +// api::GeneratedFunctionRegistry::RegisterAll(registry); +//} + +void ExtensionsBrowserClientQt::RegisterExtensionInterfaces(service_manager::BinderRegistryWithArgs<content::RenderFrameHost *> *registry, + content::RenderFrameHost *render_frame_host, + const Extension *extension) const +{ + RegisterInterfacesForExtension(registry, render_frame_host, extension); +} + +std::unique_ptr<RuntimeAPIDelegate> ExtensionsBrowserClientQt::CreateRuntimeAPIDelegate(content::BrowserContext *context) const +{ + // TODO(extensions): Implement to support Apps. + NOTREACHED(); + return std::unique_ptr<RuntimeAPIDelegate>(); +} + +const ComponentExtensionResourceManager *ExtensionsBrowserClientQt::GetComponentExtensionResourceManager() +{ + return resource_manager_.get(); +} + +void ExtensionsBrowserClientQt::BroadcastEventToRenderers(events::HistogramValue histogram_value, + const std::string &event_name, + std::unique_ptr<base::ListValue> args) +{ + NOTIMPLEMENTED(); + // TODO : do the event routing + // event_router_forwarder_->BroadcastEventToRenderers( + // histogram_value, event_name, std::move(args), GURL()); +} + +net::NetLog *ExtensionsBrowserClientQt::GetNetLog() +{ + return nullptr; +} + +ExtensionCache *ExtensionsBrowserClientQt::GetExtensionCache() +{ + // Only used by Chrome via ExtensionService. + NOTREACHED(); + return nullptr; +} + +bool ExtensionsBrowserClientQt::IsBackgroundUpdateAllowed() +{ + return true; +} + +bool ExtensionsBrowserClientQt::IsMinBrowserVersionSupported( + const std::string &min_version) +{ + return true; +} + +bool ExtensionsBrowserClientQt::IsLockScreenContext(content::BrowserContext *context) +{ + return false; +} + +// Returns the locale used by the application. +std::string ExtensionsBrowserClientQt::GetApplicationLocale() +{ + return WebEngineLibraryInfo::getApplicationLocale(); +} + +bool ExtensionsBrowserClientQt::IsAppModeForcedForApp(const ExtensionId &id) +{ + return false; +} + +bool ExtensionsBrowserClientQt::IsInDemoMode() +{ + return false; +} + +ExtensionWebContentsObserver *ExtensionsBrowserClientQt::GetExtensionWebContentsObserver(content::WebContents *web_contents) +{ + return ExtensionWebContentsObserverQt::FromWebContents(web_contents); +} + +KioskDelegate *ExtensionsBrowserClientQt::GetKioskDelegate() +{ + NOTREACHED(); + return nullptr; +} + +bool ExtensionsBrowserClientQt::IsScreensaverInDemoMode(const std::string& app_id) +{ + return false; +} + +void ExtensionsBrowserClientQt::SetAPIClientForTest(ExtensionsAPIClient *api_client) +{ + api_client_.reset(api_client); +} + +} // namespace extensions diff --git a/src/core/extensions/extensions_browser_client_qt.h b/src/core/extensions/extensions_browser_client_qt.h new file mode 100644 index 000000000..f766b96a7 --- /dev/null +++ b/src/core/extensions/extensions_browser_client_qt.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_CLIENT_QT_H_ +#define EXTENSIONS_BROWSER_CLIENT_QT_H_ + +#include "base/compiler_specific.h" +#include "extensions/browser/extensions_browser_client.h" + +namespace extensions { + +class ExtensionsAPIClient; + +// An ExtensionsBrowserClient that supports a single content::BrowserContent +// with no related incognito context. +class ExtensionsBrowserClientQt : public ExtensionsBrowserClient +{ +public: + ExtensionsBrowserClientQt(); + ~ExtensionsBrowserClientQt() override; + + // ExtensionsBrowserClient overrides: + bool IsShuttingDown() override; + bool AreExtensionsDisabled(const base::CommandLine &command_line, + content::BrowserContext *context) override; + bool IsValidContext(content::BrowserContext *context) override; + bool IsSameContext(content::BrowserContext *first, + content::BrowserContext *second) override; + bool HasOffTheRecordContext(content::BrowserContext *context) override; + content::BrowserContext *GetOffTheRecordContext(content::BrowserContext *context) override; + content::BrowserContext *GetOriginalContext(content::BrowserContext *context) override; + bool IsGuestSession(content::BrowserContext *context) const override; + bool IsExtensionIncognitoEnabled(const std::string &extension_id, content::BrowserContext *context) const override; + bool CanExtensionCrossIncognito(const Extension *extension, content::BrowserContext *context) const override; + net::URLRequestJob *MaybeCreateResourceBundleRequestJob(net::URLRequest *request, + net::NetworkDelegate *network_delegate, + const base::FilePath &directory_path, + const std::string &content_security_policy, + bool send_cors_header) override; + bool AllowCrossRendererResourceLoad(const GURL &url, + content::ResourceType resource_type, + ui::PageTransition page_transition, + int child_id, + bool is_incognito, + const Extension *extension, + const ExtensionSet &extensions, + const ProcessMap &process_map) override; + PrefService *GetPrefServiceForContext(content::BrowserContext *context) override; + void GetEarlyExtensionPrefsObservers(content::BrowserContext *context, std::vector<ExtensionPrefsObserver *> *observers) const + override; + ProcessManagerDelegate *GetProcessManagerDelegate() const override; + std::unique_ptr<ExtensionHostDelegate> + CreateExtensionHostDelegate() override; + bool DidVersionUpdate(content::BrowserContext *context) override; + void PermitExternalProtocolHandler() override; + bool IsRunningInForcedAppMode() override; + bool IsLoggedInAsPublicAccount() override; + ExtensionSystemProvider *GetExtensionSystemFactory() override; +// void RegisterExtensionFunctions(ExtensionFunctionRegistry *registry) const; + std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(content::BrowserContext *context) const override; + void RegisterExtensionInterfaces(service_manager::BinderRegistryWithArgs<content::RenderFrameHost *> *registry, + content::RenderFrameHost *render_frame_host, + const Extension *extension) const override; + const ComponentExtensionResourceManager * + GetComponentExtensionResourceManager() override; + void BroadcastEventToRenderers(events::HistogramValue histogram_value, + const std::string &event_name, + std::unique_ptr<base::ListValue> args) override; + net::NetLog *GetNetLog() override; + ExtensionCache *GetExtensionCache() override; + bool IsBackgroundUpdateAllowed() override; + bool IsMinBrowserVersionSupported(const std::string &min_version) override; + ExtensionWebContentsObserver *GetExtensionWebContentsObserver( + content::WebContents *web_contents) override; + KioskDelegate *GetKioskDelegate() override; + + // Whether the browser context is associated with Chrome OS lock screen. + bool IsLockScreenContext(content::BrowserContext *context) override; + + bool IsAppModeForcedForApp(const ExtensionId &id) override; + bool IsInDemoMode() override; + + // Return the resource relative path and id for the given request. + base::FilePath GetBundleResourcePath(const network::ResourceRequest &request, + const base::FilePath &extension_resources_path, + int *resource_id) const override; + + // Creates and starts a URLLoader to load an extension resource from the + // embedder's resource bundle (.pak) files. Used for component extensions. + void LoadResourceFromResourceBundle(const network::ResourceRequest &request, + network::mojom::URLLoaderRequest loader, + const base::FilePath &resource_relative_path, + int resource_id, + const std::string &content_security_policy, + network::mojom::URLLoaderClientPtr client, + bool send_cors_header) override; + + // Returns the locale used by the application. + std::string GetApplicationLocale() override; + + bool IsScreensaverInDemoMode(const std::string& app_id) override; + + // Sets the API client. + void SetAPIClientForTest(ExtensionsAPIClient *api_client); + +private: + // Support for extension APIs. + std::unique_ptr<ExtensionsAPIClient> api_client_; + + // Resource manager used to supply resources from pak files. + std::unique_ptr<ComponentExtensionResourceManager> resource_manager_; + + //scoped_refptr<EventRouterForwarder> event_router_forwarder_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionsBrowserClientQt); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_CLIENT_QT_H_ diff --git a/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp b/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp new file mode 100644 index 000000000..438b8a83e --- /dev/null +++ b/src/core/extensions/mime_handler_view_guest_delegate_qt.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mime_handler_view_guest_delegate_qt.h" + +#include "content/browser/browser_plugin/browser_plugin_guest.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/context_menu_params.h" +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" + +namespace extensions { + +MimeHandlerViewGuestDelegateQt::MimeHandlerViewGuestDelegateQt(MimeHandlerViewGuest *guest) + : MimeHandlerViewGuestDelegate() +{ +} + +MimeHandlerViewGuestDelegateQt::~MimeHandlerViewGuestDelegateQt() +{ +} + +bool MimeHandlerViewGuestDelegateQt::HandleContextMenu(content::WebContents *web_contents, const content::ContextMenuParams ¶ms) +{ + content::ContextMenuParams new_params = params; + + gfx::Point guest_coordinates = + static_cast<content::WebContentsImpl *>(web_contents)->GetBrowserPluginGuest()->GetScreenCoordinates(gfx::Point()); + + // Adjust (x,y) position for offset from guest to embedder. + new_params.x += guest_coordinates.x(); + new_params.y += guest_coordinates.y(); + + return false; +} + +} // namespace extensions diff --git a/src/core/extensions/mime_handler_view_guest_delegate_qt.h b/src/core/extensions/mime_handler_view_guest_delegate_qt.h new file mode 100644 index 000000000..b679c7a38 --- /dev/null +++ b/src/core/extensions/mime_handler_view_guest_delegate_qt.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Portions copyright 2015 The Chromium Embedded Framework Authors. +// Portions copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MIME_HANDLER_VIEW_GUEST_DELEGATE_QT_H_ +#define MIME_HANDLER_VIEW_GUEST_DELEGATE_QT_H_ + +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" +#include "content/browser/web_contents/web_contents_view.h" +#include "content/public/browser/web_contents.h" + +namespace content { +struct ContextMenuParams; +} + +namespace extensions { +class MimeHandlerViewGuest; + +class MimeHandlerViewGuestDelegateQt : public MimeHandlerViewGuestDelegate +{ +public: + explicit MimeHandlerViewGuestDelegateQt(MimeHandlerViewGuest *guest); + ~MimeHandlerViewGuestDelegateQt() override; + + bool HandleContextMenu(content::WebContents *web_contents, + const content::ContextMenuParams ¶ms) override; + +private: + MimeHandlerViewGuest *guest_; // Owns us. + + DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewGuestDelegateQt); +}; + +} // namespace extensions + +#endif // MIME_HANDLER_VIEW_GUEST_DELEGATE_QT_H_ diff --git a/src/core/extensions/pdf_web_contents_helper_client_qt.h b/src/core/extensions/pdf_web_contents_helper_client_qt.h new file mode 100644 index 000000000..a22feb138 --- /dev/null +++ b/src/core/extensions/pdf_web_contents_helper_client_qt.h @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ +#define PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ + +#include "base/macros.h" +#include "components/pdf/browser/pdf_web_contents_helper_client.h" + +namespace extensions { + +class PDFWebContentsHelperClientQt : public pdf::PDFWebContentsHelperClient { +public: + PDFWebContentsHelperClientQt(); + ~PDFWebContentsHelperClientQt() override; + +private: + // pdf::PDFWebContentsHelperClient: + void UpdateContentRestrictions(content::WebContents* contents, int content_restrictions) override; + void OnPDFHasUnsupportedFeature(content::WebContents* contents) override; + void OnSaveURL(content::WebContents* contents) override; + + DISALLOW_COPY_AND_ASSIGN(PDFWebContentsHelperClientQt); +}; + +} // namespace extensions + +#endif // PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp index 3ded5ec41..a495ce6f2 100644 --- a/src/core/file_picker_controller.cpp +++ b/src/core/file_picker_controller.cpp @@ -41,6 +41,7 @@ #include "type_conversion.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/file_select_listener.h" #include <QFileInfo> #include <QDir> @@ -49,18 +50,20 @@ namespace QtWebEngineCore { -FilePickerController::FilePickerController(FileChooserMode mode, content::RenderFrameHost *frameHost, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) +FilePickerController::FilePickerController(FileChooserMode mode, std::unique_ptr<content::FileSelectListener> listener, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) : QObject(parent) , m_defaultFileName(defaultFileName) , m_acceptedMimeTypes(acceptedMimeTypes) - , m_frameHost(frameHost) + , m_listener(std::move(listener)) , m_mode(mode) { } +FilePickerController::~FilePickerController() = default; + void FilePickerController::accepted(const QStringList &files) { - FilePickerController::filesSelectedInChooser(files, m_frameHost); + FilePickerController::filesSelectedInChooser(files); } void FilePickerController::accepted(const QVariant &files) @@ -77,12 +80,12 @@ void FilePickerController::accepted(const QVariant &files) qWarning("An unhandled type '%s' was provided in FilePickerController::accepted(QVariant)", files.typeName()); } - FilePickerController::filesSelectedInChooser(stringList, m_frameHost); + FilePickerController::filesSelectedInChooser(stringList); } void FilePickerController::rejected() { - FilePickerController::filesSelectedInChooser(QStringList(), m_frameHost); + FilePickerController::filesSelectedInChooser(QStringList()); } static QStringList listRecursively(const QDir &dir) @@ -99,19 +102,29 @@ static QStringList listRecursively(const QDir &dir) return ret; } -ASSERT_ENUMS_MATCH(FilePickerController::Open, content::FileChooserParams::Open) -ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParams::OpenMultiple) -ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) -ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) +ASSERT_ENUMS_MATCH(FilePickerController::Open, blink::mojom::FileChooserParams_Mode::kOpen) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, blink::mojom::FileChooserParams_Mode::kOpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, blink::mojom::FileChooserParams_Mode::kUploadFolder) +ASSERT_ENUMS_MATCH(FilePickerController::Save, blink::mojom::FileChooserParams_Mode::kSave) -void FilePickerController::filesSelectedInChooser(const QStringList &filesList, content::RenderFrameHost *frameHost) +void FilePickerController::filesSelectedInChooser(const QStringList &filesList) { - Q_ASSERT(frameHost); QStringList files(filesList); if (this->m_mode == UploadFolder && !filesList.isEmpty() && QFileInfo(filesList.first()).isDir()) // Enumerate the directory files = listRecursively(QDir(filesList.first())); - frameHost->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(this->m_mode)); + + std::vector<blink::mojom::FileChooserFileInfoPtr> chooser_files; + for (const auto &file : qAsConst(files)) { + chooser_files.push_back(blink::mojom::FileChooserFileInfo::NewNativeFile( + blink::mojom::NativeFileInfo::New(toFilePath(file), base::string16()))); + } + + if (files.isEmpty()) + m_listener->FileSelectionCanceled(); + else + m_listener->FileSelected(std::move(chooser_files), + static_cast<blink::mojom::FileChooserParams::Mode>(this->m_mode)); } QStringList FilePickerController::acceptedMimeTypes() const diff --git a/src/core/file_picker_controller.h b/src/core/file_picker_controller.h index 7507cf358..613d3ad9b 100644 --- a/src/core/file_picker_controller.h +++ b/src/core/file_picker_controller.h @@ -52,11 +52,14 @@ #define FILE_PICKER_CONTROLLER_H #include "qtwebenginecoreglobal_p.h" + +#include <memory> + #include <QObject> #include <QStringList> namespace content { - class RenderFrameHost; + class FileSelectListener; } namespace QtWebEngineCore { @@ -71,7 +74,8 @@ public: Save }; - FilePickerController(FileChooserMode mode, content::RenderFrameHost *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); + FilePickerController(FileChooserMode mode, std::unique_ptr<content::FileSelectListener> listener, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); + ~FilePickerController() override; QStringList acceptedMimeTypes() const; QString defaultFileName() const; FileChooserMode mode() const; @@ -82,10 +86,10 @@ public Q_SLOTS: void rejected(); private: - void filesSelectedInChooser(const QStringList &filesList, content::RenderFrameHost *contents); + void filesSelectedInChooser(const QStringList &filesList); QString m_defaultFileName; QStringList m_acceptedMimeTypes; - content::RenderFrameHost *m_frameHost; + std::unique_ptr<content::FileSelectListener> m_listener; FileChooserMode m_mode; }; diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index 9860c4541..0219a2be9 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -49,7 +49,7 @@ build_pass|!debug_and_release { ninjaflags = $$(NINJAFLAGS) isEmpty(ninjaflags):!silent: ninjaflags = "-v" - runninja.commands = $$NINJA $$ninjaflags -C $$gn_build_root QtWebEngineCore + runninja.commands = $$NINJA $$ninjaflags \$\(NINJAJOBS\) -C $$gn_build_root QtWebEngineCore QMAKE_EXTRA_TARGETS += runninja build_pass:build_all: default_target.target = all diff --git a/src/core/locked_ptr.h b/src/core/locked_ptr.h new file mode 100644 index 000000000..46d89819b --- /dev/null +++ b/src/core/locked_ptr.h @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef LOCKED_PTR_H +#define LOCKED_PTR_H + +#include <base/bind_internal.h> + +#include <QtCore/qreadwritelock.h> + +namespace base { + +struct LockedPtrCore +{ + LockedPtrCore(uintptr_t data) : data(data) {} + + std::atomic<size_t> refCount{1}; + // Atomic so that WeakLockedPtr::get can still read it. + std::atomic<uintptr_t> data; + QReadWriteLock lock{QReadWriteLock::Recursive}; +}; + +enum class LockedPtrMode { Weak, Shared, Exclusive }; + +template<class T, LockedPtrMode mode> class LockedPtr; + +// A WeakLockedPtr<T> is something like shared_ptr<T*>. The T* value can only be +// accessed by atomic read. +template<class T> using WeakLockedPtr = LockedPtr<T, LockedPtrMode::Weak>; + +// A SharedLockedPtr<T> is like WeakLockedPtr<T>, but the T* value is prevented +// from changing for the lifetime of the SharedLockedPtr by holding a +// shared-exclusive mutex in shared mode. +template<class T> using SharedLockedPtr = LockedPtr<T, LockedPtrMode::Shared>; + +// An ExclusiveLockedPtr<T> is like SharedLockedPtr<T>, but the mutex is held in +// exclusive mode. Only in this mode can the T* value be changed. +template<class T> using ExclusiveLockedPtr = LockedPtr<T, LockedPtrMode::Exclusive>; + +template<class T, LockedPtrMode mode> +class LockedPtr +{ + template<class T1> + static constexpr bool canConstructFrom = + std::is_same<T, T1>::value || + std::is_same<T, const T1>::value; + +public: + constexpr LockedPtr() {} + constexpr LockedPtr(std::nullptr_t) {} + + LockedPtr(const LockedPtr &that) + { + m_core = that.m_core; + lock(); + } + + LockedPtr &operator=(const LockedPtr &that) + { + unlock(); + m_core = that.m_core; + lock(); + } + + LockedPtr(LockedPtr &&that) + { + m_core = that.m_core; + that.m_core = nullptr; + } + + LockedPtr &operator=(LockedPtr &&that) + { + unlock(); + m_core = that.m_core; + that.m_core = nullptr; + } + + template<class T1, LockedPtrMode mode1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr(const LockedPtr<T1, mode1> &that) + { + m_core = that.m_core; + lock(); + } + + template<class T1, LockedPtrMode mode1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr &operator=(const LockedPtr<T1, mode1> &that) + { + unlock(); + m_core = that.m_core; + lock(); + } + + template<class T1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr(LockedPtr<T1, mode> &&that) + { + m_core = that.m_core; + that.m_core = nullptr; + } + + template<class T1, + class Enable = std::enable_if_t<canConstructFrom<T1>>> + LockedPtr &operator=(LockedPtr<T1, mode> &&that) + { + unlock(); + m_core = that.m_core; + that.m_core = nullptr; + } + + ~LockedPtr() + { + unlock(); + } + + T *get() const + { + if (m_core) { + if (mode == LockedPtrMode::Weak) + return reinterpret_cast<T *>(m_core->data.load(std::memory_order_acquire)); + else + return reinterpret_cast<T *>(m_core->data.load(std::memory_order_relaxed)); + } + return nullptr; + } + + void set(T *value) + { + static_assert(mode == LockedPtrMode::Exclusive, ""); + DCHECK(m_core); + m_core->data.store(reinterpret_cast<uintptr_t>(value), std::memory_order_release); + } + + T &operator*() const { return *get(); } + T *operator->() const { return get(); } + explicit operator bool() const { return get(); } + + bool MaybeValid() const { return m_core; } + + static LockedPtr create(T *value) + { + return new LockedPtrCore(reinterpret_cast<uintptr_t>(value)); + } + +private: + template<class T1, LockedPtrMode mode1> friend class LockedPtr; + + LockedPtr(LockedPtrCore *core) + : m_core(core) + {} + + void lock() + { + if (m_core) { + ++m_core->refCount; + + if (mode == LockedPtrMode::Shared) + m_core->lock.lockForRead(); + else if (mode == LockedPtrMode::Exclusive) + m_core->lock.lockForWrite(); + } + } + + void unlock() + { + if (m_core) { + if (mode != LockedPtrMode::Weak) + m_core->lock.unlock(); + + if (--m_core->refCount == 0) + delete m_core; + } + } + + LockedPtrCore *m_core = nullptr; +}; + +// This makes Bind check the pointer before calling the functor. +template<class T> +struct IsWeakReceiver<WeakLockedPtr<T>> : std::true_type {}; + +// By converting the WeakLockedPtr into a SharedLockedPtr we prevent the +// pointed-to object from being destroyed during the base::Callback::Run call. +// +// Unwrap() is called before checking the pointer, so there's no race condition. +template<class T> +struct BindUnwrapTraits<WeakLockedPtr<T>> +{ + static SharedLockedPtr<T> Unwrap(const WeakLockedPtr<T> &o) + { + return o; + } +}; + +// Like base::WeakPtrFactory, but InvalidateWeakPtrs *waits* until all currently +// executing base::Callbacks are finished. Queued up base::Callbacks are still +// canceled, exactly like with WeakPtrFactory. +// +// Consider, for example, the function +// +// void fun() +// { +// MyClass *myClass = new MyClass; +// myClass->scheduleDoStuff(); +// delete myClass; // ??? +// } +// +// where +// +// class MyClass +// { +// public: +// void scheduleDoStuff() +// { +// content::BrowserThread::PostTask( +// content::BrowserThread::IO, FROM_HERE, +// base::BindOnce(&MyClass::doStuff, m_weakPtrFactory.GetWeakPtr())); +// } +// void doStuff(); +// private: +// //base::WeakPtrFactory m_weakPtrFactory{this}; +// base::LockedPtrFactory m_weakPtrFactory{this}; +// }; +// +// What happens if the 'delete myClass' line is executed concurrently with +// MyClass::doStuff? +// +// With WeakPtrs we get a segfault or perhaps memory corruption. +// +// With LockedPtrs we get no crash and no corruption: LockedPtrFactory's +// destructor will wait until doStuff is done before continuing. +template<class T> +class LockedPtrFactory +{ +public: + explicit LockedPtrFactory(T *value) + : m_ptr(WeakLockedPtr<T>::create(value)) + {} + + ~LockedPtrFactory() + { + InvalidateWeakPtrs(); + } + + WeakLockedPtr<T> GetWeakPtr() { return m_ptr; } + WeakLockedPtr<const T> GetWeakPtr() const { return m_ptr; } + SharedLockedPtr<T> GetSharedPtr() { return m_ptr; } + SharedLockedPtr<const T> GetSharedPtr() const { return m_ptr; } + ExclusiveLockedPtr<T> GetExclusivePtr() { return m_ptr; } + ExclusiveLockedPtr<const T> GetExclusivePtr() const { return m_ptr; } + + void InvalidateWeakPtrs() + { + if (ExclusiveLockedPtr<T> ptr = m_ptr) + ptr.set(nullptr); + } + +private: + WeakLockedPtr<T> m_ptr; +}; + +} // namespace base + +#endif // !LOCKED_PTR_H diff --git a/src/core/login_delegate_qt.cpp b/src/core/login_delegate_qt.cpp index 9659b354a..0050f87c7 100644 --- a/src/core/login_delegate_qt.cpp +++ b/src/core/login_delegate_qt.cpp @@ -43,17 +43,32 @@ #include "login_delegate_qt.h" +#include "base/task/post_task.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/resource_request_info.h" +#include "content/public/browser/stream_info.h" +#include "extensions/buildflags/buildflags.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/info_map.h" +#include "extensions/common/extension.h" +#include "extensions/common/manifest_handlers/mime_types_handler.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + #include "net/url_request/url_request.h" #include "authentication_dialog_controller.h" #include "authentication_dialog_controller_p.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/extension_system_qt.h" +#endif // BUILDFLAG(ENABLE_EXTENSIONS) +#include "resource_context_qt.h" #include "type_conversion.h" #include "web_contents_view_qt.h" +#include "web_engine_context.h" namespace QtWebEngineCore { @@ -66,14 +81,9 @@ LoginDelegateQt::LoginDelegateQt( : m_authInfo(authInfo) , m_url(url) , m_auth_required_callback(std::move(auth_required_callback)) + , m_webContentsGetter(web_contents_getter) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&LoginDelegateQt::triggerDialog, - this, - web_contents_getter)); } LoginDelegateQt::~LoginDelegateQt() @@ -81,6 +91,13 @@ LoginDelegateQt::~LoginDelegateQt() Q_ASSERT(m_dialogController.isNull()); } +void LoginDelegateQt::triggerDialog() +{ + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&LoginDelegateQt::triggerDialogOnUI, this)); +} + void LoginDelegateQt::OnRequestCancelled() { destroy(); @@ -102,16 +119,34 @@ QString LoginDelegateQt::host() const return QString::fromStdString(m_authInfo->challenger.host()); } +int LoginDelegateQt::port() const +{ + return m_authInfo->challenger.port(); +} + bool LoginDelegateQt::isProxy() const { return m_authInfo->is_proxy; } -void LoginDelegateQt::triggerDialog(const content::ResourceRequestInfo::WebContentsGetter &webContentsGetter) +void LoginDelegateQt::triggerDialogOnUI() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + if (isProxy()) { + // workaround for 'ws' redefined symbols when including QNetworkProxy + auto authentication = WebEngineContext::qProxyNetworkAuthentication(host(), port()); + if (std::get<0>(authentication)) { + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::IO }, + base::BindOnce(&LoginDelegateQt::sendAuthToRequester, this, true, + std::get<1>(authentication), std::get<2>(authentication))); + + return; + } + } content::WebContentsImpl *webContents = - static_cast<content::WebContentsImpl *>(webContentsGetter.Run()); + static_cast<content::WebContentsImpl *>(m_webContentsGetter.Run()); if (!webContents) return; WebContentsAdapterClient *client = WebContentsViewQt::from(webContents->GetView())->client(); diff --git a/src/core/login_delegate_qt.h b/src/core/login_delegate_qt.h index 9ce5df843..3a9c073cd 100644 --- a/src/core/login_delegate_qt.h +++ b/src/core/login_delegate_qt.h @@ -66,24 +66,28 @@ public: ~LoginDelegateQt(); + void triggerDialog(); + // LoginDelegate implementation void OnRequestCancelled() override; QUrl url() const; QString realm() const; QString host() const; + int port() const; bool isProxy() const; void sendAuthToRequester(bool success, const QString &user, const QString &password); private: - void triggerDialog(const content::ResourceRequestInfo::WebContentsGetter &); + void triggerDialogOnUI(); void destroy(); scoped_refptr<net::AuthChallengeInfo> m_authInfo; GURL m_url; LoginAuthRequiredCallback m_auth_required_callback; + content::ResourceRequestInfo::WebContentsGetter m_webContentsGetter; // This member is used to keep authentication dialog controller alive until // authorization is sent or cancelled. diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index 2bac62084..a0b19cad3 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -49,10 +49,10 @@ #include "web_engine_settings.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/media/webrtc/desktop_streams_registry.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_media_id.h" +#include "content/public/browser/desktop_streams_registry.h" #include "content/public/browser/media_capture_devices.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" @@ -95,16 +95,16 @@ void getDevicesForDesktopCapture(content::MediaStreamDevices *devices, content:: DCHECK_CURRENTLY_ON(BrowserThread::UI); // Add selected desktop source to the list. - devices->push_back(content::MediaStreamDevice(content::MEDIA_DESKTOP_VIDEO_CAPTURE, mediaId.ToString(), "Screen")); + devices->push_back(content::MediaStreamDevice(content::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE, mediaId.ToString(), "Screen")); if (captureAudio) { if (mediaId.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) { devices->push_back( - content::MediaStreamDevice(content::MEDIA_DESKTOP_AUDIO_CAPTURE, + content::MediaStreamDevice(content::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, mediaId.ToString(), "Tab audio")); } else { // Use the special loopback device ID for system audio capture. devices->push_back(content::MediaStreamDevice( - content::MEDIA_DESKTOP_AUDIO_CAPTURE, + content::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, media::AudioDeviceDescription::kLoopbackInputDeviceId, "System Audio")); } @@ -157,12 +157,12 @@ WebContentsAdapterClient::MediaRequestFlags mediaRequestFlagsForRequest(const co if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaAudioCapture; - else if (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) + else if (request.audio_type == content::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaDesktopAudioCapture; if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaVideoCapture; - else if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) + else if (request.video_type == content::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE) requestFlags |= WebContentsAdapterClient::MediaDesktopVideoCapture; return requestFlags; @@ -233,8 +233,9 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content: // Post a task to process next queued request. It has to be done // asynchronously to make sure that calling infobar is not destroyed until // after this function returns. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, base::BindOnce(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, base::Unretained(this), webContents)); + base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest, + base::Unretained(this), webContents)); } std::move(callback).Run(devices, devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE : content::MEDIA_DEVICE_OK, @@ -275,12 +276,12 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(WebContentsAdapter DCHECK_CURRENTLY_ON(BrowserThread::UI); // Let's not support tab capture for now. - if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE || request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) { + if (request.video_type == content::MEDIA_GUM_TAB_VIDEO_CAPTURE || request.audio_type == content::MEDIA_GUM_TAB_AUDIO_CAPTURE) { std::move(callback).Run(content::MediaStreamDevices(), content::MEDIA_DEVICE_NOT_SUPPORTED, std::unique_ptr<content::MediaStreamUI>()); return; } - if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE || request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) { + if (request.video_type == content::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE || request.audio_type == content::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) { const bool screenCaptureEnabled = adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::ScreenCaptureEnabled); const bool originIsSecure = content::IsOriginSecure(request.security_origin); @@ -305,7 +306,7 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content:: { content::MediaStreamDevices devices; - if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE || request.requested_video_device_id.empty()) { + if (request.video_type != content::MEDIA_GUM_DESKTOP_VIDEO_CAPTURE || request.requested_video_device_id.empty()) { std::move(callback).Run(devices, content::MEDIA_DEVICE_INVALID_STATE, std::unique_ptr<content::MediaStreamUI>()); return; } @@ -319,10 +320,10 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content:: // The extension name that the stream is registered with. std::string originalExtensionName; // Resolve DesktopMediaID for the specified device id. - mediaId = getDesktopStreamsRegistry()->RequestMediaForStreamId( + mediaId = content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId( request.requested_video_device_id, main_frame->GetProcess()->GetID(), main_frame->GetRoutingID(), request.security_origin, - &originalExtensionName); + &originalExtensionName, content::kRegistryStreamTypeDesktop); } // Received invalid device id. @@ -332,7 +333,7 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content:: } // Audio is only supported for screen capture streams. - bool capture_audio = (mediaId.type == content::DesktopMediaID::TYPE_SCREEN && request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE); + bool capture_audio = (mediaId.type == content::DesktopMediaID::TYPE_SCREEN && request.audio_type == content::MEDIA_GUM_DESKTOP_AUDIO_CAPTURE); getDevicesForDesktopCapture(&devices, mediaId, capture_audio); @@ -390,22 +391,13 @@ void MediaCaptureDevicesDispatcher::getDefaultDevices(const std::string &audioDe } } -DesktopStreamsRegistry *MediaCaptureDevicesDispatcher::getDesktopStreamsRegistry() -{ - if (!m_desktopStreamsRegistry) - m_desktopStreamsRegistry.reset(new DesktopStreamsRegistry()); - return m_desktopStreamsRegistry.get(); -} - void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(int render_process_id, int render_frame_id, int page_request_id, const GURL &security_origin, content::MediaStreamType stream_type, content::MediaRequestState state) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind( - &MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread, - base::Unretained(this), render_process_id, render_frame_id, - page_request_id, security_origin, stream_type, state)); + base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread, + base::Unretained(this), render_process_id, render_frame_id, + page_request_id, security_origin, stream_type, state)); } void MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread(int render_process_id, diff --git a/src/core/media_capture_devices_dispatcher.h b/src/core/media_capture_devices_dispatcher.h index 0e5aa38be..cc6e60ede 100644 --- a/src/core/media_capture_devices_dispatcher.h +++ b/src/core/media_capture_devices_dispatcher.h @@ -57,8 +57,6 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/common/media_stream_request.h" -class DesktopStreamsRegistry; - namespace QtWebEngineCore { // This singleton is used to receive updates about media events from the content @@ -94,8 +92,6 @@ private: content::MediaStreamType /*stream_type*/, bool /*is_secure*/) override {} - DesktopStreamsRegistry *getDesktopStreamsRegistry(); - friend struct base::DefaultSingletonTraits<MediaCaptureDevicesDispatcher>; typedef base::RepeatingCallback<void(const content::MediaStreamDevices &devices, @@ -129,8 +125,6 @@ private: RequestsQueues m_pendingRequests; - std::unique_ptr<DesktopStreamsRegistry> m_desktopStreamsRegistry; - content::NotificationRegistrar m_notificationsRegistrar; DISALLOW_COPY_AND_ASSIGN(MediaCaptureDevicesDispatcher); diff --git a/src/core/net/client_cert_override.cpp b/src/core/net/client_cert_override.cpp new file mode 100644 index 000000000..305f0cef0 --- /dev/null +++ b/src/core/net/client_cert_override.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** 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 "client_cert_override.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/task/post_task.h" +#include "base/callback_forward.h" +#include "content/public/browser/browser_task_traits.h" +#include "net/ssl/client_cert_store.h" +#include "net/ssl/ssl_cert_request_info.h" +#include "net/ssl/ssl_private_key.h" +#include "net/cert/x509_certificate.h" +#include "third_party/boringssl/src/include/openssl/pem.h" +#include "third_party/boringssl/src/include/openssl/err.h" +#include "third_party/boringssl/src/include/openssl/evp.h" + +#include "client_cert_store_data.h" +#include "profile_io_data_qt.h" + +#include <QtNetwork/qtnetworkglobal.h> + +#if defined(USE_NSS_CERTS) +#include "net/ssl/client_cert_store_nss.h" +#endif + +#if defined(OS_WIN) +#include "net/ssl/client_cert_store_win.h" +#endif + +#if defined(OS_MACOSX) +#include "net/ssl/client_cert_store_mac.h" +#endif + +namespace { + +class ClientCertIdentityOverride : public net::ClientCertIdentity +{ +public: + ClientCertIdentityOverride(scoped_refptr<net::X509Certificate> cert, scoped_refptr<net::SSLPrivateKey> key) + : net::ClientCertIdentity(std::move(cert)), m_key(std::move(key)) {} + ~ClientCertIdentityOverride() override = default; + + void AcquirePrivateKey(const base::Callback<void(scoped_refptr<net::SSLPrivateKey>)> &private_key_callback) override + { + private_key_callback.Run(m_key); + } + +#if defined(OS_MACOSX) + SecIdentityRef sec_identity_ref() const override + { + return nullptr; + } +#endif + +private: + scoped_refptr<net::SSLPrivateKey> m_key; +}; + +} // namespace + +namespace QtWebEngineCore { + +ClientCertOverrideStore::ClientCertOverrideStore(ClientCertificateStoreData *storeData) + : ClientCertStore() + , m_storeData(storeData) + , m_nativeStore(createNativeStore()) +{ +} + +ClientCertOverrideStore::~ClientCertOverrideStore() = default; + +#if QT_CONFIG(ssl) +net::ClientCertIdentityList ClientCertOverrideStore::GetClientCertsOnUIThread(const net::SSLCertRequestInfo &cert_request_info) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + const auto &clientCertOverrideData = m_storeData->extraCerts; + // Look for certificates in memory store + for (int i = 0; i < clientCertOverrideData.length(); i++) { + scoped_refptr<net::X509Certificate> cert = clientCertOverrideData[i]->certPtr; + if (cert != NULL && cert->IsIssuedByEncoded(cert_request_info.cert_authorities)) { + net::ClientCertIdentityList selected_identities; + selected_identities.push_back(std::make_unique<ClientCertIdentityOverride>(cert, clientCertOverrideData[i]->keyPtr)); + return selected_identities; + } + } + return net::ClientCertIdentityList(); +} + +void ClientCertOverrideStore::GetClientCertsReturn(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback, + net::ClientCertIdentityList &&result) +{ + // Continue with native cert store if matching certificatse were not found in memory + if (result.empty() && m_nativeStore) + m_nativeStore->GetClientCerts(cert_request_info, callback); + else + callback.Run(std::move(result)); +} + +#endif // QT_CONFIG(ssl) + +void ClientCertOverrideStore::GetClientCerts(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback) +{ +#if QT_CONFIG(ssl) + // Access the user-provided data from the UI thread, but return on whatever thread this is. + if (base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&ClientCertOverrideStore::GetClientCertsOnUIThread, + base::Unretained(this), base::ConstRef(cert_request_info)), + base::BindOnce(&ClientCertOverrideStore::GetClientCertsReturn, + base::Unretained(this), base::ConstRef(cert_request_info), callback)) + ) { + return; + } +#endif // QT_CONFIG(ssl) + + // Continue with native cert store if we failed to post task + if (m_nativeStore) + m_nativeStore->GetClientCerts(cert_request_info, callback); + else + callback.Run(net::ClientCertIdentityList()); +} + +// static +std::unique_ptr<net::ClientCertStore> ClientCertOverrideStore::createNativeStore() +{ +#if defined(USE_NSS_CERTS) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(net::ClientCertStoreNSS::PasswordDelegateFactory())); +#elif defined(OS_WIN) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin()); +#elif defined(OS_MACOSX) + return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac()); +#else + return nullptr; +#endif +} +} // namespace QtWebEngineCore diff --git a/src/core/net/client_cert_override.h b/src/core/net/client_cert_override.h new file mode 100644 index 000000000..35c1f96af --- /dev/null +++ b/src/core/net/client_cert_override.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef CLIENT_CERT_OVERRIDE_P_H +#define CLIENT_CERT_OVERRIDE_P_H + +#include "net/ssl/client_cert_store.h" +#include "base/callback_forward.h" +#include "net/cert/x509_certificate.h" + +namespace net { +class SSLCertRequestInfo; +} // namespace net + +namespace QtWebEngineCore { +struct ClientCertificateStoreData; + +class ClientCertOverrideStore : public net::ClientCertStore +{ +public: + ClientCertOverrideStore(ClientCertificateStoreData *storeData); + virtual ~ClientCertOverrideStore() override; + void GetClientCerts(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback) override; +private: + static std::unique_ptr<net::ClientCertStore> createNativeStore(); + net::ClientCertIdentityList GetClientCertsOnUIThread(const net::SSLCertRequestInfo &request); + void GetClientCertsReturn(const net::SSLCertRequestInfo &cert_request_info, + const ClientCertListCallback &callback, + net::ClientCertIdentityList &&result); + ClientCertificateStoreData *m_storeData; + std::unique_ptr<net::ClientCertStore> m_nativeStore; +}; + +} // QtWebEngineCore + +#endif + + diff --git a/src/core/net/client_cert_store_data.cpp b/src/core/net/client_cert_store_data.cpp new file mode 100644 index 000000000..d1018a063 --- /dev/null +++ b/src/core/net/client_cert_store_data.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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 "net/client_cert_store_data.h" + +#if QT_CONFIG(ssl) +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "net/base/net_errors.h" +#include "net/cert/x509_certificate.h" +#include "net/ssl/ssl_platform_key_util.h" +#include "net/ssl/ssl_private_key.h" +#include "net/ssl/threaded_ssl_private_key.h" + +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" +#include "third_party/boringssl/src/include/openssl/pem.h" + +#include "QtCore/qbytearray.h" + +namespace { + +class SSLPlatformKeyOverride : public net::ThreadedSSLPrivateKey::Delegate { +public: + SSLPlatformKeyOverride(const QByteArray &sslKeyInBytes) + { + m_mem = BIO_new_mem_buf(sslKeyInBytes, -1); + m_key = PEM_read_bio_PrivateKey(m_mem, nullptr, nullptr, nullptr); + } + + ~SSLPlatformKeyOverride() override + { + if (m_key) + EVP_PKEY_free(m_key); + if (m_mem) + BIO_free(m_mem); + } + + net::Error Sign(uint16_t algorithm, base::span<const uint8_t> input, std::vector<uint8_t> *signature) override + { + bssl::ScopedEVP_MD_CTX ctx; + EVP_PKEY_CTX *pctx; + if (!EVP_DigestSignInit(ctx.get(), &pctx, + SSL_get_signature_algorithm_digest(algorithm), + nullptr, m_key)) { + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + } + + if (SSL_is_signature_algorithm_rsa_pss(algorithm)) { + if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* hash length */)) { + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + } + } + size_t sig_len = 0; + if (!EVP_DigestSign(ctx.get(), NULL, &sig_len, input.data(), input.size())) + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + signature->resize(sig_len); + if (!EVP_DigestSign(ctx.get(), signature->data(), &sig_len, input.data(), input.size())) + return net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; + signature->resize(sig_len); + return net::OK; + } + + std::vector<uint16_t> GetAlgorithmPreferences() override + { + return { SSL_SIGN_RSA_PKCS1_SHA1, SSL_SIGN_RSA_PKCS1_SHA512 + , SSL_SIGN_RSA_PKCS1_SHA384, SSL_SIGN_RSA_PKCS1_SHA256 }; + } + +private: + EVP_PKEY *m_key; + BIO *m_mem; + + DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyOverride); +}; + +scoped_refptr<net::SSLPrivateKey> wrapOpenSSLPrivateKey(const QByteArray &sslKeyInBytes) +{ + if (sslKeyInBytes.isEmpty()) + return nullptr; + + return base::MakeRefCounted<net::ThreadedSSLPrivateKey>( + std::make_unique<SSLPlatformKeyOverride>(sslKeyInBytes), + net::GetSSLPlatformKeyTaskRunner()); +} + +} // namespace + +namespace QtWebEngineCore { + +void ClientCertificateStoreData::add(const QSslCertificate &certificate, const QSslKey &privateKey) +{ + QByteArray sslKeyInBytes = privateKey.toPem(); + QByteArray certInBytes = certificate.toDer(); + + Entry *data = new Entry; + data->keyPtr = wrapOpenSSLPrivateKey(sslKeyInBytes); + data->certPtr = net::X509Certificate::CreateFromBytes(certInBytes.data(), certInBytes.length()); + data->key = privateKey; + data->certificate = certificate; + extraCerts.append(data); +} + +void ClientCertificateStoreData::remove(const QSslCertificate &certificate) +{ + auto it = extraCerts.begin(); + while (it != extraCerts.end()) { + const QtWebEngineCore::ClientCertificateStoreData::Entry *overrideData = *it; + if (certificate.toDer() == overrideData->certificate.toDer()) { + it = extraCerts.erase(it); + delete overrideData; + continue; + } + ++it; + } +} + +void ClientCertificateStoreData::clear() +{ + qDeleteAll(extraCerts); + extraCerts.clear(); +} + +} // namespace QtWebEngineCore + +#endif diff --git a/src/core/net/client_cert_store_data.h b/src/core/net/client_cert_store_data.h new file mode 100644 index 000000000..7f83f4b60 --- /dev/null +++ b/src/core/net/client_cert_store_data.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef CLIENT_CERT_STORE_DATA_H +#define CLIENT_CERT_STORE_DATA_H + +#include "qtwebenginecoreglobal.h" +#include "qtnetworkglobal.h" + +#if QT_CONFIG(ssl) +#include "base/memory/ref_counted.h" + +#include <QtCore/qvector.h> +#include <QtNetwork/qsslcertificate.h> +#include <QtNetwork/qsslkey.h> + +namespace net { +class SSLPrivateKey; +class X509Certificate; +} + +namespace QtWebEngineCore { + +struct ClientCertificateStoreData { + struct Entry { + QSslKey key; + QSslCertificate certificate; + scoped_refptr<net::X509Certificate> certPtr; + scoped_refptr<net::SSLPrivateKey> keyPtr; + }; + + void add(const QSslCertificate &certificate, const QSslKey &privateKey); + void remove(const QSslCertificate &certificate); + void clear(); + + QVector<Entry*> extraCerts; +}; + +} // namespace QtWebEngineCore + +#endif +#endif // CLIENT_CERT_STORE_DATA_H diff --git a/src/core/net/cookie_monster_delegate_qt.cpp b/src/core/net/cookie_monster_delegate_qt.cpp index bb89e9e5f..3253b08b9 100644 --- a/src/core/net/cookie_monster_delegate_qt.cpp +++ b/src/core/net/cookie_monster_delegate_qt.cpp @@ -41,6 +41,8 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "net/cookies/cookie_util.h" @@ -87,8 +89,8 @@ void CookieMonsterDelegateQt::getAllCookies(quint64 callbackId) net::CookieMonster::GetCookieListCallback callback = base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread, this, callbackId); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesOnIOThread, this, std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesOnIOThread, this, std::move(callback))); } void CookieMonsterDelegateQt::GetAllCookiesOnIOThread(net::CookieMonster::GetCookieListCallback callback) @@ -108,9 +110,9 @@ void CookieMonsterDelegateQt::setCookie(quint64 callbackId, const QNetworkCookie GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::SetCookieOnIOThread, this, - gurl, cookie.toRawForm().toStdString(), std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::SetCookieOnIOThread, this, + gurl, cookie.toRawForm().toStdString(), std::move(callback))); } void CookieMonsterDelegateQt::SetCookieOnIOThread( @@ -131,9 +133,9 @@ void CookieMonsterDelegateQt::deleteCookie(const QNetworkCookie &cookie, const Q GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteCookieOnIOThread, this, - gurl, cookie.name().toStdString())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteCookieOnIOThread, this, + gurl, cookie.name().toStdString())); } void CookieMonsterDelegateQt::DeleteCookieOnIOThread(const GURL& url, const std::string& cookie_name) @@ -149,8 +151,8 @@ void CookieMonsterDelegateQt::deleteSessionCookies(quint64 callbackId) net::CookieMonster::DeleteCallback callback = base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread, this, callbackId); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread, this, std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread, this, std::move(callback))); } void CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread(net::CookieMonster::DeleteCallback callback) @@ -166,8 +168,8 @@ void CookieMonsterDelegateQt::deleteAllCookies(quint64 callbackId) net::CookieMonster::DeleteCallback callback = base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread, this, callbackId); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteAllOnIOThread, this, std::move(callback))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteAllOnIOThread, this, std::move(callback))); } void CookieMonsterDelegateQt::DeleteAllOnIOThread(net::CookieMonster::DeleteCallback callback) @@ -238,26 +240,23 @@ void CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread(qint64 callbackId, for (auto &&cookie : cookies) rawCookies += toQt(cookie).toRawForm() % QByteArrayLiteral("\n"); - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId, rawCookies)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId, rawCookies)); } void CookieMonsterDelegateQt::SetCookieCallbackOnIOThread(qint64 callbackId, bool success) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, success)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, success)); } void CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread(qint64 callbackId, uint numCookies) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId, numCookies)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId, numCookies)); } void CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread(qint64 callbackId, const QByteArray &cookies) diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp index 37309931e..3641cb845 100644 --- a/src/core/net/network_delegate_qt.cpp +++ b/src/core/net/network_delegate_qt.cpp @@ -39,22 +39,26 @@ #include "network_delegate_qt.h" -#include "profile_adapter.h" +#include "base/task/post_task.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_request_info.h" -#include "cookie_monster_delegate_qt.h" -#include "ui/base/page_transition_types.h" -#include "profile_io_data_qt.h" #include "net/base/load_flags.h" #include "net/url_request/url_request.h" +#include "ui/base/page_transition_types.h" + +#include "profile_adapter.h" +#include "cookie_monster_delegate_qt.h" +#include "profile_io_data_qt.h" #include "qwebengineurlrequestinfo.h" #include "qwebengineurlrequestinfo_p.h" #include "qwebengineurlrequestinterceptor.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" #include "web_contents_view_qt.h" +#include "url_request_notification.h" namespace QtWebEngineCore { @@ -81,128 +85,18 @@ WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::Page } } -namespace { - -QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType) +static QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType) { if (resourceType >= 0 && resourceType < content::ResourceType(QWebEngineUrlRequestInfo::ResourceTypeLast)) return static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType); return QWebEngineUrlRequestInfo::ResourceTypeUnknown; } -QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType) +static QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType) { return static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType); } -// Notifies WebContentsAdapterClient of a new URLRequest. -class URLRequestNotification { -public: - URLRequestNotification(net::URLRequest *request, - const QUrl &url, - bool isMainFrameRequest, - int navigationType, - int frameTreeNodeId, - net::CompletionOnceCallback callback) - : m_request(request) - , m_url(url) - , m_isMainFrameRequest(isMainFrameRequest) - , m_navigationType(navigationType) - , m_frameTreeNodeId(frameTreeNodeId) - , m_callback(std::move(callback)) - { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - m_request->SetUserData(UserData::key, std::make_unique<UserData>(this)); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&URLRequestNotification::notify, base::Unretained(this))); - } - -private: - // Calls cancel() when the URLRequest is destroyed. - class UserData : public base::SupportsUserData::Data { - public: - UserData(URLRequestNotification *ptr) : m_ptr(ptr) {} - ~UserData() { m_ptr->cancel(); } - static const char key[]; - private: - URLRequestNotification *m_ptr; - }; - - void cancel() - { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - // May run concurrently with notify() but we only touch m_request here. - - m_request = nullptr; - } - - void notify() - { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - // May run concurrently with cancel() so no peeking at m_request here. - - int error = net::OK; - content::WebContents *webContents = content::WebContents::FromFrameTreeNodeId(m_frameTreeNodeId); - if (webContents) { - int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; - WebContentsAdapterClient *client = - WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client(); - client->navigationRequested(m_navigationType, - m_url, - navigationRequestAction, - m_isMainFrameRequest); - error = net::ERR_FAILED; - switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) { - case WebContentsAdapterClient::AcceptRequest: - error = net::OK; - break; - case WebContentsAdapterClient::IgnoreRequest: - error = net::ERR_ABORTED; - break; - } - DCHECK(error != net::ERR_FAILED); - } - - // Run the callback on the IO thread. - content::BrowserThread::PostTask( - content::BrowserThread::IO, - FROM_HERE, - base::BindOnce(&URLRequestNotification::complete, base::Unretained(this), error)); - } - - void complete(int error) - { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - if (m_request) { - if (m_request->status().status() != net::URLRequestStatus::CANCELED) - std::move(m_callback).Run(error); - m_request->RemoveUserData(UserData::key); - } - - delete this; - } - - ~URLRequestNotification() {} - - net::URLRequest *m_request; - QUrl m_url; - bool m_isMainFrameRequest; - int m_navigationType; - int m_frameTreeNodeId; - net::CompletionOnceCallback m_callback; -}; - -const char URLRequestNotification::UserData::key[] = "QtWebEngineCore::URLRequestNotification"; - -} // namespace - NetworkDelegateQt::NetworkDelegateQt(ProfileIODataQt *data) : m_profileIOData(data) { @@ -212,7 +106,6 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_profileIOData); - const content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request); content::ResourceType resourceType = content::RESOURCE_TYPE_LAST_TYPE; @@ -231,49 +124,59 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet else firstPartyUrl = toQt(request->site_for_cookies()); - QWebEngineUrlRequestInterceptor* interceptor = m_profileIOData->acquireInterceptor(); - if (interceptor) { - QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), - toQt(navigationType), - qUrl, - firstPartyUrl, - QByteArray::fromStdString(request->method())); - QWebEngineUrlRequestInfo requestInfo(infoPrivate); - interceptor->interceptRequest(requestInfo); - m_profileIOData->releaseInterceptor(); - if (requestInfo.changed()) { - int result = infoPrivate->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; - - if (qUrl != infoPrivate->url) - *newUrl = toGurl(infoPrivate->url); - - if (!infoPrivate->extraHeaders.isEmpty()) { - auto end = infoPrivate->extraHeaders.constEnd(); - for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) - request->SetExtraRequestHeaderByName(header.key().toStdString(), header.value().toStdString(), /* overwrite */ true); + QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), + toQt(navigationType), + qUrl, + firstPartyUrl, + QByteArray::fromStdString(request->method())); + QWebEngineUrlRequestInfo requestInfo(infoPrivate); + + // Deprecated =begin + // quick peek if deprecated + QWebEngineUrlRequestInterceptor* profileInterceptor = m_profileIOData->requestInterceptor(); + if (profileInterceptor && profileInterceptor->property("deprecated").toBool()) { + profileInterceptor = nullptr; + if (QWebEngineUrlRequestInterceptor* interceptor = m_profileIOData->acquireInterceptor()) { + interceptor->interceptRequest(requestInfo); + m_profileIOData->releaseInterceptor(); + if (requestInfo.changed()) { + int result = infoPrivate->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; + + if (qUrl != infoPrivate->url) + *newUrl = toGurl(infoPrivate->url); + + if (!infoPrivate->extraHeaders.isEmpty()) { + auto end = infoPrivate->extraHeaders.constEnd(); + for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) + request->SetExtraRequestHeaderByName(header.key().toStdString(), header.value().toStdString(), /* overwrite */ true); + } + + if (result != net::OK) + return result; + + requestInfo.resetChanged(); } - - if (result != net::OK) - return result; + } else { + m_profileIOData->releaseInterceptor(); } - } else - m_profileIOData->releaseInterceptor(); + } + // Deprecated =cut if (!resourceInfo) return net::OK; - int frameTreeNodeId = resourceInfo->GetFrameTreeNodeId(); - // Only intercept MAIN_FRAME and SUB_FRAME with an associated render frame. - if (!content::IsResourceTypeFrame(resourceType) || frameTreeNodeId == -1) + if (!m_profileIOData->hasPageInterceptors() && !profileInterceptor && !content::IsResourceTypeFrame(resourceType)) return net::OK; + auto webContentsGetter = resourceInfo->GetWebContentsGetterForRequest(); new URLRequestNotification( request, - qUrl, resourceInfo->IsMainFrame(), - navigationType, - frameTreeNodeId, - std::move(callback) + newUrl, + std::move(requestInfo), + webContentsGetter, + std::move(callback), + profileInterceptor ? m_profileIOData->profileAdapter() : nullptr ); // We'll run the callback after we notified the UI thread. @@ -290,13 +193,18 @@ void NetworkDelegateQt::OnCompleted(net::URLRequest */*request*/, bool /*started bool NetworkDelegateQt::OnCanSetCookie(const net::URLRequest& request, const net::CanonicalCookie & /*cookie*/, - net::CookieOptions*) + net::CookieOptions*, + bool allowedFromCaller) { + if (!allowedFromCaller) + return false; return canSetCookies(request.site_for_cookies(), request.url(), std::string()); } -bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest& request, const net::CookieList&) +bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest& request, const net::CookieList&, bool allowedFromCaller) { + if (!allowedFromCaller) + return false; return canGetCookies(request.site_for_cookies(), request.url()); } diff --git a/src/core/net/network_delegate_qt.h b/src/core/net/network_delegate_qt.h index e4ff196aa..842af5006 100644 --- a/src/core/net/network_delegate_qt.h +++ b/src/core/net/network_delegate_qt.h @@ -62,7 +62,7 @@ public: // net::NetworkDelegate implementation int OnBeforeURLRequest(net::URLRequest* request, net::CompletionOnceCallback callback, GURL* new_url) override; void OnURLRequestDestroyed(net::URLRequest* request) override; - bool OnCanSetCookie(const net::URLRequest& request, const net::CanonicalCookie& cookie, net::CookieOptions* options) override; + bool OnCanSetCookie(const net::URLRequest& request, const net::CanonicalCookie& cookie, net::CookieOptions* options, bool) override; int OnBeforeStartTransaction(net::URLRequest *request, const net::CompletionOnceCallback callback, net::HttpRequestHeaders *headers) override; void OnBeforeSendHeaders(net::URLRequest* request, const net::ProxyInfo& proxy_info, const net::ProxyRetryInfoMap& proxy_retry_info, net::HttpRequestHeaders* headers) override; @@ -75,7 +75,7 @@ public: void OnCompleted(net::URLRequest *request, bool started, int net_error) override; void OnPACScriptError(int, const base::string16&) override; net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(net::URLRequest*, const net::AuthChallengeInfo&, AuthCallback, net::AuthCredentials*) override; - bool OnCanGetCookies(const net::URLRequest&, const net::CookieList&) override; + bool OnCanGetCookies(const net::URLRequest&, const net::CookieList&, bool) override; bool OnCanAccessFile(const net::URLRequest&, const base::FilePath&, const base::FilePath&) const override; bool OnCanEnablePrivacyMode(const GURL&, const GURL&) const override; bool OnAreExperimentalCookieFeaturesEnabled() const override; diff --git a/src/core/net/proxy_config_service_qt.cpp b/src/core/net/proxy_config_service_qt.cpp index 13b969281..ff8ab20aa 100644 --- a/src/core/net/proxy_config_service_qt.cpp +++ b/src/core/net/proxy_config_service_qt.cpp @@ -47,6 +47,7 @@ #include "base/bind.h" #include "content/public/browser/browser_thread.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" using content::BrowserThread; @@ -68,10 +69,13 @@ net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qt } } -ProxyConfigServiceQt::ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService) +ProxyConfigServiceQt::ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService, + const net::ProxyConfigWithAnnotation& initialConfig, ProxyPrefs::ConfigState initialState) : m_baseService(baseService.release()), m_usesSystemConfiguration(false), - m_registeredObserver(false) + m_registeredObserver(false), + m_prefConfig(initialConfig), + m_perfState(initialState) { } @@ -100,8 +104,10 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxy ConfigAvailability systemAvailability = net::ProxyConfigService::CONFIG_UNSET; if (m_baseService.get()) systemAvailability = m_baseService->GetLatestProxyConfig(&systemConfig); - *config = systemConfig; - // make sure to get updates via OnProxyConfigChanged + ProxyPrefs::ConfigState configState; + systemAvailability = PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig( + m_perfState, m_prefConfig, systemAvailability, systemConfig, + false, &configState, config); RegisterObserver(); return systemAvailability; } diff --git a/src/core/net/proxy_config_service_qt.h b/src/core/net/proxy_config_service_qt.h index dcd303894..09e88d445 100644 --- a/src/core/net/proxy_config_service_qt.h +++ b/src/core/net/proxy_config_service_qt.h @@ -43,8 +43,10 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" +#include "net/proxy_resolution/proxy_config.h" #include "net/proxy_resolution/proxy_config_service.h" #include "net/proxy_resolution/proxy_config_with_annotation.h" +#include "components/proxy_config/proxy_prefs.h" #include <QNetworkProxy> @@ -55,7 +57,9 @@ public: static net::ProxyServer fromQNetworkProxy(const QNetworkProxy &); - explicit ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService); + explicit ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService, + const net::ProxyConfigWithAnnotation& initialConfig, + ProxyPrefs::ConfigState initialState); ~ProxyConfigServiceQt() override; // ProxyConfigService implementation: @@ -76,7 +80,7 @@ private: void RegisterObserver(); std::unique_ptr<net::ProxyConfigService> m_baseService; - base::ObserverList<net::ProxyConfigService::Observer, true> m_observers; + base::ObserverList<net::ProxyConfigService::Observer, true>::Unchecked m_observers; // Keep the last state around. bool m_usesSystemConfiguration; @@ -86,6 +90,10 @@ private: // Indicates whether the base service registration is done. bool m_registeredObserver; + // Configuration as defined by prefs. + net::ProxyConfigWithAnnotation m_prefConfig; + ProxyPrefs::ConfigState m_perfState; + DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceQt); }; diff --git a/src/core/net/qrc_url_scheme_handler.cpp b/src/core/net/qrc_url_scheme_handler.cpp new file mode 100644 index 000000000..74a77a7ec --- /dev/null +++ b/src/core/net/qrc_url_scheme_handler.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 "qrc_url_scheme_handler.h" + +#include <QtWebEngineCore/qwebengineurlrequestjob.h> + +#include <QFile> +#include <QFileInfo> +#include <QMimeDatabase> +#include <QMimeType> + +namespace QtWebEngineCore { + +void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job) +{ + QByteArray requestMethod = job->requestMethod(); + if (requestMethod != "GET") { + job->fail(QWebEngineUrlRequestJob::RequestDenied); + return; + } + + QUrl requestUrl = job->requestUrl(); + QString requestPath = requestUrl.path(); + QScopedPointer<QFile> file(new QFile(':' + requestPath, job)); + QFileInfo fileInfo(*file); + QMimeDatabase mimeDatabase; + QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileInfo); + job->reply(mimeType.name().toUtf8(), file.take()); +} + +} // namespace QtWebEngineCore diff --git a/src/core/net/qrc_url_scheme_handler.h b/src/core/net/qrc_url_scheme_handler.h new file mode 100644 index 000000000..f6ca92879 --- /dev/null +++ b/src/core/net/qrc_url_scheme_handler.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QRC_URL_SCHEME_HANDLER_H +#define QRC_URL_SCHEME_HANDLER_H + +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> +#include <QtWebEngineCore/qwebengineurlschemehandler.h> + +namespace QtWebEngineCore { + +class QrcUrlSchemeHandler final : public QWebEngineUrlSchemeHandler { +public: + void requestStarted(QWebEngineUrlRequestJob *) override; +}; + +} // namespace QtWebEngineCore + +#endif // !QRC_URL_SCHEME_HANDLER_H diff --git a/src/core/net/url_request_context_getter_qt.cpp b/src/core/net/url_request_context_getter_qt.cpp index 636d27358..6081a5e9f 100644 --- a/src/core/net/url_request_context_getter_qt.cpp +++ b/src/core/net/url_request_context_getter_qt.cpp @@ -40,6 +40,10 @@ #include "url_request_context_getter_qt.h" #include "profile_io_data_qt.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" + namespace QtWebEngineCore { URLRequestContextGetterQt::URLRequestContextGetterQt(ProfileIODataQt *data) @@ -59,7 +63,7 @@ net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetterQt::GetNetworkTaskRunner() const { - return content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO); + return base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO}); } } // namespace QtWebEngineCore diff --git a/src/core/net/url_request_custom_job.cpp b/src/core/net/url_request_custom_job.cpp index d371c7bff..cba9b4dc5 100644 --- a/src/core/net/url_request_custom_job.cpp +++ b/src/core/net/url_request_custom_job.cpp @@ -39,6 +39,9 @@ #include "url_request_custom_job.h" #include "url_request_custom_job_proxy.h" + +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "net/base/io_buffer.h" @@ -68,17 +71,30 @@ URLRequestCustomJob::~URLRequestCustomJob() if (m_device && m_device->isOpen()) m_device->close(); m_device = nullptr; - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::release, - m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy)); } void URLRequestCustomJob::Start() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::initialize, - m_proxy, request()->url(), request()->method(), request()->initiator())); + HttpRequestHeaders requestHeaders = request()->extra_request_headers(); + std::map<std::string, std::string> headers; + net::HttpRequestHeaders::Iterator it(requestHeaders); + while (it.GetNext()) + headers.emplace(it.name(), it.value()); + if (!request()->referrer().empty()) + headers.emplace("Referer", request()->referrer()); + + // TODO: handle UploadDataStream, for instance using a QIODevice wrapper. + + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&URLRequestCustomJobProxy::initialize, + m_proxy, + request()->url(), + request()->method(), + request()->initiator(), + std::move(headers))); } void URLRequestCustomJob::Kill() @@ -94,9 +110,9 @@ void URLRequestCustomJob::Kill() m_pendingReadPos = 0; } m_device = nullptr; - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::release, - m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&URLRequestCustomJobProxy::release, + m_proxy)); URLRequestJob::Kill(); } diff --git a/src/core/net/url_request_custom_job_delegate.cpp b/src/core/net/url_request_custom_job_delegate.cpp index 338bd7137..b5a7a55a7 100644 --- a/src/core/net/url_request_custom_job_delegate.cpp +++ b/src/core/net/url_request_custom_job_delegate.cpp @@ -40,9 +40,12 @@ #include "url_request_custom_job_delegate.h" #include "url_request_custom_job_proxy.h" -#include "type_conversion.h" -#include "net/base/net_errors.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "net/base/net_errors.h" + +#include "type_conversion.h" #include <QByteArray> @@ -51,11 +54,13 @@ namespace QtWebEngineCore { URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url, const QByteArray &method, - const QUrl &initiatorOrigin) + const QUrl &initiatorOrigin, + const QMap<QByteArray, QByteArray> &headers) : m_proxy(proxy), m_request(url), m_method(method), - m_initiatorOrigin(initiatorOrigin) + m_initiatorOrigin(initiatorOrigin), + m_requestHeaders(headers) { } @@ -78,32 +83,36 @@ QUrl URLRequestCustomJobDelegate::initiator() const return m_initiatorOrigin; } +QMap<QByteArray, QByteArray> URLRequestCustomJobDelegate::requestHeaders() const +{ + return m_requestHeaders; +} + void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device) { if (device) QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::reply, - m_proxy,contentType.toStdString(),device)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::reply, + m_proxy,contentType.toStdString(),device)); } void URLRequestCustomJobDelegate::slotReadyRead() { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::readyRead, m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::readyRead, m_proxy)); } void URLRequestCustomJobDelegate::abort() { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::abort, m_proxy)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::abort, m_proxy)); } void URLRequestCustomJobDelegate::redirect(const QUrl &url) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::redirect, - m_proxy, toGurl(url))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::redirect, m_proxy, toGurl(url))); } void URLRequestCustomJobDelegate::fail(Error error) @@ -129,9 +138,8 @@ void URLRequestCustomJobDelegate::fail(Error error) break; } if (net_error) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCustomJobProxy::fail, - m_proxy, net_error)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&URLRequestCustomJobProxy::fail, m_proxy, net_error)); } } diff --git a/src/core/net/url_request_custom_job_delegate.h b/src/core/net/url_request_custom_job_delegate.h index caabfcf99..1bf3ade1f 100644 --- a/src/core/net/url_request_custom_job_delegate.h +++ b/src/core/net/url_request_custom_job_delegate.h @@ -54,6 +54,7 @@ #include "base/memory/ref_counted.h" #include "qtwebenginecoreglobal_p.h" +#include <QMap> #include <QObject> #include <QUrl> @@ -80,6 +81,7 @@ public: QUrl url() const; QByteArray method() const; QUrl initiator() const; + QMap<QByteArray, QByteArray> requestHeaders() const; void reply(const QByteArray &contentType, QIODevice *device); void redirect(const QUrl& url); @@ -93,13 +95,15 @@ private: URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url, const QByteArray &method, - const QUrl &initiatorOrigin); + const QUrl &initiatorOrigin, + const QMap<QByteArray, QByteArray> &requestHeaders); friend class URLRequestCustomJobProxy; scoped_refptr<URLRequestCustomJobProxy> m_proxy; QUrl m_request; QByteArray m_method; QUrl m_initiatorOrigin; + const QMap<QByteArray, QByteArray> m_requestHeaders; }; } // namespace diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp index b5f10388c..72d14450e 100644 --- a/src/core/net/url_request_custom_job_proxy.cpp +++ b/src/core/net/url_request_custom_job_proxy.cpp @@ -152,7 +152,9 @@ void URLRequestCustomJobProxy::readyRead() m_job->notifyReadyRead(); } -void URLRequestCustomJobProxy::initialize(GURL url, std::string method, base::Optional<url::Origin> initiator) +void URLRequestCustomJobProxy::initialize(GURL url, std::string method, + base::Optional<url::Origin> initiator, + std::map<std::string, std::string> headers) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); Q_ASSERT(!m_delegate); @@ -164,12 +166,16 @@ void URLRequestCustomJobProxy::initialize(GURL url, std::string method, base::Op QWebEngineUrlSchemeHandler *schemeHandler = nullptr; if (m_profileAdapter) - schemeHandler = m_profileAdapter->customUrlSchemeHandlers()[toQByteArray(m_scheme)]; + schemeHandler = m_profileAdapter->urlSchemeHandler(toQByteArray(m_scheme)); + QMap<QByteArray, QByteArray> qHeaders; + for (auto it = headers.cbegin(); it != headers.cend(); ++it) + qHeaders.insert(toQByteArray(it->first), toQByteArray(it->second)); if (schemeHandler) { m_delegate = new URLRequestCustomJobDelegate(this, toQt(url), QByteArray::fromStdString(method), - initiatorOrigin); + initiatorOrigin, + qHeaders); QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate); schemeHandler->requestStarted(requestJob); } diff --git a/src/core/net/url_request_custom_job_proxy.h b/src/core/net/url_request_custom_job_proxy.h index 3986fe119..aa55db07c 100644 --- a/src/core/net/url_request_custom_job_proxy.h +++ b/src/core/net/url_request_custom_job_proxy.h @@ -72,7 +72,7 @@ public: void abort(); void fail(int error); void release(); - void initialize(GURL url, std::string method, base::Optional<url::Origin> initiatorOrigin); + void initialize(GURL url, std::string method, base::Optional<url::Origin> initiatorOrigin, std::map<std::string, std::string> headers); void readyRead(); // IO thread owned: diff --git a/src/core/net/url_request_notification.cpp b/src/core/net/url_request_notification.cpp new file mode 100644 index 000000000..6da661cff --- /dev/null +++ b/src/core/net/url_request_notification.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** 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 "url_request_notification.h" + +#include "base/supports_user_data.h" +#include "base/task/post_task.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_thread.h" +#include "net/url_request/url_request.h" +#include "web_contents_adapter_client.h" +#include "web_contents_view_qt.h" +#include "profile_io_data_qt.h" +#include "qwebengineurlrequestinfo_p.h" +#include "type_conversion.h" + +namespace QtWebEngineCore { + +// Calls cancel() when the URLRequest is destroyed. +class UserData : public base::SupportsUserData::Data { +public: + UserData(URLRequestNotification *ptr) : m_ptr(ptr) {} + ~UserData() { m_ptr->cancel(); } + static const char key[]; +private: + URLRequestNotification *m_ptr; +}; + +const char UserData::key[] = "QtWebEngineCore::URLRequestNotification"; + +static content::ResourceType fromQt(QWebEngineUrlRequestInfo::ResourceType resourceType) +{ + return static_cast<content::ResourceType>(resourceType); +} + +URLRequestNotification::URLRequestNotification(net::URLRequest *request, + bool isMainFrameRequest, + GURL *newUrl, + QWebEngineUrlRequestInfo &&requestInfo, + content::ResourceRequestInfo::WebContentsGetter webContentsGetter, + net::CompletionOnceCallback callback, + QPointer<ProfileAdapter> adapter) + : m_request(request) + , m_isMainFrameRequest(isMainFrameRequest) + , m_newUrl(newUrl) + , m_originalUrl(requestInfo.requestUrl()) + , m_requestInfo(std::move(requestInfo)) + , m_webContentsGetter(webContentsGetter) + , m_callback(std::move(callback)) + , m_profileAdapter(adapter) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + m_request->SetUserData(UserData::key, std::make_unique<UserData>(this)); + + base::PostTaskWithTraits( + FROM_HERE, + {content::BrowserThread::UI}, + base::BindOnce(&URLRequestNotification::notify, base::Unretained(this))); +} + + +void URLRequestNotification::notify() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // May run concurrently with cancel() so no peeking at m_request here. + + int result = net::OK; + content::WebContents *webContents = m_webContentsGetter.Run(); + + if (webContents) { + + if (m_profileAdapter) { + QWebEngineUrlRequestInterceptor* interceptor = m_profileAdapter->requestInterceptor(); + interceptor->interceptRequest(m_requestInfo); + } + + WebContentsAdapterClient *client = + WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client(); + + if (!m_requestInfo.changed()) { + client->interceptRequest(m_requestInfo); + } + + if (m_requestInfo.changed()) { + result = m_requestInfo.d_ptr->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; + // We handle the rest of the changes later when we are back in I/O thread + } + + // Only do navigationRequested on MAIN_FRAME and SUB_FRAME resources + if (result == net::OK && content::IsResourceTypeFrame(fromQt(m_requestInfo.resourceType()))) { + int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; + client->navigationRequested(m_requestInfo.navigationType(), + m_requestInfo.requestUrl(), + navigationRequestAction, + m_isMainFrameRequest); + result = net::ERR_FAILED; + switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) { + case WebContentsAdapterClient::AcceptRequest: + result = net::OK; + break; + case WebContentsAdapterClient::IgnoreRequest: + result = net::ERR_ABORTED; + break; + } + DCHECK(result != net::ERR_FAILED); + } + } + + // Run the callback on the IO thread. + base::PostTaskWithTraits( + FROM_HERE, + {content::BrowserThread::IO}, + base::BindOnce(&URLRequestNotification::complete, base::Unretained(this), result)); +} + +void URLRequestNotification::cancel() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + // May run concurrently with notify() but we only touch m_request here. + + m_request = nullptr; +} + +void URLRequestNotification::complete(int error) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (m_request) { + if (m_requestInfo.changed()) { + if (m_originalUrl != m_requestInfo.d_ptr->url) + *m_newUrl = toGurl(m_requestInfo.d_ptr->url); + + if (!m_requestInfo.d_ptr->extraHeaders.isEmpty()) { + auto end = m_requestInfo.d_ptr->extraHeaders.constEnd(); + for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header) + m_request->SetExtraRequestHeaderByName(header.key().toStdString(), header.value().toStdString(), /* overwrite */ true); + } + } + + if (m_request->status().status() != net::URLRequestStatus::CANCELED) + std::move(m_callback).Run(error); + m_request->RemoveUserData(UserData::key); + } + + delete this; +} + +} diff --git a/src/core/net/url_request_notification.h b/src/core/net/url_request_notification.h new file mode 100644 index 000000000..1d9acf12f --- /dev/null +++ b/src/core/net/url_request_notification.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef URL_REQUEST_NOTIFIACTION_H +#define URL_REQUEST_NOTIFIACTION_H + +#include "content/public/browser/resource_request_info.h" +#include "net/base/completion_once_callback.h" +#include "qwebengineurlrequestinfo.h" +#include <QPointer> + +class GURL; + +namespace net { +class URLRequest; +} + +namespace QtWebEngineCore { + +class ProfileAdapter; +class ProfileIoDataQt; + +// Notifies WebContentsAdapterClient of a new URLRequest. +class URLRequestNotification { +public: + URLRequestNotification(net::URLRequest *request, + bool isMainFrameRequest, + GURL *newUrl, + QWebEngineUrlRequestInfo &&requestInfo, + content::ResourceRequestInfo::WebContentsGetter webContentsGetter, + net::CompletionOnceCallback callback, + QPointer<ProfileAdapter> adapter); + ~URLRequestNotification() = default; + void cancel(); + void notify(); + void complete(int error); + +private: + net::URLRequest *m_request; //used only by io thread + bool m_isMainFrameRequest; + GURL *m_newUrl; + const QUrl m_originalUrl; + QWebEngineUrlRequestInfo m_requestInfo; + content::ResourceRequestInfo::WebContentsGetter m_webContentsGetter; + net::CompletionOnceCallback m_callback; + QPointer<ProfileAdapter> m_profileAdapter; +}; +} +#endif diff --git a/src/core/net/url_request_qrc_job_qt.cpp b/src/core/net/url_request_qrc_job_qt.cpp deleted file mode 100644 index a2712653d..000000000 --- a/src/core/net/url_request_qrc_job_qt.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** 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 "url_request_qrc_job_qt.h" - -#include "type_conversion.h" - -#include "base/pending_task.h" -#include "base/threading/thread_task_runner_handle.h" -#include "net/base/net_errors.h" -#include "net/base/io_buffer.h" - -#include <QUrl> -#include <QFileInfo> -#include <QMimeDatabase> -#include <QMimeType> - -using namespace net; -namespace QtWebEngineCore { - -URLRequestQrcJobQt::URLRequestQrcJobQt(URLRequest *request, NetworkDelegate *networkDelegate) - : URLRequestJob(request, networkDelegate) - , m_remainingBytes(0) - , m_weakFactory(this) -{ -} - -URLRequestQrcJobQt::~URLRequestQrcJobQt() -{ - if (m_file.isOpen()) - m_file.close(); -} - -void URLRequestQrcJobQt::Start() -{ - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&URLRequestQrcJobQt::startGetHead, m_weakFactory.GetWeakPtr())); -} - -void URLRequestQrcJobQt::Kill() -{ - if (m_file.isOpen()) - m_file.close(); - m_weakFactory.InvalidateWeakPtrs(); - - URLRequestJob::Kill(); -} - -bool URLRequestQrcJobQt::GetMimeType(std::string *mimeType) const -{ - DCHECK(request_); - if (m_mimeType.size() > 0) { - *mimeType = m_mimeType; - return true; - } - return false; -} - -int URLRequestQrcJobQt::ReadRawData(IOBuffer *buf, int bufSize) -{ - DCHECK_GE(m_remainingBytes, 0); - // File has been read finished. - if (!m_remainingBytes || !bufSize) { - return 0; - } - if (m_remainingBytes < bufSize) - bufSize = static_cast<int>(m_remainingBytes); - qint64 rv = m_file.read(buf->data(), bufSize); - if (rv >= 0) { - m_remainingBytes -= rv; - DCHECK_GE(m_remainingBytes, 0); - return static_cast<int>(rv); - } - return static_cast<int>(rv); -} - -void URLRequestQrcJobQt::startGetHead() -{ - // Get qrc file path. - QString qrcFilePath = ':' + toQt(request_->url()).path(); - m_file.setFileName(qrcFilePath); - QFileInfo qrcFileInfo(m_file); - // Get qrc file mime type. - QMimeDatabase mimeDatabase; - QMimeType mimeType = mimeDatabase.mimeTypeForFile(qrcFileInfo); - m_mimeType = mimeType.name().toStdString(); - // Open file - if (m_file.open(QIODevice::ReadOnly)) { - m_remainingBytes = m_file.size(); - set_expected_content_size(m_remainingBytes); - // Notify that the headers are complete - NotifyHeadersComplete(); - } else { - NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, ERR_INVALID_URL)); - } -} - -} // namespace QtWebEngineCore diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp index 918500b58..ec36e70d9 100644 --- a/src/core/net/webui_controller_factory_qt.cpp +++ b/src/core/net/webui_controller_factory_qt.cpp @@ -48,6 +48,7 @@ #include "base/location.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "chrome/browser/accessibility/accessibility_ui.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/devtools_ui.h" #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h" @@ -136,6 +137,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co // return nullptr; return &NewWebUI<DevToolsUI>; } + if (url.host() == chrome::kChromeUIAccessibilityHost) + return &NewWebUI<AccessibilityUI>; // if (url.host_piece() == chrome::kChromeUIUserActionsHost) // return &NewWebUI<UserActionsUI>; diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp index ec49414b0..c4a075544 100644 --- a/src/core/ozone/gl_context_qt.cpp +++ b/src/core/ozone/gl_context_qt.cpp @@ -119,14 +119,21 @@ void* GLContextHelper::getGlXConfig() void* GLContextHelper::getEGLDisplay() { +#ifdef Q_OS_WIN + // Windows QPA plugin does not implement resourceForIntegration for "egldisplay". + // Use resourceForContext instead. + return resourceForContext(QByteArrayLiteral("egldisplay")); +#else return resourceForIntegration(QByteArrayLiteral("egldisplay")); +#endif } void* GLContextHelper::getXDisplay() { - if (QGuiApplication::platformName() != QLatin1String("xcb")) - return nullptr; - return qApp->platformNativeInterface()->nativeResourceForScreen(QByteArrayLiteral("display"), qApp->primaryScreen()); + QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); + if (pni) + return pni->nativeResourceForScreen(QByteArrayLiteral("display"), qApp->primaryScreen()); + return nullptr; } void* GLContextHelper::getNativeDisplay() diff --git a/src/core/ozone/gl_surface_egl_qt.cpp b/src/core/ozone/gl_surface_egl_qt.cpp index 9fe5985ce..8715a5095 100644 --- a/src/core/ozone/gl_surface_egl_qt.cpp +++ b/src/core/ozone/gl_surface_egl_qt.cpp @@ -44,9 +44,9 @@ #include "gl_context_qt.h" #include "ozone/gl_surface_egl_qt.h" -#include "ui/gl/gl_surface_egl.h" #if !defined(OS_MACOSX) #include "ui/gl/egl_util.h" +#include "ui/gl/gl_surface_egl.h" #include "ui/gl/init/gl_factory.h" // From ANGLE's egl/eglext.h. @@ -302,10 +302,6 @@ void* GLSurfacelessQtEGL::GetShareHandle() return NULL; } -} // namespace gl -#endif // !defined(OS_MACOSX) - -namespace gl { std::string DriverEGL::GetPlatformExtensions() { EGLDisplay display = GLContextHelper::getEGLDisplay(); @@ -317,3 +313,15 @@ std::string DriverEGL::GetPlatformExtensions() return str ? std::string(str) : ""; } } // namespace gl +#else +namespace gl { +struct GL_EXPORT DriverEGL { + static std::string GetPlatformExtensions(); +}; + +std::string DriverEGL::GetPlatformExtensions() +{ + return ""; +} +} // namespace gl +#endif // !defined(OS_MACOSX) diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp index 7cde289ae..551ba888c 100644 --- a/src/core/ozone/gl_surface_qt.cpp +++ b/src/core/ozone/gl_surface_qt.cpp @@ -64,7 +64,6 @@ #include "ozone/gl_surface_wgl_qt.h" #include "gpu/ipc/service/direct_composition_surface_win.h" -#include "ui/gl/gl_context_wgl.h" #include "ui/gl/vsync_provider_win.h" #endif @@ -141,9 +140,6 @@ bool InitializeGLOneOffPlatform() { VSyncProviderWin::InitializeOneOff(); - if (GetGLImplementation() == kGLImplementationOSMesaGL) - return false; - if (GetGLImplementation() == kGLImplementationEGLGLES2) return GLSurfaceEGLQt::InitializeOneOff(); diff --git a/src/core/ozone/gl_surface_wgl_qt.cpp b/src/core/ozone/gl_surface_wgl_qt.cpp index 7c9e87b86..ac27a9c20 100644 --- a/src/core/ozone/gl_surface_wgl_qt.cpp +++ b/src/core/ozone/gl_surface_wgl_qt.cpp @@ -37,9 +37,9 @@ ** ****************************************************************************/ -#if defined(OS_WIN) - #include "gl_surface_wgl_qt.h" + +#if defined(OS_WIN) #include "ui/gl/gl_surface_wgl.h" namespace gl { diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp index 905e8f403..1115f3fac 100644 --- a/src/core/ozone/ozone_platform_qt.cpp +++ b/src/core/ozone/ozone_platform_qt.cpp @@ -43,6 +43,7 @@ #include "ozone/surface_factory_qt.h" #include "ozone/platform_window_qt.h" #include "ui/display/types/native_display_delegate.h" +#include "ui/events/system_input_injector.h" #include "ui/ozone/common/stub_client_native_pixmap_factory.h" #include "ui/ozone/common/stub_overlay_manager.h" #include "ui/ozone/public/cursor_factory_ozone.h" diff --git a/src/core/ozone/platform_window_qt.h b/src/core/ozone/platform_window_qt.h index b712b706a..bb2fc714b 100644 --- a/src/core/ozone/platform_window_qt.h +++ b/src/core/ozone/platform_window_qt.h @@ -75,6 +75,9 @@ public: void MoveCursorTo(const gfx::Point&) override { } void ConfineCursorToBounds(const gfx::Rect&) override { } PlatformImeController* GetPlatformImeController() override { return nullptr; } + void SetRestoredBoundsInPixels(const gfx::Rect& bounds) override { } + gfx::Rect GetRestoredBoundsInPixels() const override { return gfx::Rect(); } + // PlatformEventDispatcher: bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index b999f4186..2a7311187 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -61,8 +61,9 @@ ProfileAdapter::PermissionType toQt(content::PermissionType type) return ProfileAdapter::AudioCapturePermission; case content::PermissionType::VIDEO_CAPTURE: return ProfileAdapter::VideoCapturePermission; - case content::PermissionType::FLASH: case content::PermissionType::NOTIFICATIONS: + return ProfileAdapter::NotificationPermission; + case content::PermissionType::FLASH: case content::PermissionType::MIDI_SYSEX: case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: case content::PermissionType::MIDI: @@ -76,6 +77,7 @@ ProfileAdapter::PermissionType toQt(content::PermissionType type) case content::PermissionType::CLIPBOARD_WRITE: return ProfileAdapter::ClipboardWrite; case content::PermissionType::PAYMENT_HANDLER: + case content::PermissionType::BACKGROUND_FETCH: case content::PermissionType::NUM: break; } @@ -187,6 +189,9 @@ int PermissionManagerQt::RequestPermission(content::PermissionType permission, m_requests.insert(request_id, request); if (permissionType == ProfileAdapter::GeolocationPermission) contentsDelegate->requestGeolocationPermission(request.origin); + else if (permissionType == ProfileAdapter::NotificationPermission) + contentsDelegate->requestUserNotificationPermission(request.origin); + return request_id; } @@ -235,6 +240,8 @@ int PermissionManagerQt::RequestPermissions(const std::vector<content::Permissio const ProfileAdapter::PermissionType permissionType = toQt(permission); if (permissionType == ProfileAdapter::GeolocationPermission) contentsDelegate->requestGeolocationPermission(request.origin); + else if (permissionType == ProfileAdapter::NotificationPermission) + contentsDelegate->requestUserNotificationPermission(request.origin); } return request_id; } @@ -294,8 +301,8 @@ void PermissionManagerQt::ResetPermission( int PermissionManagerQt::SubscribePermissionStatusChange( content::PermissionType permission, + content::RenderFrameHost * /* render_frame_host */, const GURL& requesting_origin, - const GURL& /*embedding_origin*/, const base::Callback<void(blink::mojom::PermissionStatus)>& callback) { int subscriber_id = ++m_subscriberIdCount; @@ -311,7 +318,7 @@ int PermissionManagerQt::SubscribePermissionStatusChange( void PermissionManagerQt::UnsubscribePermissionStatusChange(int subscription_id) { if (!m_subscribers.remove(subscription_id)) - qWarning() << "PermissionManagerQt::UnsubscribePermissionStatusChange called on unknown subscription id" << subscription_id; + LOG(WARNING) << "PermissionManagerQt::UnsubscribePermissionStatusChange called on unknown subscription id" << subscription_id; } } // namespace QtWebEngineCore diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h index b3bd3dc7a..89eb6cf85 100644 --- a/src/core/permission_manager_qt.h +++ b/src/core/permission_manager_qt.h @@ -92,8 +92,8 @@ public: int SubscribePermissionStatusChange( content::PermissionType permission, + content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, - const GURL& embedding_origin, const base::Callback<void(blink::mojom::PermissionStatus)>& callback) override; void UnsubscribePermissionStatusChange(int subscription_id) override; diff --git a/src/core/platform_notification_service_qt.cpp b/src/core/platform_notification_service_qt.cpp new file mode 100644 index 000000000..dff3aed61 --- /dev/null +++ b/src/core/platform_notification_service_qt.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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 "platform_notification_service_qt.h" + +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/permission_type.h" +#include "content/public/browser/notification_event_dispatcher.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +#include "profile_adapter.h" +#include "profile_adapter_client.h" +#include "profile_qt.h" +#include "user_notification_controller.h" +#include "resource_context_qt.h" +#include "type_conversion.h" + +#include <QSharedPointer> + +namespace QtWebEngineCore { + +struct NonPersistentNotificationDelegate : UserNotificationController::Delegate { + NonPersistentNotificationDelegate(const std::string &id) : notification_id(id) { } + + virtual void shown() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentShowEvent(notification_id); + } + + virtual void clicked() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentClickEvent(notification_id, base::DoNothing()); + } + + virtual void closed(bool /*by_user*/) override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNonPersistentCloseEvent(notification_id, base::DoNothing()); + } + + const std::string notification_id; +}; + +struct PersistentNotificationDelegate : UserNotificationController::Delegate { + PersistentNotificationDelegate(content::BrowserContext *context, const std::string &id, const GURL &origin) + : browser_context(context), notification_id(id), origin(origin) { } + + virtual void shown() override { } + + virtual void clicked() override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNotificationClickEvent(browser_context, notification_id, origin, base::nullopt, base::nullopt, base::DoNothing()); + } + + virtual void closed(bool by_user) override { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (auto inst = content::NotificationEventDispatcher::GetInstance()) + inst->DispatchNotificationCloseEvent(browser_context, notification_id, origin, by_user, base::DoNothing()); + } + + content::BrowserContext *browser_context; + const std::string notification_id; + const GURL origin; +}; + + +PlatformNotificationServiceQt::PlatformNotificationServiceQt() {} + +PlatformNotificationServiceQt::~PlatformNotificationServiceQt() {} + +void PlatformNotificationServiceQt::DisplayNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id, + const GURL &origin, + const blink::PlatformNotificationData ¬ificationData, + const blink::NotificationResources ¬ificationResources) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt*>(browser_context); + + auto delegate = new NonPersistentNotificationDelegate(notification_id); + QSharedPointer<UserNotificationController> controller( + new UserNotificationController(notificationData, notificationResources, origin, delegate)); + + profile->profileAdapter()->ephemeralNotifications().insert(QByteArray::fromStdString(notification_id), controller); + + const QList<ProfileAdapterClient *> clients = profile->profileAdapter()->clients(); + for (ProfileAdapterClient *client : clients) + client->showNotification(controller); +} + +void PlatformNotificationServiceQt::DisplayPersistentNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id, + const GURL &service_worker_origin, + const GURL &origin, + const blink::PlatformNotificationData ¬ificationData, + const blink::NotificationResources ¬ificationResources) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt * profile = static_cast<ProfileQt*>(browser_context); + + auto delegate = new PersistentNotificationDelegate(profile, notification_id, service_worker_origin); + QSharedPointer<UserNotificationController> controller( + new UserNotificationController(notificationData, notificationResources, service_worker_origin, delegate)); + + profile->profileAdapter()->persistentNotifications().insert(QByteArray::fromStdString(notification_id), controller); + const QList<ProfileAdapterClient *> clients = profile->profileAdapter()->clients(); + for (ProfileAdapterClient *client : clients) + client->showNotification(controller); +} + +void PlatformNotificationServiceQt::CloseNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt*>(browser_context); + + QSharedPointer<UserNotificationController> notificationController = + profile->profileAdapter()->ephemeralNotifications().take(QByteArray::fromStdString(notification_id)).lock(); + if (notificationController) + notificationController->closeNotification(); +} + +void PlatformNotificationServiceQt::ClosePersistentNotification( + content::BrowserContext *browser_context, + const std::string ¬ification_id) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt*>(browser_context); + + QSharedPointer<UserNotificationController> notificationController = + profile->profileAdapter()->persistentNotifications().take(QByteArray::fromStdString(notification_id)); + if (notificationController) + notificationController->closeNotification(); +} + +void PlatformNotificationServiceQt::GetDisplayedNotifications( + content::BrowserContext *browser_context, + const DisplayedNotificationsCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + ProfileQt *profile = static_cast<ProfileQt *>(browser_context); + + std::unique_ptr<std::set<std::string>> movableStdStringSet = std::make_unique<std::set<std::string>>(); + auto it = profile->profileAdapter()->persistentNotifications().constBegin(); + const auto end = profile->profileAdapter()->persistentNotifications().constEnd(); + while (it != end) { + if (it.value()->isShown()) + movableStdStringSet->insert(it.key().toStdString()); + ++it; + } + + callback.Run(std::move(movableStdStringSet), true /* supports_synchronization */); +} + +int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId(content::BrowserContext *browser_context) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + auto prefs = static_cast<ProfileQt *>(browser_context)->GetPrefs(); + int64_t nextId = prefs->GetInteger(prefs::kNotificationNextPersistentId) + 1; + prefs->SetInt64(prefs::kNotificationNextPersistentId, nextId); + return nextId; +} + +} // namespace QtWebEngineCore diff --git a/src/core/platform_notification_service_qt.h b/src/core/platform_notification_service_qt.h new file mode 100644 index 000000000..66cee9ed0 --- /dev/null +++ b/src/core/platform_notification_service_qt.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef PLATFORM_NOTIFICATION_SERVICE_QT_H +#define PLATFORM_NOTIFICATION_SERVICE_QT_H + +#include "content/public/browser/platform_notification_service.h" + +namespace QtWebEngineCore { + +class PlatformNotificationServiceQt : public content::PlatformNotificationService { +public: + PlatformNotificationServiceQt(); + ~PlatformNotificationServiceQt() override; + + // Displays the notification described in |notification_data| to the user. A + // closure through which the notification can be closed will be stored in the + // |cancel_callback| argument. This method must be called on the UI thread. + void DisplayNotification(content::BrowserContext* browser_context, + const std::string& notification_id, + const GURL& origin, + const blink::PlatformNotificationData& notificationData, + const blink::NotificationResources& notificationResources) override; + + // Displays the persistent notification described in |notification_data| to + // the user. This method must be called on the UI thread. + void DisplayPersistentNotification(content::BrowserContext* browser_context, + const std::string& notification_id, + const GURL& service_worker_origin, + const GURL& origin, + const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources) override; + + // Closes the notification identified by |notification_id|. + // This method must be called on the UI thread. + void CloseNotification(content::BrowserContext* browser_context, const std::string& notification_id) override; + + // Closes the persistent notification identified by |persistent_notification_id|. + // This method must be called on the UI thread. + void ClosePersistentNotification(content::BrowserContext* browser_context, const std::string& notification_id) override; + + // Retrieves the ids of all currently displaying notifications and + // posts |callback| with the result. + void GetDisplayedNotifications(content::BrowserContext* browser_context, const DisplayedNotificationsCallback& callback) override; + + // Reads the value of the next persistent notification ID from the profile and + // increments the value, as it is called once per notification write. + virtual int64_t ReadNextPersistentNotificationId(content::BrowserContext* browser_context) override; + + // Records a given notification to UKM. + virtual void RecordNotificationUkmEvent(content::BrowserContext*, const content::NotificationDatabaseData&) override { } +}; + +} // namespace QtWebEngineCore + +#endif // PLATFORM_NOTIFICATION_SERVICE_QT_H diff --git a/src/core/printing/pdfium_document_wrapper_qt.cpp b/src/core/printing/pdfium_document_wrapper_qt.cpp index a18258d0e..6dbdf64ef 100644 --- a/src/core/printing/pdfium_document_wrapper_qt.cpp +++ b/src/core/printing/pdfium_document_wrapper_qt.cpp @@ -54,7 +54,6 @@ public: : m_pageData(FPDF_LoadPage(data, pageIndex)) , m_width(FPDF_GetPageWidth(m_pageData)) , m_height(FPDF_GetPageHeight(m_pageData)) - , m_index(pageIndex) , m_image(createImage(targetWidth, targetHeight)) { } @@ -63,7 +62,6 @@ public: : m_pageData(nullptr) , m_width(-1) , m_height(-1) - , m_index(-1) , m_image(QImage()) { } @@ -102,14 +100,13 @@ private: 0, 0); FPDFBitmap_Destroy(bitmap); bitmap = nullptr; - return std::move(image); + return image; } private: FPDF_PAGE m_pageData; int m_width; int m_height; - int m_index; QImage m_image; }; diff --git a/src/core/printing/print_view_manager_base_qt.cpp b/src/core/printing/print_view_manager_base_qt.cpp index 0e7239ef8..1a16be69e 100644 --- a/src/core/printing/print_view_manager_base_qt.cpp +++ b/src/core/printing/print_view_manager_base_qt.cpp @@ -52,6 +52,7 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/task/post_task.h" #include "base/timer/timer.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" @@ -59,12 +60,13 @@ #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" #include "components/printing/common/print_messages.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" -#include "printing/pdf_metafile_skia.h" +#include "printing/metafile_skia.h" #include "printing/print_job_constants.h" #include "printing/printed_document.h" @@ -123,8 +125,8 @@ void PrintViewManagerBaseQt::PrintDocument(printing::PrintedDocument *document, const gfx::Rect &content_area, const gfx::Point &offsets) { - std::unique_ptr<printing::PdfMetafileSkia> metafile = - std::make_unique<printing::PdfMetafileSkia>(); + std::unique_ptr<printing::MetafileSkia> metafile = + std::make_unique<printing::MetafileSkia>(); CHECK(metafile->InitFromData(print_data->front(), print_data->size())); // Update the rendered document. It will send notifications to the listener. @@ -155,21 +157,19 @@ void PrintViewManagerBaseQt::OnDidPrintDocument(content::RenderFrameHost* /*rend return; const PrintHostMsg_DidPrintContent_Params &content = params.content; - if (!base::SharedMemory::IsHandleValid(content.metafile_data_handle)) { + if (!content.metafile_data_region.IsValid()) { NOTREACHED() << "invalid memory handle"; web_contents()->Stop(); return; } - std::unique_ptr<base::SharedMemory> shared_buf = - std::make_unique<base::SharedMemory>(content.metafile_data_handle, true); - if (!shared_buf->Map(content.data_size)) { + auto data = base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(content.metafile_data_region); + if (!data) { NOTREACHED() << "couldn't map"; web_contents()->Stop(); return; } - auto data = base::MakeRefCounted<base::RefCountedSharedMemory>( - std::move(shared_buf), content.data_size); + PrintDocument(document, data, params.page_size, params.content_area, params.physical_offsets); } @@ -516,9 +516,8 @@ void PrintViewManagerBaseQt::ReleasePrinterQuery() printerQuery = m_printerQueriesQueue->PopPrinterQuery(cookie); if (!printerQuery.get()) return; - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&printing::PrinterQuery::StopWorker, printerQuery.get())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&printing::PrinterQuery::StopWorker, printerQuery.get())); } // Originally from print_preview_message_handler.cc: @@ -528,7 +527,7 @@ void PrintViewManagerBaseQt::StopWorker(int documentCookie) { scoped_refptr<printing::PrinterQuery> printer_query = m_printerQueriesQueue->PopPrinterQuery(documentCookie); if (printer_query.get()) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(&printing::PrinterQuery::StopWorker, printer_query)); } } diff --git a/src/core/printing/print_view_manager_qt.cpp b/src/core/printing/print_view_manager_qt.cpp index ff9fc76be..e88f48624 100644 --- a/src/core/printing/print_view_manager_qt.cpp +++ b/src/core/printing/print_view_manager_qt.cpp @@ -53,50 +53,43 @@ #include "base/values.h" #include "base/memory/ref_counted_memory.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/printer_query.h" #include "components/printing/common/print_messages.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/web_preferences.h" -#include "printing/pdf_metafile_skia.h" +#include "printing/metafile_skia.h" #include "printing/print_job_constants.h" #include "printing/units.h" -DEFINE_WEB_CONTENTS_USER_DATA_KEY(QtWebEngineCore::PrintViewManagerQt); - namespace { static const qreal kMicronsToMillimeter = 1000.0f; -static std::vector<char> -GetStdVectorFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) +static QSharedPointer<QByteArray> GetStdVectorFromHandle(const base::ReadOnlySharedMemoryRegion &handle) { - std::unique_ptr<base::SharedMemory> shared_buf( - new base::SharedMemory(handle, true)); - - if (!shared_buf->Map(data_size)) { - return std::vector<char>(); - } + base::ReadOnlySharedMemoryMapping map = handle.Map(); + if (!map.IsValid()) + return QSharedPointer<QByteArray>(new QByteArray); - char* data = static_cast<char*>(shared_buf->memory()); - return std::vector<char>(data, data + data_size); + const char* data = static_cast<const char*>(map.memory()); + return QSharedPointer<QByteArray>(new QByteArray(data, map.size())); } static scoped_refptr<base::RefCountedBytes> -GetBytesFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) +GetBytesFromHandle(const base::ReadOnlySharedMemoryRegion &handle) { - std::unique_ptr<base::SharedMemory> shared_buf(new base::SharedMemory(handle, true)); - - if (!shared_buf->Map(data_size)) { + base::ReadOnlySharedMemoryMapping map = handle.Map(); + if (!map.IsValid()) return nullptr; - } - unsigned char* data = static_cast<unsigned char*>(shared_buf->memory()); - std::vector<unsigned char> dataVector(data, data + data_size); + const unsigned char* data = static_cast<const unsigned char*>(map.memory()); + std::vector<unsigned char> dataVector(data, data + map.size()); return base::RefCountedBytes::TakeVector(&dataVector); } @@ -108,15 +101,14 @@ static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data, base::AssertBlockingAllowed(); DCHECK_GT(data->size(), 0U); - printing::PdfMetafileSkia metafile; + printing::MetafileSkia metafile; metafile.InitFromData(static_cast<const void*>(data->front()), data->size()); base::File file(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); bool success = file.IsValid() && metafile.SaveTo(&file); - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(saveCallback, success)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(saveCallback, success)); } static base::DictionaryValue *createPrintSettings() @@ -222,16 +214,16 @@ void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayou return; if (m_printSettings || !filePath.length()) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, false)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, false)); return; } m_pdfOutputPath = toFilePath(filePath); m_pdfSaveCallback = callback; if (!PrintToPDFInternal(pageLayout, printInColor)) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, false)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, false)); resetPdfState(); } } @@ -246,16 +238,15 @@ void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, // If there already is a pending print in progress, don't try starting another one. if (m_printSettings) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, QSharedPointer<QByteArray>())); return; } m_pdfPrintCallback = callback; if (!PrintToPDFInternal(pageLayout, printInColor, useCustomMargins)) { - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(callback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, QSharedPointer<QByteArray>())); resetPdfState(); } @@ -358,21 +349,18 @@ void PrintViewManagerQt::OnMetafileReadyForPrinting(content::RenderFrameHost* rf StopWorker(params.document_cookie); // Create local copies so we can reset the state and take a new pdf print job. - base::Callback<void(const std::vector<char>&)> pdf_print_callback = m_pdfPrintCallback; - base::Callback<void(bool)> pdf_save_callback = m_pdfSaveCallback; + PrintToPDFCallback pdf_print_callback = std::move(m_pdfPrintCallback); + PrintToPDFFileCallback pdf_save_callback = std::move(m_pdfSaveCallback); base::FilePath pdfOutputPath = m_pdfOutputPath; resetPdfState(); if (!pdf_print_callback.is_null()) { - std::vector<char> data_vector = GetStdVectorFromHandle(params.content.metafile_data_handle, - params.content.data_size); - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(pdf_print_callback, data_vector)); + QSharedPointer<QByteArray> data_array = GetStdVectorFromHandle(params.content.metafile_data_region); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(pdf_print_callback, data_array)); } else { - scoped_refptr<base::RefCountedBytes> data_bytes - = GetBytesFromHandle(params.content.metafile_data_handle, params.content.data_size); + scoped_refptr<base::RefCountedBytes> data_bytes = GetBytesFromHandle(params.content.metafile_data_region); base::PostTaskWithTraits(FROM_HERE, {base::MayBlock()}, base::BindOnce(&SavePdfFile, data_bytes, pdfOutputPath, pdf_save_callback)); } @@ -392,9 +380,8 @@ void PrintViewManagerQt::DidStartLoading() void PrintViewManagerQt::NavigationStopped() { if (!m_pdfPrintCallback.is_null()) { - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(m_pdfPrintCallback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>())); } resetPdfState(); PrintViewManagerBaseQt::NavigationStopped(); @@ -404,9 +391,8 @@ void PrintViewManagerQt::RenderProcessGone(base::TerminationStatus status) { PrintViewManagerBaseQt::RenderProcessGone(status); if (!m_pdfPrintCallback.is_null()) { - content::BrowserThread::PostTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(m_pdfPrintCallback, std::vector<char>())); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>())); } resetPdfState(); } diff --git a/src/core/printing/print_view_manager_qt.h b/src/core/printing/print_view_manager_qt.h index 209be8782..b21389691 100644 --- a/src/core/printing/print_view_manager_qt.h +++ b/src/core/printing/print_view_manager_qt.h @@ -56,6 +56,8 @@ #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_user_data.h" +#include <QSharedPointer> + struct PrintHostMsg_RequestPrintPreview_Params; struct PrintHostMsg_DidPreviewDocument_Params; @@ -83,7 +85,7 @@ class PrintViewManagerQt { public: ~PrintViewManagerQt() override; - typedef base::Callback<void(const std::vector<char> &result)> PrintToPDFCallback; + typedef base::Callback<void(QSharedPointer<QByteArray> result)> PrintToPDFCallback; typedef base::Callback<void(bool success)> PrintToPDFFileCallback; // Method to print a page to a Pdf document with page size \a pageSize in location \a filePath. diff --git a/src/core/process_main.cpp b/src/core/process_main.cpp index 677f0b10a..d661d3b90 100644 --- a/src/core/process_main.cpp +++ b/src/core/process_main.cpp @@ -44,7 +44,10 @@ #if defined(OS_WIN) #include "sandbox/win/src/sandbox_types.h" #include "content/public/app/sandbox_helper_win.h" -#endif // OS_WIN +#elif defined(OS_MACOSX) +#include "base/logging.h" +#include "sandbox/mac/seatbelt_exec.h" +#endif namespace QtWebEngine { @@ -64,6 +67,13 @@ int processMain(int argc, const char **argv) params.argc = argc; params.argv = argv; #endif // OS_WIN +#if defined(OS_MACOSX) + sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt = + sandbox::SeatbeltExecServer::CreateFromArguments(argv[0], argc, const_cast<char**>(argv)); + if (seatbelt.sandbox_required) { + CHECK(seatbelt.server->InitializeSandbox()); + } +#endif // defined(OS_MACOSX) return content::ContentMain(params); } diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index 1b946949a..7070292d6 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -44,10 +44,12 @@ #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/download_manager.h" +#include "api/qwebengineurlscheme.h" #include "content_client_qt.h" #include "download_manager_delegate_qt.h" #include "net/url_request_context_getter_qt.h" #include "permission_manager_qt.h" +#include "profile_adapter_client.h" #include "profile_qt.h" #include "renderer_host/user_resource_controller_host.h" #include "type_conversion.h" @@ -57,6 +59,10 @@ #include "components/keyed_service/content/browser_context_dependency_manager.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/extension_system.h" +#endif + #include <QCoreApplication> #include <QDir> #include <QString> @@ -78,10 +84,12 @@ namespace QtWebEngineCore { ProfileAdapter::ProfileAdapter(const QString &storageName): m_name(storageName) , m_offTheRecord(storageName.isEmpty()) + , m_downloadPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) , m_httpCacheType(DiskHttpCache) , m_persistentCookiesPolicy(AllowPersistentCookies) , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) , m_httpCacheMaxSize(0) + , m_pageRequestInterceptors(0) { WebEngineContext::current()->addProfileAdapter(this); // creation of profile requires webengine context @@ -89,6 +97,11 @@ ProfileAdapter::ProfileAdapter(const QString &storageName): content::BrowserContext::Initialize(m_profile.data(), toFilePath(dataPath())); // fixme: this should not be here m_profile->m_profileIOData->initializeOnUIThread(); + m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (!storageName.isEmpty()) + extensions::ExtensionSystem::Get(m_profile.data())->InitForRegularProfile(true); +#endif } ProfileAdapter::~ProfileAdapter() @@ -101,6 +114,8 @@ ProfileAdapter::~ProfileAdapter() m_profile->GetDownloadManager(m_profile.data())->Shutdown(); m_downloadManagerDelegate.reset(); } + delete m_clientCertificateStore; + Q_ASSERT(m_pageRequestInterceptors == 0); } void ProfileAdapter::setStorageName(const QString &storageName) @@ -177,6 +192,22 @@ void ProfileAdapter::removeClient(ProfileAdapterClient *adapterClient) m_clients.removeOne(adapterClient); } +void ProfileAdapter::addPageRequestInterceptor() +{ + ++m_pageRequestInterceptors; + if (m_profile->m_urlRequestContextGetter.get()) + m_profile->m_profileIOData->updateRequestInterceptor(); +} + +void ProfileAdapter::removePageRequestInterceptor() +{ + Q_ASSERT(m_pageRequestInterceptors > 0); + --m_pageRequestInterceptors; + if (m_profile->m_urlRequestContextGetter.get()) + m_profile->m_profileIOData->updateRequestInterceptor(); +} + + void ProfileAdapter::cancelDownload(quint32 downloadId) { downloadManagerDelegate()->cancelDownload(downloadId); @@ -237,6 +268,11 @@ void ProfileAdapter::setDataPath(const QString &path) } } +void ProfileAdapter::setDownloadPath(const QString &path) +{ + m_downloadPath = path.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) : path; +} + QString ProfileAdapter::cachePath() const { if (m_offTheRecord) @@ -405,9 +441,23 @@ void ProfileAdapter::setHttpCacheMaxSize(int maxSize) m_profile->m_profileIOData->updateHttpCache(); } -const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &ProfileAdapter::customUrlSchemeHandlers() const +static bool isInternalScheme(const QByteArray &scheme) { - return m_customUrlSchemeHandlers; + static QSet<QByteArray> internalSchemes{ + QByteArrayLiteral("qrc"), + QByteArrayLiteral("data"), + QByteArrayLiteral("blob"), + QByteArrayLiteral("http"), + QByteArrayLiteral("https"), + QByteArrayLiteral("ftp"), + QByteArrayLiteral("javascript"), + }; + return internalSchemes.contains(scheme); +} + +QWebEngineUrlSchemeHandler *ProfileAdapter::urlSchemeHandler(const QByteArray &scheme) +{ + return m_customUrlSchemeHandlers.value(scheme.toLower()).data(); } const QList<QByteArray> ProfileAdapter::customUrlSchemes() const @@ -421,12 +471,17 @@ void ProfileAdapter::updateCustomUrlSchemeHandlers() m_profile->m_profileIOData->updateJobFactory(); } -bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) +void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) { + Q_ASSERT(handler); bool removedOneOrMore = false; auto it = m_customUrlSchemeHandlers.begin(); while (it != m_customUrlSchemeHandlers.end()) { if (it.value() == handler) { + if (isInternalScheme(it.key())) { + qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", it.key().constData()); + continue; + } it = m_customUrlSchemeHandlers.erase(it); removedOneOrMore = true; continue; @@ -435,26 +490,43 @@ bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *ha } if (removedOneOrMore) updateCustomUrlSchemeHandlers(); - return removedOneOrMore; } -QWebEngineUrlSchemeHandler *ProfileAdapter::takeCustomUrlSchemeHandler(const QByteArray &scheme) +void ProfileAdapter::removeUrlScheme(const QByteArray &scheme) { - QWebEngineUrlSchemeHandler *handler = m_customUrlSchemeHandlers.take(scheme); - if (handler) + QByteArray canonicalScheme = scheme.toLower(); + if (isInternalScheme(canonicalScheme)) { + qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", scheme.constData()); + return; + } + if (m_customUrlSchemeHandlers.remove(canonicalScheme)) updateCustomUrlSchemeHandlers(); - return handler; } -void ProfileAdapter::addCustomUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) +void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) { - m_customUrlSchemeHandlers.insert(scheme, handler); + Q_ASSERT(handler); + QByteArray canonicalScheme = scheme.toLower(); + if (isInternalScheme(canonicalScheme)) { + qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData()); + return; + } + if (m_customUrlSchemeHandlers.value(canonicalScheme, handler) != handler) { + qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); + return; + } + if (QWebEngineUrlScheme::schemeByName(canonicalScheme) == QWebEngineUrlScheme()) + qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " + "before installing the custom scheme handler.", scheme.constData()); + + m_customUrlSchemeHandlers.insert(canonicalScheme, handler); updateCustomUrlSchemeHandlers(); } -void ProfileAdapter::clearCustomUrlSchemeHandlers() +void ProfileAdapter::removeAllUrlSchemeHandlers() { m_customUrlSchemeHandlers.clear(); + m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); updateCustomUrlSchemeHandlers(); } @@ -563,7 +635,44 @@ void ProfileAdapter::removeWebContentsAdapterClient(WebContentsAdapterClient *cl void ProfileAdapter::resetVisitedLinksManager() { - m_visitedLinksManager.reset(new VisitedLinksManagerQt(this)); + m_visitedLinksManager.reset(new VisitedLinksManagerQt(m_profile.data(), persistVisitedLinks())); +} + +void ProfileAdapter::setUseForGlobalCertificateVerification(bool enable) +{ + if (m_usedForGlobalCertificateVerification == enable) + return; + + static QPointer<ProfileAdapter> profileForglobalCertificateVerification; + + m_usedForGlobalCertificateVerification = enable; + if (enable) { + if (profileForglobalCertificateVerification) { + profileForglobalCertificateVerification->m_usedForGlobalCertificateVerification = false; + for (auto *client : qAsConst(profileForglobalCertificateVerification->m_clients)) + client->useForGlobalCertificateVerificationChanged(); + } + profileForglobalCertificateVerification = this; + } else { + Q_ASSERT(profileForglobalCertificateVerification); + Q_ASSERT(profileForglobalCertificateVerification == this); + profileForglobalCertificateVerification = nullptr; + } + + if (m_profile->m_urlRequestContextGetter.get()) + m_profile->m_profileIOData->updateUsedForGlobalCertificateVerification(); +} + +bool ProfileAdapter::isUsedForGlobalCertificateVerification() const +{ + return m_usedForGlobalCertificateVerification; +} + +QWebEngineClientCertificateStore *ProfileAdapter::clientCertificateStore() +{ + if (!m_clientCertificateStore) + m_clientCertificateStore = new QWebEngineClientCertificateStore(m_profile->m_profileIOData->clientCertificateStoreData()); + return m_clientCertificateStore; } } // namespace QtWebEngineCore diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index 7ed5c13f5..1aff145b2 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -60,16 +60,19 @@ #include <QString> #include <QVector> +#include "api/qwebengineclientcertificatestore.h" #include "api/qwebenginecookiestore.h" #include "api/qwebengineurlrequestinterceptor.h" #include "api/qwebengineurlschemehandler.h" +#include "net/qrc_url_scheme_handler.h" QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { -class ProfileAdapterClient; +class UserNotificationController; class DownloadManagerDelegateQt; +class ProfileAdapterClient; class ProfileQt; class UserResourceControllerHost; class VisitedLinksManagerQt; @@ -113,6 +116,9 @@ public: QString dataPath() const; void setDataPath(const QString &path); + QString downloadPath() const { return m_downloadPath; } + void setDownloadPath(const QString &path); + QString cachePath() const; void setCachePath(const QString &path); @@ -153,8 +159,7 @@ public: enum PermissionType { UnsupportedPermission = 0, GeolocationPermission = 1, -// Reserved: -// NotificationPermission = 2, + NotificationPermission = 2, AudioCapturePermission = 3, VideoCapturePermission = 4, ClipboardRead = 5, @@ -174,14 +179,14 @@ public: void setHttpCacheMaxSize(int maxSize); bool trackVisitedLinks() const; - bool persistVisitedLinks() const; - const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &customUrlSchemeHandlers() const; + QWebEngineUrlSchemeHandler *urlSchemeHandler(const QByteArray &scheme); + void installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler); + void removeUrlScheme(const QByteArray &scheme); + void removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler); + void removeAllUrlSchemeHandlers(); + const QList<QByteArray> customUrlSchemes() const; - void clearCustomUrlSchemeHandlers(); - void addCustomUrlSchemeHandler(const QByteArray &, QWebEngineUrlSchemeHandler *); - bool removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *); - QWebEngineUrlSchemeHandler *takeCustomUrlSchemeHandler(const QByteArray &); UserResourceControllerHost *userResourceController(); void permissionRequestReply(const QUrl &origin, PermissionType type, bool reply); @@ -193,30 +198,53 @@ public: void clearHttpCache(); + void setUseForGlobalCertificateVerification(bool enable = true); + bool isUsedForGlobalCertificateVerification() const; + + void addPageRequestInterceptor(); + void removePageRequestInterceptor(); + bool hasPageRequestInterceptor() const { return m_pageRequestInterceptors > 0; } + + QWebEngineClientCertificateStore *clientCertificateStore(); + + QHash<QByteArray, QWeakPointer<UserNotificationController>> &ephemeralNotifications() + { return m_ephemeralNotifications; } + QHash<QByteArray, QSharedPointer<UserNotificationController>> &persistentNotifications() + { return m_persistentNotifications; } + private: void updateCustomUrlSchemeHandlers(); void resetVisitedLinksManager(); + bool persistVisitedLinks() const; QString m_name; bool m_offTheRecord; + bool m_usedForGlobalCertificateVerification = false; QScopedPointer<ProfileQt> m_profile; QScopedPointer<VisitedLinksManagerQt> m_visitedLinksManager; QScopedPointer<DownloadManagerDelegateQt> m_downloadManagerDelegate; QScopedPointer<UserResourceControllerHost> m_userResourceController; QScopedPointer<QWebEngineCookieStore> m_cookieStore; + QWebEngineClientCertificateStore *m_clientCertificateStore = nullptr; QPointer<QWebEngineUrlRequestInterceptor> m_requestInterceptor; QString m_dataPath; + QString m_downloadPath; QString m_cachePath; QString m_httpUserAgent; HttpCacheType m_httpCacheType; QString m_httpAcceptLanguage; PersistentCookiesPolicy m_persistentCookiesPolicy; VisitedLinksPolicy m_visitedLinksPolicy; - QHash<QByteArray, QWebEngineUrlSchemeHandler *> m_customUrlSchemeHandlers; + QHash<QByteArray, QPointer<QWebEngineUrlSchemeHandler>> m_customUrlSchemeHandlers; + QHash<QByteArray, QWeakPointer<UserNotificationController>> m_ephemeralNotifications; + QHash<QByteArray, QSharedPointer<UserNotificationController>> m_persistentNotifications; + QList<ProfileAdapterClient*> m_clients; QVector<WebContentsAdapterClient *> m_webContentsAdapterClients; int m_httpCacheMaxSize; + int m_pageRequestInterceptors; + QrcUrlSchemeHandler m_qrcHandler; Q_DISABLE_COPY(ProfileAdapter) }; diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h index 19af12ca4..8ee9d240e 100644 --- a/src/core/profile_adapter_client.h +++ b/src/core/profile_adapter_client.h @@ -52,12 +52,14 @@ #define PROFILE_ADAPTER_CLIENT_H #include "qtwebenginecoreglobal_p.h" +#include <QSharedPointer> #include <QString> #include <QUrl> namespace QtWebEngineCore { class WebContentsAdapterClient; +class UserNotificationController; class QWEBENGINECORE_PRIVATE_EXPORT ProfileAdapterClient { @@ -142,6 +144,9 @@ public: virtual void downloadRequested(DownloadItemInfo &info) = 0; virtual void downloadUpdated(const DownloadItemInfo &info) = 0; + virtual void useForGlobalCertificateVerificationChanged() {} + virtual void showNotification(QSharedPointer<UserNotificationController> &) { } + virtual void addWebContentsAdapterClient(WebContentsAdapterClient *adapter) = 0; virtual void removeWebContentsAdapterClient(WebContentsAdapterClient *adapter) = 0; static QString downloadInterruptReasonToString(DownloadInterruptReason reason); diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp index 63585b2c3..f1fe96f81 100644 --- a/src/core/profile_io_data_qt.cpp +++ b/src/core/profile_io_data_qt.cpp @@ -39,15 +39,17 @@ #include "profile_io_data_qt.h" -#include "base/task_scheduler/post_task.h" +#include "base/task/post_task.h" #include "components/certificate_transparency/ct_known_logs.h" #include "components/network_session_configurator/common/network_features.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/cookie_store_factory.h" #include "content/public/common/content_features.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "net/cert/cert_verifier.h" #include "net/cert/ct_log_verifier.h" #include "net/cert/ct_policy_enforcer.h" @@ -76,16 +78,26 @@ #include "services/file/user_id_map.h" #include "services/network/proxy_service_mojo.h" +#include "net/client_cert_override.h" +#include "net/client_cert_store_data.h" #include "net/cookie_monster_delegate_qt.h" #include "net/custom_protocol_handler.h" #include "net/network_delegate_qt.h" #include "net/proxy_config_service_qt.h" -#include "net/qrc_protocol_handler_qt.h" #include "net/url_request_context_getter_qt.h" #include "profile_qt.h" #include "resource_context_qt.h" #include "type_conversion.h" +#if defined(USE_NSS_CERTS) +#include "net/cert_net/nss_ocsp.h" +#endif + +#if defined(OS_LINUX) || defined(OS_MACOSX) +#include "net/cert/cert_net_fetcher.h" +#include "net/cert_net/cert_net_fetcher_impl.h" +#endif + namespace QtWebEngineCore { static const char* const kDefaultAuthSchemes[] = { net::kBasicAuthScheme, @@ -102,8 +114,6 @@ static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &f return false; if (first.enable_channel_id != second.enable_channel_id) return false; - if (first.enable_token_binding != second.enable_token_binding) - return false; return true; } @@ -153,13 +163,13 @@ static net::HttpNetworkSession::Params generateNetworkSessionParams(bool ignoreC { net::HttpNetworkSession::Params network_session_params; network_session_params.ignore_certificate_errors = ignoreCertificateErrors; - network_session_params.enable_token_binding = base::FeatureList::IsEnabled(features::kTokenBinding); network_session_params.enable_channel_id = base::FeatureList::IsEnabled(features::kChannelID); return network_session_params; } ProfileIODataQt::ProfileIODataQt(ProfileQt *profile) : m_profile(profile), + m_clientCertificateStoreData(new ClientCertificateStoreData), m_mutex(QMutex::Recursive), m_weakPtrFactory(this) { @@ -171,8 +181,19 @@ ProfileIODataQt::~ProfileIODataQt() { if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::IO)) DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (m_useForGlobalCertificateVerification) { +#if defined(USE_NSS_CERTS) + net::SetURLRequestContextForNSSHttpIO(nullptr); +#endif +#if defined(OS_LINUX) ||defined(OS_MACOSX) + net::ShutdownGlobalCertNetFetcher(); +#endif + } + if (m_urlRequestContext && m_urlRequestContext->proxy_resolution_service()) m_urlRequestContext->proxy_resolution_service()->OnShutdown(); + m_resourceContext.reset(); if (m_cookieDelegate) m_cookieDelegate->setCookieMonster(0); // this will let CookieMonsterDelegateQt be deleted @@ -180,9 +201,16 @@ ProfileIODataQt::~ProfileIODataQt() delete m_proxyConfigService.fetchAndStoreAcquire(0); } +QPointer<ProfileAdapter> ProfileIODataQt::profileAdapter() +{ + return m_profileAdapter; +} + void ProfileIODataQt::shutdownOnUIThread() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + delete m_clientCertificateStoreData; + m_clientCertificateStoreData = nullptr; bool posted = content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE, this); if (!posted) { qWarning() << "Could not delete ProfileIODataQt on io thread !"; @@ -203,6 +231,13 @@ content::ResourceContext *ProfileIODataQt::resourceContext() return m_resourceContext.get(); } +#if BUILDFLAG(ENABLE_EXTENSIONS) +extensions::ExtensionSystemQt* ProfileIODataQt::GetExtensionSystem() +{ + return m_profile->GetExtensionSystem(); +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + void ProfileIODataQt::initializeOnIOThread() { m_networkDelegate.reset(new NetworkDelegateQt(this)); @@ -214,6 +249,7 @@ void ProfileIODataQt::initializeOnIOThread() QMutexLocker lock(&m_mutex); generateAllStorage(); generateJobFactory(); + setGlobalCertificateVerification(); m_initialized = true; } @@ -280,7 +316,15 @@ void ProfileIODataQt::generateStorage() net::ProxyConfigService *proxyConfigService = m_proxyConfigService.fetchAndStoreAcquire(0); Q_ASSERT(proxyConfigService); - m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); + std::unique_ptr<net::CertVerifier> cert_verifier = net::CertVerifier::CreateDefault(); + net::CertVerifier::Config config; + // Enable revocation checking: + config.enable_rev_checking = true; + // Mirroring Android WebView (we have no beef with Symantec, and our users might use them): + config.disable_symantec_enforcement = true; + cert_verifier->SetConfig(config); + + m_storage->set_cert_verifier(std::move(cert_verifier)); std::unique_ptr<net::MultiLogCTVerifier> ct_verifier(new net::MultiLogCTVerifier()); std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs; for (const auto &ct_log : certificate_transparency::GetKnownLogs()) { @@ -305,7 +349,7 @@ void ProfileIODataQt::generateStorage() scoped_refptr<base::SequencedTaskRunner> background_task_runner( base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), - base::TaskPriority::BACKGROUND, + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})); m_transportSecurityPersister = std::make_unique<net::TransportSecurityPersister>( @@ -346,7 +390,7 @@ void ProfileIODataQt::generateCookieStore() channel_id_db = new net::SQLiteChannelIDStore( toFilePath(m_channelIdPath), base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BACKGROUND})); + {base::MayBlock(), base::TaskPriority::BEST_EFFORT})); } m_storage->set_channel_id_service( @@ -361,8 +405,8 @@ void ProfileIODataQt::generateCookieStore() base::FilePath(), false, false, - nullptr) - ); + nullptr), + nullptr); break; case ProfileAdapter::AllowPersistentCookies: cookieStore = content::CreateCookieStore( @@ -370,8 +414,8 @@ void ProfileIODataQt::generateCookieStore() toFilePath(m_cookiesPath), false, true, - nullptr) - ); + nullptr), + nullptr); break; case ProfileAdapter::ForcePersistentCookies: cookieStore = content::CreateCookieStore( @@ -379,8 +423,8 @@ void ProfileIODataQt::generateCookieStore() toFilePath(m_cookiesPath), true, true, - nullptr) - ); + nullptr), + nullptr); break; } @@ -477,13 +521,10 @@ void ProfileIODataQt::generateJobFactory() std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( new net::DataProtocolHandler())); scoped_refptr<base::TaskRunner> taskRunner(base::CreateTaskRunnerWithTraits({base::MayBlock(), - base::TaskPriority::BACKGROUND, + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); jobFactory->SetProtocolHandler(url::kFileScheme, std::make_unique<net::FileProtocolHandler>(taskRunner)); - jobFactory->SetProtocolHandler(kQrcSchemeQt, - std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( - new QrcProtocolHandlerQt())); jobFactory->SetProtocolHandler(url::kFtpScheme, net::FtpProtocolHandler::Create(m_urlRequestContext->host_resolver())); @@ -541,6 +582,21 @@ void ProfileIODataQt::regenerateJobFactory() } } +void ProfileIODataQt::setGlobalCertificateVerification() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + QMutexLocker lock(&m_mutex); + if (m_useForGlobalCertificateVerification) { +#if defined(USE_NSS_CERTS) + // Set request context used by NSS for OCSP requests. + net::SetURLRequestContextForNSSHttpIO(m_urlRequestContext.get()); +#endif +#if defined(OS_LINUX) || defined(OS_MACOSX) + net::SetGlobalCertNetFetcher(net::CreateCertNetFetcher(m_urlRequestContext.get())); +#endif + } +} + void ProfileIODataQt::setRequestContextData(content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors) { @@ -563,6 +619,7 @@ void ProfileIODataQt::setFullConfiguration() m_httpCachePath = m_profileAdapter->httpCachePath(); m_httpCacheMaxSize = m_profileAdapter->httpCacheMaxSize(); m_customUrlSchemes = m_profileAdapter->customUrlSchemes(); + m_useForGlobalCertificateVerification = m_profileAdapter->isUsedForGlobalCertificateVerification(); m_dataPath = m_profileAdapter->dataPath(); } @@ -572,8 +629,8 @@ void ProfileIODataQt::requestStorageGeneration() { if (m_initialized && !m_updateAllStorage) { m_updateAllStorage = true; createProxyConfig(); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&ProfileIODataQt::generateAllStorage, m_weakPtr)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ProfileIODataQt::generateAllStorage, m_weakPtr)); } } @@ -586,10 +643,14 @@ void ProfileIODataQt::createProxyConfig() // must synchronously run on the glib message loop. This will be passed to // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). Q_ASSERT(m_proxyConfigService == 0); + net::ProxyConfigWithAnnotation initialConfig; + ProxyPrefs::ConfigState initialConfigState = PrefProxyConfigTrackerImpl::ReadPrefConfig( + m_profileAdapter->profile()->GetPrefs(), &initialConfig); m_proxyConfigService = new ProxyConfigServiceQt( net::ProxyResolutionService::CreateSystemProxyConfigService( - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO))); + base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})), + initialConfig, initialConfigState); //pass interface to io thread m_proxyResolverFactoryInterface = ChromeMojoProxyResolverFactory::CreateWithStrongBinding().PassInterface(); } @@ -656,8 +717,8 @@ void ProfileIODataQt::updateJobFactory() if (m_initialized && !m_updateJobFactory) { m_updateJobFactory = true; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&ProfileIODataQt::regenerateJobFactory, m_weakPtr)); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ProfileIODataQt::regenerateJobFactory, m_weakPtr)); } } @@ -666,6 +727,7 @@ void ProfileIODataQt::updateRequestInterceptor() Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); QMutexLocker lock(&m_mutex); m_requestInterceptor = m_profileAdapter->requestInterceptor(); + m_hasPageInterceptors = m_profileAdapter->hasPageRequestInterceptor(); // We in this case do not need to regenerate any Chromium classes. } @@ -675,6 +737,18 @@ QWebEngineUrlRequestInterceptor *ProfileIODataQt::acquireInterceptor() return m_requestInterceptor; } +QWebEngineUrlRequestInterceptor *ProfileIODataQt::requestInterceptor() +{ + return m_requestInterceptor; +} + +bool ProfileIODataQt::hasPageInterceptors() +{ + // used in NetworkDelegateQt::OnBeforeURLRequest + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + return m_hasPageInterceptors; +} + void ProfileIODataQt::releaseInterceptor() { m_mutex.unlock(); @@ -690,4 +764,31 @@ bool ProfileIODataQt::canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) return m_cookieDelegate->canGetCookies(firstPartyUrl, url); } +void ProfileIODataQt::updateUsedForGlobalCertificateVerification() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + QMutexLocker lock(&m_mutex); + m_useForGlobalCertificateVerification = m_profileAdapter->isUsedForGlobalCertificateVerification(); + + if (m_useForGlobalCertificateVerification) + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ProfileIODataQt::setGlobalCertificateVerification, m_weakPtr)); +} + +ClientCertificateStoreData *ProfileIODataQt::clientCertificateStoreData() +{ + return m_clientCertificateStoreData; +} + +std::unique_ptr<net::ClientCertStore> ProfileIODataQt::CreateClientCertStore() +{ + return std::unique_ptr<net::ClientCertStore>(new ClientCertOverrideStore(m_clientCertificateStoreData)); +} + +// static +ProfileIODataQt *ProfileIODataQt::FromResourceContext(content::ResourceContext *resource_context) +{ + return static_cast<ResourceContextQt *>(resource_context)->m_io_data; +} + } // namespace QtWebEngineCore diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h index 2d4706bf4..edb2fd3b5 100644 --- a/src/core/profile_io_data_qt.h +++ b/src/core/profile_io_data_qt.h @@ -43,6 +43,7 @@ #include "profile_adapter.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" +#include "extensions/buildflags/buildflags.h" #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h" #include <QtCore/QString> @@ -50,6 +51,7 @@ #include <QtCore/QMutex> namespace net { +class ClientCertStore; class DhcpPacFileFetcherFactory; class HttpAuthPreferences; class HttpNetworkSession; @@ -61,8 +63,13 @@ class URLRequestJobFactoryImpl; class TransportSecurityPersister; } +namespace extensions { +class ExtensionSystemQt; +} + namespace QtWebEngineCore { +class ClientCertificateStoreData; class ProfileQt; // ProfileIOData contains data that lives on the IOthread @@ -75,8 +82,13 @@ public: ProfileIODataQt(ProfileQt *profile); // runs on ui thread virtual ~ProfileIODataQt(); + QPointer<ProfileAdapter> profileAdapter(); content::ResourceContext *resourceContext(); net::URLRequestContext *urlRequestContext(); +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt* GetExtensionSystem(); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + void initializeOnIOThread(); void initializeOnUIThread(); // runs on ui thread void shutdownOnUIThread(); // runs on ui thread @@ -91,10 +103,12 @@ public: void regenerateJobFactory(); bool canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url) const; bool canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) const; + void setGlobalCertificateVerification(); // Used in NetworkDelegateQt::OnBeforeURLRequest. QWebEngineUrlRequestInterceptor *acquireInterceptor(); void releaseInterceptor(); + QWebEngineUrlRequestInterceptor *requestInterceptor(); void setRequestContextData(content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors); @@ -107,7 +121,12 @@ public: void updateRequestInterceptor(); // runs on ui thread void requestStorageGeneration(); //runs on ui thread void createProxyConfig(); //runs on ui thread + void updateUsedForGlobalCertificateVerification(); // runs on ui thread + bool hasPageInterceptors(); + ClientCertificateStoreData *clientCertificateStoreData(); + std::unique_ptr<net::ClientCertStore> CreateClientCertStore(); + static ProfileIODataQt *FromResourceContext(content::ResourceContext *resource_context); private: ProfileQt *m_profile; std::unique_ptr<net::URLRequestContextStorage> m_storage; @@ -129,6 +148,7 @@ private: QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; QPointer<ProfileAdapter> m_profileAdapter; // never dereferenced in IO thread and it is passed by qpointer ProfileAdapter::PersistentCookiesPolicy m_persistentCookiesPolicy; + ClientCertificateStoreData *m_clientCertificateStoreData; QString m_cookiesPath; QString m_channelIdPath; QString m_httpAcceptLanguage; @@ -144,6 +164,8 @@ private: bool m_updateAllStorage = false; bool m_updateJobFactory = false; bool m_ignoreCertificateErrors = false; + bool m_useForGlobalCertificateVerification = false; + bool m_hasPageInterceptors = false; base::WeakPtrFactory<ProfileIODataQt> m_weakPtrFactory; // this should be always the last member QString m_dataPath; DISALLOW_COPY_AND_ASSIGN(ProfileIODataQt); diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp index df05d891e..39500629a 100644 --- a/src/core/profile_qt.cpp +++ b/src/core/profile_qt.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -41,6 +41,7 @@ #include "profile_adapter.h" #include "browsing_data_remover_delegate_qt.h" +#include "command_line_pref_store_qt.h" #include "download_manager_delegate_qt.h" #include "net/ssl_host_state_delegate_qt.h" #include "net/url_request_context_getter_qt.h" @@ -48,6 +49,7 @@ #include "qtwebenginecoreglobal_p.h" #include "type_conversion.h" #include "web_engine_library_info.h" +#include "web_engine_context.h" #include "base/time/time.h" #include "content/public/browser/browser_thread.h" @@ -62,22 +64,38 @@ #include "components/prefs/pref_service_factory.h" #include "components/prefs/pref_registry_simple.h" #include "components/user_prefs/user_prefs.h" +#include "components/proxy_config/pref_proxy_config_tracker_impl.h" +#include "chrome/common/pref_names.h" #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spellcheck_service.h" -#include "chrome/common/pref_names.h" #include "components/spellcheck/browser/pref_names.h" #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "components/guest_view/browser/guest_view_manager.h" +#include "extensions/browser/extension_protocols.h" +#include "extensions/browser/pref_names.h" +#include "extensions/browser/process_manager.h" +#include "extensions/common/constants.h" + +#include "extensions/extension_system_qt.h" +#endif + namespace QtWebEngineCore { ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) : m_profileIOData(new ProfileIODataQt(this)), m_profileAdapter(profileAdapter) +#if BUILDFLAG(ENABLE_EXTENSIONS) + , m_extensionSystem(nullptr) +#endif // BUILDFLAG(ENABLE_EXTENSIONS) { PrefServiceFactory factory; factory.set_user_prefs(new InMemoryPrefStore); + factory.set_command_line_prefs(base::MakeRefCounted<CommandLinePrefStoreQt>( + WebEngineContext::commandLine())); PrefRegistrySimple *registry = new PrefRegistrySimple(); - + PrefProxyConfigTrackerImpl::RegisterPrefs(registry); #if QT_CONFIG(webengine_spellchecker) // Initial spellcheck settings registry->RegisterStringPref(prefs::kAcceptLanguages, std::string()); @@ -87,6 +105,26 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckEnable, false); registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckUseSpellingService, false); #endif // QT_CONFIG(webengine_spellchecker) + registry->RegisterBooleanPref(prefs::kShowInternalAccessibilityTree, false); + registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + registry->RegisterDictionaryPref(extensions::pref_names::kExtensions); + registry->RegisterListPref(extensions::pref_names::kInstallAllowList); + registry->RegisterListPref(extensions::pref_names::kInstallDenyList); + registry->RegisterDictionaryPref(extensions::pref_names::kInstallForceList); + registry->RegisterDictionaryPref(extensions::pref_names::kInstallLoginScreenAppList); + registry->RegisterListPref(extensions::pref_names::kAllowedTypes); + registry->RegisterBooleanPref(extensions::pref_names::kStorageGarbageCollect, false); + registry->RegisterInt64Pref(extensions::pref_names::kLastUpdateCheck, 0); + registry->RegisterInt64Pref(extensions::pref_names::kNextUpdateCheck, 0); + registry->RegisterListPref(extensions::pref_names::kAllowedInstallSites); + registry->RegisterStringPref(extensions::pref_names::kLastChromeVersion, std::string()); + registry->RegisterListPref(extensions::pref_names::kNativeMessagingBlacklist); + registry->RegisterListPref(extensions::pref_names::kNativeMessagingWhitelist); + registry->RegisterBooleanPref(extensions::pref_names::kNativeMessagingUserLevelHosts, true); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + m_prefService = factory.Create(registry); user_prefs::UserPrefs::Set(this, m_prefService.get()); @@ -95,6 +133,11 @@ ProfileQt::ProfileQt(ProfileAdapter *profileAdapter) // ProfileQt object is allocated at the same address as a previously // destroyed one. Needs to be called after WebEngineContext initialization. BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + m_extensionSystem = static_cast<extensions::ExtensionSystemQt*>(extensions::ExtensionSystem::Get(this)); + m_extensionSystem->InitForRegularProfile(true); +#endif } ProfileQt::~ProfileQt() @@ -123,6 +166,11 @@ base::FilePath ProfileQt::GetPath() const return toFilePath(m_profileAdapter->dataPath()); } +base::FilePath ProfileQt::GetCachePath() const +{ + return toFilePath(m_profileAdapter->cachePath()); +} + bool ProfileQt::IsOffTheRecord() const { return m_profileAdapter->isOffTheRecord(); @@ -156,7 +204,11 @@ content::DownloadManagerDelegate *ProfileQt::GetDownloadManagerDelegate() content::BrowserPluginGuestManager *ProfileQt::GetGuestManager() { +#if BUILDFLAG(ENABLE_EXTENSIONS) + return guest_view::GuestViewManager::FromBrowserContext(this); +#else return nullptr; +#endif } storage::SpecialStoragePolicy *ProfileQt::GetSpecialStoragePolicy() @@ -210,6 +262,12 @@ net::URLRequestContextGetter *ProfileQt::CreateRequestContext( { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!m_urlRequestContextGetter.get()); +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::InfoMap* extension_info_map = GetExtensionSystem()->info_map(); + (*protocol_handlers)[extensions::kExtensionScheme] = + extensions::CreateExtensionProtocolHandler(IsOffTheRecord(),extension_info_map); +#endif + m_profileIOData->setRequestContextData(protocol_handlers, std::move(request_interceptors)); m_profileIOData->updateStorageSettings(); m_urlRequestContextGetter = new URLRequestContextGetterQt(m_profileIOData.get()); @@ -229,8 +287,8 @@ net::URLRequestContextGetter *ProfileQt::CreateRequestContextForStoragePartition void ProfileQt::FailedToLoadDictionary(const std::string &language) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - qWarning() << "Could not load dictionary for:" << toQt(language) << endl - << "Make sure that correct bdic file is in:" << toQt(WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES).value()); + LOG(WARNING) << "Could not load dictionary for:" << language; + LOG(INFO) << "Make sure that correct bdic file is in:" << WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES); } void ProfileQt::setSpellCheckLanguages(const QStringList &languages) @@ -266,4 +324,12 @@ bool ProfileQt::isSpellCheckEnabled() const return m_prefService->GetBoolean(spellcheck::prefs::kSpellCheckEnable); } #endif // QT_CONFIG(webengine_spellchecker) + +#if BUILDFLAG(ENABLE_EXTENSIONS) +extensions::ExtensionSystemQt* ProfileQt::GetExtensionSystem() +{ + return m_extensionSystem; +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + } // namespace QtWebEngineCore diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h index 00119c053..41eeeecf5 100644 --- a/src/core/profile_qt.h +++ b/src/core/profile_qt.h @@ -43,6 +43,7 @@ #include "chrome/browser/profiles/profile.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/resource_context.h" +#include "extensions/buildflags/buildflags.h" #include "net/url_request/url_request_context.h" #include "profile_io_data_qt.h" #include <QtGlobal> @@ -53,6 +54,10 @@ QT_END_NAMESPACE class InMemoryPrefStore; class PrefService; +namespace extensions { +class ExtensionSystemQt; +} + namespace QtWebEngineCore { class ProfileAdapter; @@ -68,6 +73,7 @@ public: // BrowserContext implementation: base::FilePath GetPath() const override; + base::FilePath GetCachePath() const override; bool IsOffTheRecord() const override; net::URLRequestContextGetter *CreateMediaRequestContext() override; @@ -98,6 +104,7 @@ public: PrefService *GetPrefs() override; const PrefService *GetPrefs() const override; net::URLRequestContextGetter *GetRequestContext() override; + void Initialize(); ProfileAdapter *profileAdapter() { return m_profileAdapter; } @@ -108,6 +115,9 @@ public: void setSpellCheckEnabled(bool enabled); bool isSpellCheckEnabled() const; #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt* GetExtensionSystem(); +#endif // defined(ENABLE_EXTENSIONS) private: friend class ContentBrowserClientQt; @@ -119,6 +129,10 @@ private: std::unique_ptr<ProfileIODataQt> m_profileIOData; ProfileAdapter *m_profileAdapter; friend class ProfileAdapter; +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt *m_extensionSystem; +#endif //ENABLE_EXTENSIONS + friend class BrowserContextAdapter; DISALLOW_COPY_AND_ASSIGN(ProfileQt); }; diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni index 14da1e6cf..7c0ca763e 100644 --- a/src/core/qtwebengine.gni +++ b/src/core/qtwebengine.gni @@ -1,5 +1,6 @@ import("//build/config/ui.gni") import("//media/media_options.gni") +import("//extensions/buildflags/buildflags.gni") import("//third_party/widevine/cdm/widevine.gni") chromium_version = exec_script("//build/util/version.py", [ "-f", rebase_path("//chrome/VERSION"), @@ -9,6 +10,7 @@ chromium_version = exec_script("//build/util/version.py", [ "-f", rebase_path("/ include_dirs = [ "//skia/config", "//third_party", + "//third_party/boringssl/src/include", "//third_party/skia/include/core" ] @@ -25,20 +27,19 @@ deps = [ "//components/web_cache/browser", "//components/web_cache/renderer", "//components/spellcheck:buildflags", + "//components/proxy_config", "//content/public/app:browser", - "//content/public/browser", - "//content/public/common", - "//content/public/renderer", + "//content", "//media:media_buildflags", "//net:net_with_v8", "//services/proxy_resolver:lib", "//skia", "//third_party/blink/public:blink", - "//third_party/mesa:mesa_headers", "//ui/accessibility", + "//ui/gl", "//qtwebengine/browser:interfaces", ":qtwebengine_sources", - ":qtwebengine_resources" + ":qtwebengine_resources", ] if (enable_webrtc) { @@ -49,12 +50,22 @@ if (is_linux && !is_desktop_linux) { deps += [ "//ui/events/ozone:events_ozone_evdev"] } +if (use_xscrnsaver) { + deps += [ "//ui/base/x" ] +} + if (use_ozone) { deps += [ "//ui/ozone/common" ] } +if (enable_extensions) { + deps += [ + ":qtwebengine_extensions_features" + ] +} + data_deps = [ "//qtwebengine/browser:service_manifests" ] defines = [ diff --git a/src/core/qtwebengine_resources.gni b/src/core/qtwebengine_resources.gni index 6e8c3c6eb..283235f66 100644 --- a/src/core/qtwebengine_resources.gni +++ b/src/core/qtwebengine_resources.gni @@ -1,10 +1,14 @@ import("//tools/grit/repack.gni") import("//build/config/locales.gni") import("//chrome/chrome_repack_locales.gni") +import("//extensions/buildflags/buildflags.gni") group("qtwebengine_resources") { deps = [ "//chrome/app:generated_resources", + "//chrome/browser:resources", + "//chrome/browser/resources:component_extension_resources", + "//chrome/common:resources", "//components/resources:components_resources", ":qtwebengine_repack_resources", ":qtwebengine_repack_resources_100", @@ -17,6 +21,8 @@ group("qtwebengine_resources") { repack("qtwebengine_repack_resources") { sources = [ "$root_gen_dir/qtwebengine/qt_webengine_resources.pak", + "$root_gen_dir/chrome/browser_resources.pak", + "$root_gen_dir/chrome/common_resources.pak", "$root_gen_dir/chrome/quota_internals_resources.pak", "$root_gen_dir/chrome/task_scheduler_internals_resources.pak", "$root_gen_dir/components/components_resources.pak", @@ -31,6 +37,8 @@ repack("qtwebengine_repack_resources") { "//qtwebengine/browser:qt_webengine_resources", "//chrome/browser/resources:quota_internals_resources", "//chrome/browser/resources:task_scheduler_internals_resources", + "//chrome/browser:resources_grit", + "//chrome/common:resources_grit", "//components/resources:components_resources_grit", "//content:resources_grit", "//mojo/public/js:resources", @@ -38,6 +46,20 @@ repack("qtwebengine_repack_resources") { "//third_party/blink/public:resources_grit", "//ui/resources:webui_resources_grd_grit", ] + + if (enable_extensions) { + sources += [ + "$root_gen_dir/chrome/component_extension_resources.pak", + "$root_gen_dir/extensions/extensions_renderer_resources.pak", + "$root_gen_dir/extensions/extensions_resources.pak", + ] + deps += [ + "//chrome/browser/resources:component_extension_resources_grit", + "//extensions:extensions_renderer_resources_grit", + "//extensions:extensions_resources_grd_grit", + ] + } + } repack("qtwebengine_repack_resources_100") { @@ -56,6 +78,14 @@ repack("qtwebengine_repack_resources_100") { "//third_party/blink/public:scaled_resources_100_percent", "//ui/resources:ui_resources_grd_grit" ] + if (enable_extensions) { + sources += [ + "$root_gen_dir/extensions/extensions_browser_resources_100_percent.pak" + ] + deps += [ + "//extensions:extensions_browser_resources_grit" + ] + } } repack("qtwebengine_repack_resources_200") { @@ -74,6 +104,14 @@ repack("qtwebengine_repack_resources_200") { "//third_party/blink/public:scaled_resources_200_percent", "//ui/resources:ui_resources_grd_grit" ] + if (enable_extensions) { + sources += [ + "$root_gen_dir/extensions/extensions_browser_resources_200_percent.pak" + ] + deps += [ + "//extensions:extensions_browser_resources_grit" + ] + } } repack("qtwebengine_repack_resources_devtools") { diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni index b1361e727..58df7096b 100644 --- a/src/core/qtwebengine_sources.gni +++ b/src/core/qtwebengine_sources.gni @@ -1,9 +1,11 @@ import("//build/config/features.gni") import("//build/config/ui.gni") +import("//chrome/common/features.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//pdf/features.gni") import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") +import("//extensions/buildflags/buildflags.gni") source_set("qtwebengine_spellcheck_sources") { include_dirs = core_include_dirs @@ -40,22 +42,22 @@ source_set("qtwebengine_sources") { "//skia:skia_config", "//third_party/boringssl:external_config", ] + deps = [ "//chrome/common:buildflags", "//components/nacl/common:buildflags", "//extensions/buildflags:buildflags", "//third_party/blink/public/mojom:mojom_platform", ] + sources = [ - "//chrome/common/custom_handlers/protocol_handler.cc", - "//chrome/common/custom_handlers/protocol_handler.h", + "//chrome/browser/accessibility/accessibility_ui.cc", + "//chrome/browser/accessibility/accessibility_ui.h", "//chrome/browser/custom_handlers/protocol_handler_registry.cc", "//chrome/browser/custom_handlers/protocol_handler_registry.h", "//chrome/browser/custom_handlers/protocol_handler_registry_factory.cc", "//chrome/browser/custom_handlers/protocol_handler_registry_factory.h", "//chrome/browser/media/webrtc/desktop_media_list.h", - "//chrome/browser/media/webrtc/desktop_streams_registry.cc", - "//chrome/browser/media/webrtc/desktop_streams_registry.h", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc", "//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h", "//chrome/browser/profiles/profile.cc", @@ -72,6 +74,8 @@ source_set("qtwebengine_sources") { "//chrome/browser/ui/webui/quota_internals/quota_internals_ui.h", "//chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.cc", "//chrome/browser/ui/webui/task_scheduler_internals/task_scheduler_internals_ui.h", + "//chrome/common/custom_handlers/protocol_handler.cc", + "//chrome/common/custom_handlers/protocol_handler.h", "//chrome/common/chrome_switches.cc", "//chrome/common/chrome_switches.h", "//chrome/common/pref_names.cc", @@ -80,12 +84,47 @@ source_set("qtwebengine_sources") { "//chrome/common/url_constants.h", "//chrome/common/webui_url_constants.cc", "//chrome/common/webui_url_constants.h", - "//extensions/common/constants.cc", - "//extensions/common/constants.h", - "//extensions/common/url_pattern.cc", - "//extensions/common/url_pattern.h", + "//components/prefs/in_memory_pref_store.cc", + "//components/prefs/in_memory_pref_store.h", ] + if (enable_extensions) { + deps += [ + ":qtwebengine_extensions_features", + "//chrome/browser/resources:component_extension_resources_grit", + "//chrome/common/extensions/api", + "//chrome/common/extensions/api:extensions_features", + "//components/crx_file", + "//components/crx_file:crx_creator", + "//components/spellcheck:buildflags", + "//extensions/buildflags:buildflags", + "//extensions/common", + "//extensions/common/api", + "//extensions/common:core_api_provider", + "//extensions/browser", + "//extensions/browser/api", + "//extensions/browser:core_api_provider", + "//extensions/renderer", + "//extensions:extensions_resources", + "//extensions/strings", + ] + sources += [ + "//chrome/common/extensions/permissions/chrome_api_permissions.cc", + "//chrome/common/extensions/permissions/chrome_api_permissions.h", + "//chrome/common/extensions/permissions/chrome_permission_message_provider.cc", + "//chrome/common/extensions/permissions/chrome_permission_message_provider.h", + "//chrome/common/extensions/permissions/chrome_permission_message_rules.cc", + "//chrome/common/extensions/permissions/chrome_permission_message_rules.h", + ] + } else { + sources += [ + "//extensions/common/constants.cc", + "//extensions/common/constants.h", + "//extensions/common/url_pattern.cc", + "//extensions/common/url_pattern.h", + ] + } + if (is_linux) { sources += [ "//chrome/browser/ui/webui/sandbox_internals_ui.cc", @@ -109,11 +148,6 @@ source_set("qtwebengine_sources") { "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", ] - - deps += [ - # Need to depend on //content/ppapi_plugin, which is private, thus depending on parent. - "//content", - ] } if (enable_basic_printing || enable_print_preview) { @@ -136,6 +170,8 @@ source_set("qtwebengine_sources") { deps += [ "//pdf", "//pdf:buildflags", + "//components/pdf/browser:browser", + "//components/pdf/renderer:renderer", "//components/printing/browser", "//components/printing/renderer", ] diff --git a/src/core/quota_permission_context_qt.cpp b/src/core/quota_permission_context_qt.cpp index cb1467364..a502e7fc8 100644 --- a/src/core/quota_permission_context_qt.cpp +++ b/src/core/quota_permission_context_qt.cpp @@ -39,7 +39,9 @@ #include "quota_permission_context_qt.h" +#include "base/task/post_task.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "quota_request_controller_impl.h" @@ -64,10 +66,10 @@ void QuotaPermissionContextQt::RequestQuotaPermission(const StorageQuotaParams & } if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&QuotaPermissionContextQt::RequestQuotaPermission, this, - params, render_process_id, callback)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&QuotaPermissionContextQt::RequestQuotaPermission, this, + params, render_process_id, callback)); return; } @@ -95,10 +97,10 @@ void QuotaPermissionContextQt::dispatchCallbackOnIOThread(const PermissionCallba return; if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&QuotaPermissionContextQt::dispatchCallbackOnIOThread, - this, callback, response)); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&QuotaPermissionContextQt::dispatchCallbackOnIOThread, + this, callback, response)); return; } diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 40ed75973..9791c8c46 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -40,18 +40,20 @@ #include "render_widget_host_view_qt.h" #include "browser_accessibility_manager_qt.h" -#include "chromium_overrides.h" -#include "compositor.h" +#include "compositor/compositor.h" #include "qtwebenginecoreglobal_p.h" #include "render_widget_host_view_qt_delegate.h" +#include "touch_handle_drawable_client.h" +#include "touch_selection_controller_client_qt.h" +#include "touch_selection_menu_controller.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" #include "web_event_factory.h" #include "components/viz/common/surfaces/frame_sink_id_allocator.h" -#include "content/browser/accessibility/browser_accessibility_state_impl.h" -#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/frame_host/frame_tree.h" +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/content_switches_internal.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" @@ -61,9 +63,11 @@ #include "third_party/blink/public/platform/web_cursor_info.h" #include "ui/events/blink/blink_event_util.h" #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/geometry/size_conversions.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" @@ -82,7 +86,6 @@ #include <QFocusEvent> #include <QGuiApplication> #include <QInputMethodEvent> -#include <QLoggingCategory> #include <QTextFormat> #include <QKeyEvent> #include <QMouseEvent> @@ -93,7 +96,6 @@ #include <QWheelEvent> #include <QWindow> #include <QtGui/private/qinputcontrol_p.h> -#include <QtGui/qaccessible.h> namespace QtWebEngineCore { @@ -184,14 +186,13 @@ static inline bool isCommonTextEditShortcut(const QKeyEvent *ke) static uint32_t s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: - MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, float dpiScale, int index = -1) + MotionEventQt(const QList<QTouchEvent::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) - , dpiScale(dpiScale) { // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 Q_ASSERT((action != Action::DOWN && action != Action::UP) || index == 0); @@ -202,8 +203,8 @@ public: int GetActionIndex() const override { return index; } size_t GetPointerCount() const override { return touchPoints.size(); } int GetPointerId(size_t pointer_index) const override { return touchPoints.at(pointer_index).id(); } - float GetX(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().x() / dpiScale; } - float GetY(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().y() / dpiScale; } + float GetX(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().x(); } + float GetY(size_t pointer_index) const override { return touchPoints.at(pointer_index).pos().y(); } float GetRawX(size_t pointer_index) const override { return touchPoints.at(pointer_index).screenPos().x(); } float GetRawY(size_t pointer_index) const override { return touchPoints.at(pointer_index).screenPos().y(); } float GetTouchMajor(size_t pointer_index) const override @@ -224,6 +225,8 @@ public: float GetPressure(size_t pointer_index) const override { return touchPoints.at(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; } @@ -241,20 +244,22 @@ private: const uint32_t eventId; int flags; int index; - float dpiScale; }; -bool isAccessibilityEnabled() { - // On Linux accessibility is disabled by default due to performance issues, - // and can be re-enabled by setting the QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment - // variable. For details, see QTBUG-59922. -#ifdef Q_OS_LINUX - static bool accessibility_enabled - = qEnvironmentVariableIsSet("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY"); -#else - const bool accessibility_enabled = true; -#endif - return accessibility_enabled; +static content::ScreenInfo screenInfoFromQScreen(QScreen *screen) +{ + content::ScreenInfo r; + if (screen) { + r.device_scale_factor = screen->devicePixelRatio(); + r.depth_per_component = 8; + r.depth = screen->depth(); + r.is_monochrome = (r.depth == 1); + r.rect = toGfx(screen->geometry()); + r.available_rect = toGfx(screen->availableGeometry()); + } else { + r.device_scale_factor = qGuiApp->devicePixelRatio(); + } + return r; } RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget) @@ -262,7 +267,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_gestureProvider(QtGestureProviderConfig(), this) , m_sendMotionActionDown(false) , m_touchMotionStarted(false) - , m_compositor(new Compositor(this)) + , m_compositor(new Compositor(widget)) , m_loadVisuallyCommittedState(NotCommitted) , m_adapterClient(0) , m_imeInProgress(false) @@ -273,20 +278,12 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget , m_cursorPosition(0) , m_emptyPreviousSelection(true) , m_wheelAckPending(false) - , m_pendingResize(false) , m_mouseWheelPhaseHandler(this) // This frame-sink id is based on what RenderWidgetHostViewChildFrame does: , m_frameSinkId(base::checked_cast<uint32_t>(widget->GetProcess()->GetID()), base::checked_cast<uint32_t>(widget->GetRoutingID())) { host()->SetView(this); -#ifndef QT_NO_ACCESSIBILITY - if (isAccessibilityEnabled()) { - QAccessible::installActivationObserver(this); - if (QAccessible::isActive()) - content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); - } -#endif // QT_NO_ACCESSIBILITY if (GetTextInputManager()) GetTextInputManager()->AddObserver(this); @@ -294,27 +291,32 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget const QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); m_imeHasHiddenTextCapability = context && context->hasCapability(QPlatformInputContext::HiddenTextCapability); - m_localSurfaceId = m_localSurfaceIdAllocator.GenerateId(); - if (host()->delegate() && host()->delegate()->GetInputEventRouter()) host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(GetFrameSinkId(), this); + + m_touchSelectionControllerClient.reset(new TouchSelectionControllerClientQt(this)); + ui::TouchSelectionController::Config config; + config.max_tap_duration = base::TimeDelta::FromMilliseconds(ui::GestureConfiguration::GetInstance()->long_press_time_in_ms()); + config.tap_slop = ui::GestureConfiguration::GetInstance()->max_touch_move_in_pixels_for_click(); + config.enable_longpress_drag_selection = false; + m_touchSelectionController.reset(new ui::TouchSelectionController(m_touchSelectionControllerClient.get(), config)); } RenderWidgetHostViewQt::~RenderWidgetHostViewQt() { QObject::disconnect(m_adapterClientDestroyedConnection); -#ifndef QT_NO_ACCESSIBILITY - QAccessible::removeActivationObserver(this); -#endif // QT_NO_ACCESSIBILITY if (text_input_manager_) text_input_manager_->RemoveObserver(this); + + m_touchSelectionController.reset(); + m_touchSelectionControllerClient.reset(); } void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegate) { m_delegate.reset(delegate); - m_compositor->setViewDelegate(delegate); + visualPropertiesChanged(); } void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterClient) @@ -341,30 +343,16 @@ void RenderWidgetHostViewQt::InitAsFullscreen(content::RenderWidgetHostView*) { } -void RenderWidgetHostViewQt::SetSize(const gfx::Size& size) +void RenderWidgetHostViewQt::SetSize(const gfx::Size &sizeInDips) { - int width = size.width(); - int height = size.height(); - - m_delegate->resize(width,height); + m_delegate->resize(sizeInDips.width(), sizeInDips.height()); } -void RenderWidgetHostViewQt::SetBounds(const gfx::Rect& screenRect) +void RenderWidgetHostViewQt::SetBounds(const gfx::Rect &windowRectInDips) { - // This is called when webkit has sent us a Move message. - if (IsPopup()) - m_delegate->move(toQt(screenRect.origin())); - SetSize(screenRect.size()); -} - -gfx::Size RenderWidgetHostViewQt::GetCompositorViewportPixelSize() const -{ - if (!m_delegate || !m_delegate->window() || !m_delegate->window()->screen()) - return gfx::Size(); - - const QScreen* screen = m_delegate->window()->screen(); - gfx::SizeF size = toGfx(m_delegate->screenRect().size()); - return gfx::ToCeiledSize(gfx::ScaleSize(size, screen->devicePixelRatio())); + DCHECK(IsPopup()); + m_delegate->move(toQt(windowRectInDips.origin())); + m_delegate->resize(windowRectInDips.width(), windowRectInDips.height()); } gfx::NativeView RenderWidgetHostViewQt::GetNativeView() const @@ -443,11 +431,7 @@ bool RenderWidgetHostViewQt::IsShowing() // Retrieve the bounds of the View, in screen coordinates. gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const { - QRectF p = m_delegate->contentsRect(); - float s = dpiScale(); - gfx::Point p1(floor(p.x() / s), floor(p.y() / s)); - gfx::Point p2(ceil(p.right() /s), ceil(p.bottom() / s)); - return gfx::BoundingRect(p1, p2); + return m_viewRectInDips; } void RenderWidgetHostViewQt::UpdateBackgroundColor() @@ -601,15 +585,13 @@ void RenderWidgetHostViewQt::DisplayCursor(const content::WebCursor &webCursor) } #if defined(USE_AURA) if (auraType != ui::CursorType::kNull) { - QWindow *window = m_delegate->window(); - qreal windowDpr = window ? window->devicePixelRatio() : 1.0f; int resourceId; gfx::Point hotspot; // GetCursorDataFor only knows hotspots for 1x and 2x cursor images, in physical pixels. - qreal hotspotDpr = windowDpr <= 1.0f ? 1.0f : 2.0f; + qreal hotspotDpr = m_screenInfo.device_scale_factor <= 1.0f ? 1.0f : 2.0f; if (ui::GetCursorDataFor(ui::CursorSize::kNormal, auraType, hotspotDpr, &resourceId, &hotspot)) { if (const gfx::ImageSkia *imageSkia = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resourceId)) { - QImage imageQt = toQImage(imageSkia->GetRepresentation(windowDpr)); + QImage imageQt = toQImage(imageSkia->GetRepresentation(m_screenInfo.device_scale_factor)); // Convert hotspot coordinates into device-independent pixels. qreal hotX = hotspot.x() / hotspotDpr; @@ -682,21 +664,18 @@ void RenderWidgetHostViewQt::DidCreateNewRendererCompositorFrameSink(viz::mojom: void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &local_surface_id, viz::CompositorFrame frame, base::Optional<viz::HitTestRegionList>) { bool scrollOffsetChanged = (m_lastScrollOffset != frame.metadata.root_scroll_offset); - bool contentsSizeChanged = (m_lastContentsSize != frame.metadata.root_layer_size); + bool contentsSizeChanged = (m_lastContentsSize != frame.metadata.scrollable_viewport_size); m_lastScrollOffset = frame.metadata.root_scroll_offset; - m_lastContentsSize = frame.metadata.root_layer_size; + m_lastContentsSize = frame.metadata.scrollable_viewport_size; // Force to process swap messages uint32_t frame_token = frame.metadata.frame_token; if (frame_token) OnFrameTokenChangedForView(frame_token); - // Support experimental.viewport.devicePixelRatio, see GetScreenInfo implementation below. - float dpiScale = this->dpiScale(); - if (dpiScale != 0 && dpiScale != 1) - frame.metadata.device_scale_factor /= dpiScale; - - m_compositor->submitFrame(std::move(frame)); + m_compositor->submitFrame( + std::move(frame), + base::BindOnce(&RenderWidgetHostViewQtDelegate::update, base::Unretained(m_delegate.get()))); if (m_loadVisuallyCommittedState == NotCommitted) { m_loadVisuallyCommittedState = DidFirstCompositorFrameSwap; @@ -709,31 +688,16 @@ void RenderWidgetHostViewQt::SubmitCompositorFrame(const viz::LocalSurfaceId &lo m_adapterClient->updateScrollPosition(toQt(m_lastScrollOffset)); if (contentsSizeChanged) m_adapterClient->updateContentsSize(toQt(m_lastContentsSize)); - - if (m_pendingResize && host()) { - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; - } } void RenderWidgetHostViewQt::GetScreenInfo(content::ScreenInfo *results) const { - QWindow *window = m_delegate->window(); - if (!window) - return; - GetScreenInfoFromNativeWindow(window, results); - - // Support experimental.viewport.devicePixelRatio - results->device_scale_factor *= dpiScale(); + *results = m_screenInfo; } gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow() { - if (!m_delegate->window()) - return gfx::Rect(); - - QRect r = m_delegate->window()->frameGeometry(); - return gfx::Rect(r.x(), r.y(), r.width(), r.height()); + return m_windowRectInDips; } void RenderWidgetHostViewQt::ClearCompositorFrame() @@ -902,7 +866,33 @@ void RenderWidgetHostViewQt::OnGestureEvent(const ui::GestureEventData& gesture) return; } - host()->ForwardGestureEvent(ui::CreateWebGestureEventFromGestureEventData(gesture)); + blink::WebGestureEvent event = ui::CreateWebGestureEventFromGestureEventData(gesture); + + if (m_touchSelectionController && m_touchSelectionControllerClient) { + switch (event.GetType()) { + case blink::WebInputEvent::kGestureLongPress: + m_touchSelectionController->HandleLongPressEvent(event.TimeStamp(), event.PositionInWidget()); + break; + case blink::WebInputEvent::kGestureTap: + m_touchSelectionController->HandleTapEvent(event.PositionInWidget(), event.data.tap.tap_count); + break; + case blink::WebInputEvent::kGestureScrollBegin: + m_touchSelectionControllerClient->onScrollBegin(); + break; + case blink::WebInputEvent::kGestureScrollEnd: + m_touchSelectionControllerClient->onScrollEnd(); + break; + default: + break; + } + } + + host()->ForwardGestureEvent(event); +} + +void RenderWidgetHostViewQt::DidStopFlinging() +{ + m_touchSelectionControllerClient->DidStopFlinging(); } viz::ScopedSurfaceIdAllocator RenderWidgetHostViewQt::DidUpdateVisualProperties(const cc::RenderFrameMetadata &metadata) @@ -915,27 +905,12 @@ viz::ScopedSurfaceIdAllocator RenderWidgetHostViewQt::DidUpdateVisualProperties( void RenderWidgetHostViewQt::OnDidUpdateVisualPropertiesComplete(const cc::RenderFrameMetadata &metadata) { - if (metadata.local_surface_id) - m_localSurfaceIdAllocator.UpdateFromChild(*metadata.local_surface_id); - - m_localSurfaceId = m_localSurfaceIdAllocator.GenerateId(); - host()->SendScreenRects(); - if (m_pendingResize) { - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; - } + synchronizeVisualProperties(metadata.local_surface_id); } QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) { - return m_compositor->updatePaintNode(oldNode); -} - -void RenderWidgetHostViewQt::notifyResize() -{ - m_pendingResize = true; - if (host()->SynchronizeVisualProperties()) - m_pendingResize = false; + return m_compositor->updatePaintNode(oldNode, m_delegate.get()); } void RenderWidgetHostViewQt::notifyShown() @@ -948,17 +923,26 @@ void RenderWidgetHostViewQt::notifyHidden() host()->WasHidden(); } -void RenderWidgetHostViewQt::windowBoundsChanged() +void RenderWidgetHostViewQt::visualPropertiesChanged() { - host()->SendScreenRects(); - if (m_delegate && m_delegate->window()) - host()->NotifyScreenInfoChanged(); -} + if (!m_delegate) + return; -void RenderWidgetHostViewQt::windowChanged() -{ - if (m_delegate && m_delegate->window()) - host()->NotifyScreenInfoChanged(); + gfx::Rect oldViewRect = m_viewRectInDips; + m_viewRectInDips = toGfx(m_delegate->viewGeometry().toAlignedRect()); + + gfx::Rect oldWindowRect = m_windowRectInDips; + QWindow *window = m_delegate->window(); + m_windowRectInDips = window ? toGfx(window->frameGeometry()) : gfx::Rect(); + + content::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) @@ -1164,14 +1148,9 @@ QList<QTouchEvent::TouchPoint> RenderWidgetHostViewQt::mapTouchPointIds(const QL return outputPoints; } -float RenderWidgetHostViewQt::dpiScale() const -{ - return m_adapterClient ? m_adapterClient->dpiScale() : 1.0; -} - bool RenderWidgetHostViewQt::IsPopup() const { - return popup_type_ != blink::kWebPopupTypeNone; + return widget_type_ == content::WidgetType::kPopup; } void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event) @@ -1313,9 +1292,9 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) } if (hasSelection) { - content::RenderFrameHostImpl *frameHost = static_cast<content::RenderFrameHostImpl *>(getFocusedFrameHost()); - if (frameHost) - frameHost->GetFrameInputHandler()->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); + content::mojom::FrameInputHandler *frameInputHandler = getFrameInputHandler(); + if (frameInputHandler) + frameInputHandler->SetEditableSelectionOffsets(selectionRange.start(), selectionRange.end()); } int replacementLength = ev->replacementLength(); @@ -1392,21 +1371,11 @@ void RenderWidgetHostViewQt::handleInputMethodQueryEvent(QInputMethodQueryEvent ev->accept(); } -#ifndef QT_NO_ACCESSIBILITY -void RenderWidgetHostViewQt::accessibilityActiveChanged(bool active) -{ - if (active) - content::BrowserAccessibilityStateImpl::GetInstance()->EnableAccessibility(); - else - content::BrowserAccessibilityStateImpl::GetInstance()->DisableAccessibility(); -} -#endif // QT_NO_ACCESSIBILITY - void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) { if (!m_wheelAckPending) { Q_ASSERT(m_pendingWheelEvents.isEmpty()); - blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(ev, dpiScale()); + blink::WebMouseWheelEvent webEvent = WebEventFactory::toWebWheelEvent(ev); m_wheelAckPending = (webEvent.phase != blink::WebMouseWheelEvent::kPhaseEnded); m_mouseWheelPhaseHandler.AddPhaseIfNeededAndScheduleEndEvent(webEvent, false); host()->ForwardWheelEvent(webEvent); @@ -1414,10 +1383,10 @@ void RenderWidgetHostViewQt::handleWheelEvent(QWheelEvent *ev) } if (!m_pendingWheelEvents.isEmpty()) { // Try to combine with this wheel event with the last pending one. - if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev, dpiScale())) + if (WebEventFactory::coalesceWebWheelEvent(m_pendingWheelEvents.last(), ev)) return; } - m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev, dpiScale())); + m_pendingWheelEvents.append(WebEventFactory::toWebWheelEvent(ev)); } void RenderWidgetHostViewQt::WheelEventAck(const blink::WebMouseWheelEvent &event, content::InputEventAckState /*ack_result*/) @@ -1452,16 +1421,11 @@ 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) { - host()->ForwardGestureEvent(WebEventFactory::toWebGestureEvent( - ev, - static_cast<double>(dpiScale()))); + host()->ForwardGestureEvent(WebEventFactory::toWebGestureEvent(ev)); } } #endif -Q_DECLARE_LOGGING_CATEGORY(QWEBENGINE_TOUCH_HANDLING); -Q_LOGGING_CATEGORY(QWEBENGINE_TOUCH_HANDLING, "qt.webengine.touch"); - void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) { // On macOS instead of handling touch events, we use the OS provided QNativeGestureEvents. @@ -1469,7 +1433,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) if (ev->spontaneous()) { return; } else { - qCWarning(QWEBENGINE_TOUCH_HANDLING) + VLOG(1) << "Sending simulated touch events to Chromium does not work properly on macOS. " "Consider using QNativeGestureEvents or QMouseEvents."; } @@ -1486,11 +1450,35 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) eventTimestamp += m_eventsToNowDelta; QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(ev->touchPoints()); + { + ui::MotionEvent::Action action; + switch (touchPoints[0].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; + } + + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), 0); + if (m_touchSelectionController->WillHandleTouchEvent(motionEvent)) { + ev->accept(); + return; + } + } switch (ev->type()) { case QEvent::TouchBegin: m_sendMotionActionDown = true; m_touchMotionStarted = true; + m_touchSelectionControllerClient->onTouchDown(); break; case QEvent::TouchUpdate: m_touchMotionStarted = true; @@ -1510,13 +1498,13 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) if (touchPoints.isEmpty()) touchPoints = m_previousTouchPoints; clearPreviousTouchMotionState(); - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, - ev->modifiers(), dpiScale()); + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::Action::CANCEL, ev->modifiers()); processMotionEvent(cancelEvent); return; } case QEvent::TouchEnd: clearPreviousTouchMotionState(); + m_touchSelectionControllerClient->onTouchUp(); break; default: break; @@ -1563,8 +1551,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) continue; } - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), dpiScale(), - i); + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); processMotionEvent(motionEvent); } } @@ -1581,7 +1568,7 @@ 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, dpiScale()); + blink::WebMouseEvent webEvent = WebEventFactory::toWebMouseEvent(event); if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown || webEvent.GetType() == blink::WebInputEvent::kMouseUp) && webEvent.button == blink::WebMouseEvent::Button::kNoButton) { // Blink can only handle the 3 main mouse-buttons and may assert when processing mouse-down for no button. @@ -1627,7 +1614,7 @@ void RenderWidgetHostViewQt::handlePointerEvent(T *event) void RenderWidgetHostViewQt::handleHoverEvent(QHoverEvent *ev) { - host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(ev, dpiScale())); + host()->ForwardMouseEvent(WebEventFactory::toWebMouseEvent(ev)); } void RenderWidgetHostViewQt::handleFocusEvent(QFocusEvent *ev) @@ -1654,11 +1641,6 @@ void RenderWidgetHostViewQt::SetNeedsBeginFrames(bool needs_begin_frames) m_compositor->setNeedsBeginFrames(needs_begin_frames); } -void RenderWidgetHostViewQt::OnBeginFrame(base::TimeTicks frame_time) -{ - host()->ProgressFlingIfNeeded(frame_time); -} - content::RenderFrameHost *RenderWidgetHostViewQt::getFocusedFrameHost() { content::RenderViewHostImpl *viewHost = content::RenderViewHostImpl::From(host()); @@ -1672,6 +1654,15 @@ content::RenderFrameHost *RenderWidgetHostViewQt::getFocusedFrameHost() return focusedFrame->current_frame_host(); } +content::mojom::FrameInputHandler *RenderWidgetHostViewQt::getFrameInputHandler() +{ + content::RenderFrameHostImpl *frameHost = static_cast<content::RenderFrameHostImpl *>(getFocusedFrameHost()); + if (!frameHost) + return nullptr; + + return frameHost->GetFrameInputHandler(); +} + ui::TextInputType RenderWidgetHostViewQt::getTextInputType() const { if (text_input_manager_ && text_input_manager_->GetTextInputState()) @@ -1696,7 +1687,7 @@ const viz::FrameSinkId &RenderWidgetHostViewQt::GetFrameSinkId() const const viz::LocalSurfaceId &RenderWidgetHostViewQt::GetLocalSurfaceId() const { - return m_localSurfaceId; + return m_localSurfaceIdAllocator.GetCurrentLocalSurfaceId(); } void RenderWidgetHostViewQt::TakeFallbackContentFrom(content::RenderWidgetHostView *view) @@ -1710,14 +1701,39 @@ void RenderWidgetHostViewQt::TakeFallbackContentFrom(content::RenderWidgetHostVi void RenderWidgetHostViewQt::EnsureSurfaceSynchronizedForLayoutTest() { - ++m_latestCaptureSequenceNumber; - if (host()) - host()->SynchronizeVisualProperties(); + NOTIMPLEMENTED(); } uint32_t RenderWidgetHostViewQt::GetCaptureSequenceNumber() const { - return m_latestCaptureSequenceNumber; + return 0; +} + +void RenderWidgetHostViewQt::ResetFallbackToFirstNavigationSurface() +{ + Q_UNIMPLEMENTED(); +} + +void RenderWidgetHostViewQt::OnRenderFrameMetadataChangedAfterActivation() +{ + content::RenderWidgetHostViewBase::OnRenderFrameMetadataChangedAfterActivation(); + + const cc::RenderFrameMetadata &metadata = host()->render_frame_metadata_provider()->LastRenderFrameMetadata(); + if (metadata.selection.start != m_selectionStart || metadata.selection.end != m_selectionEnd) { + m_selectionStart = metadata.selection.start; + m_selectionEnd = metadata.selection.end; + m_touchSelectionControllerClient->UpdateClientSelectionBounds(m_selectionStart, m_selectionEnd); + } +} + +void RenderWidgetHostViewQt::synchronizeVisualProperties(const base::Optional<viz::LocalSurfaceId> &childSurfaceId) +{ + if (childSurfaceId) + m_localSurfaceIdAllocator.UpdateFromChild(*childSurfaceId); + else + m_localSurfaceIdAllocator.GenerateId(); + + host()->SynchronizeVisualProperties(); } } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index a12ffe636..70b4f509e 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -50,14 +50,12 @@ #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/common/view_messages.h" #include "gpu/ipc/common/gpu_messages.h" #include "ui/events/gesture_detection/filtered_gesture_provider.h" #include "qtwebenginecoreglobal_p.h" #include <QMap> #include <QPoint> #include <QtGlobal> -#include <QtGui/qaccessible.h> #include <QtGui/QTouchEvent> QT_BEGIN_NAMESPACE @@ -67,11 +65,21 @@ QT_END_NAMESPACE namespace content { class RenderFrameHost; class RenderWidgetHostImpl; +namespace mojom { +class FrameInputHandler; +} +} + +namespace ui { +class TouchSelectionController; } namespace QtWebEngineCore { class Compositor; +class TouchHandleDrawableClient; +class TouchSelectionControllerClientQt; +class TouchSelectionMenuController; struct MultipleMouseClickHelper { @@ -94,9 +102,6 @@ class RenderWidgetHostViewQt , public ui::GestureProviderClient , public RenderWidgetHostViewQtDelegateClient , public base::SupportsWeakPtr<RenderWidgetHostViewQt> -#ifndef QT_NO_ACCESSIBILITY - , public QAccessible::ActivationObserver -#endif // QT_NO_ACCESSIBILITY , public content::TextInputManager::Observer { public: @@ -111,15 +116,14 @@ public: RenderWidgetHostViewQtDelegate *delegate() { return m_delegate.get(); } void setDelegate(RenderWidgetHostViewQtDelegate *delegate); + WebContentsAdapterClient *adapterClient() { return m_adapterClient; } void setAdapterClient(WebContentsAdapterClient *adapterClient); - void OnBeginFrame(base::TimeTicks frame_time); void InitAsChild(gfx::NativeView) override; void InitAsPopup(content::RenderWidgetHostView*, const gfx::Rect&) override; void InitAsFullscreen(content::RenderWidgetHostView*) override; void SetSize(const gfx::Size& size) override; void SetBounds(const gfx::Rect&) override; - gfx::Size GetCompositorViewportPixelSize() const override; gfx::NativeView GetNativeView() const override; gfx::NativeViewAccessible GetNativeViewAccessible() override; void Focus() override; @@ -163,17 +167,17 @@ public: void TakeFallbackContentFrom(content::RenderWidgetHostView *view) override; void EnsureSurfaceSynchronizedForLayoutTest() override; uint32_t GetCaptureSequenceNumber() const override; + void ResetFallbackToFirstNavigationSurface() override; + void DidStopFlinging() override; // Overridden from ui::GestureProviderClient. void OnGestureEvent(const ui::GestureEventData& gesture) override; // Overridden from RenderWidgetHostViewQtDelegateClient. QSGNode *updatePaintNode(QSGNode *) override; - void notifyResize() override; void notifyShown() override; void notifyHidden() override; - void windowBoundsChanged() override; - void windowChanged() override; + void visualPropertiesChanged() override; bool forwardEvent(QEvent *) override; QVariant inputMethodQuery(Qt::InputMethodQuery query) override; void closePopup() override; @@ -209,27 +213,37 @@ public: // Overridden from content::BrowserAccessibilityDelegate content::BrowserAccessibilityManager* CreateBrowserAccessibilityManager(content::BrowserAccessibilityDelegate* delegate, bool for_root_frame) override; -#ifndef QT_NO_ACCESSIBILITY - void accessibilityActiveChanged(bool active) override; -#endif // QT_NO_ACCESSIBILITY LoadVisuallyCommittedState getLoadVisuallyCommittedState() const { return m_loadVisuallyCommittedState; } void setLoadVisuallyCommittedState(LoadVisuallyCommittedState state) { m_loadVisuallyCommittedState = state; } + // Overridden from content::RenderFrameMetadataProvider::Observer + void OnRenderFrameMetadataChangedAfterActivation() override; + gfx::SizeF lastContentsSize() const { return m_lastContentsSize; } gfx::Vector2dF lastScrollOffset() const { return m_lastScrollOffset; } + ui::TouchSelectionController *getTouchSelectionController() const { return m_touchSelectionController.get(); } + TouchSelectionControllerClientQt *getTouchSelectionControllerClient() const { return m_touchSelectionControllerClient.get(); } + content::mojom::FrameInputHandler *getFrameInputHandler(); + ui::TextInputType getTextInputType() const; + private: void processMotionEvent(const ui::MotionEvent &motionEvent); void clearPreviousTouchMotionState(); QList<QTouchEvent::TouchPoint> mapTouchPointIds(const QList<QTouchEvent::TouchPoint> &inputPoints); - float dpiScale() const; - void updateNeedsBeginFramesInternal(); bool IsPopup() const; void selectionChanged(); content::RenderFrameHost *getFocusedFrameHost(); - ui::TextInputType getTextInputType() const; + + void synchronizeVisualProperties(const base::Optional<viz::LocalSurfaceId> &childSurfaceId); + + // Geometry of the view in screen DIPs. + gfx::Rect m_viewRectInDips; + // Geometry of the window, including frame, in screen DIPs. + gfx::Rect m_windowRectInDips; + content::ScreenInfo m_screenInfo; ui::FilteredGestureProvider m_gestureProvider; base::TimeDelta m_eventsToNowDelta; @@ -252,7 +266,6 @@ private: gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; - viz::LocalSurfaceId m_localSurfaceId; viz::ParentLocalSurfaceIdAllocator m_localSurfaceIdAllocator; uint m_imState; @@ -265,13 +278,16 @@ private: bool m_imeHasHiddenTextCapability; bool m_wheelAckPending; - bool m_pendingResize; QList<blink::WebMouseWheelEvent> m_pendingWheelEvents; content::MouseWheelPhaseHandler m_mouseWheelPhaseHandler; viz::FrameSinkId m_frameSinkId; - uint32_t m_latestCaptureSequenceNumber = 0u; std::string m_editCommand; + + std::unique_ptr<TouchSelectionControllerClientQt> m_touchSelectionControllerClient; + std::unique_ptr<ui::TouchSelectionController> m_touchSelectionController; + gfx::SelectionBound m_selectionStart; + gfx::SelectionBound m_selectionEnd; }; } // 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 5ce595502..e2c98360d 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -78,11 +78,9 @@ class QWEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient { public: virtual ~RenderWidgetHostViewQtDelegateClient() { } virtual QSGNode *updatePaintNode(QSGNode *) = 0; - virtual void notifyResize() = 0; virtual void notifyShown() = 0; virtual void notifyHidden() = 0; - virtual void windowBoundsChanged() = 0; - virtual void windowChanged() = 0; + virtual void visualPropertiesChanged() = 0; virtual bool forwardEvent(QEvent *) = 0; virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) = 0; virtual void closePopup() = 0; @@ -92,8 +90,7 @@ class QWEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate { public: virtual ~RenderWidgetHostViewQtDelegate() { } virtual void initAsPopup(const QRect&) = 0; - virtual QRectF screenRect() const = 0; - virtual QRectF contentsRect() const = 0; + virtual QRectF viewGeometry() const = 0; virtual void setKeyboardFocus() = 0; virtual bool hasKeyboardFocus() = 0; virtual void lockMouse() = 0; diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 403448b91..296e78b07 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -40,6 +40,8 @@ #include "renderer/content_renderer_client_qt.h" #include "common/qt_messages.h" +#include "extensions/buildflags/buildflags.h" +#include "printing/buildflags/buildflags.h" #include "renderer/content_settings_observer_qt.h" #include "base/strings/string_split.h" #if QT_CONFIG(webengine_spellchecker) @@ -85,6 +87,12 @@ #if QT_CONFIG(webengine_webchannel) #include "renderer/web_channel_ipc_transport.h" #endif + +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "common/extensions/extensions_client_qt.h" +#include "extensions/extensions_renderer_client_qt.h" +#endif //ENABLE_EXTENSIONS + #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/connector.h" @@ -106,6 +114,10 @@ static const char kHttpErrorDomain[] = "http"; ContentRendererClientQt::ContentRendererClientQt() { +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionsClient::Set(extensions::ExtensionsClientQt::GetInstance()); + extensions::ExtensionsRendererClient::Set(ExtensionsRendererClientQt::GetInstance()); +#endif } ContentRendererClientQt::~ContentRendererClientQt() @@ -137,7 +149,11 @@ void ContentRendererClientQt::RenderThreadStarted() // Allow XMLHttpRequests from qrc to file. blink::WebURL qrc(blink::KURL("qrc:")); blink::WebString file(blink::WebString::FromASCII("file")); - blink::WebSecurityPolicy::AddOriginAccessWhitelistEntry(qrc, file, blink::WebString(), true); + blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(qrc, file, blink::WebString(), true, + network::mojom::CORSOriginAccessMatchPriority::kDefaultPriority); +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RenderThreadStarted(); +#endif } void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view) @@ -149,11 +165,12 @@ void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame) { - new QtWebEngineCore::RenderFrameObserverQt(render_frame); + QtWebEngineCore::RenderFrameObserverQt *render_frame_observer = new QtWebEngineCore::RenderFrameObserverQt(render_frame); #if QT_CONFIG(webengine_webchannel) if (render_frame->IsMainFrame()) new WebChannelIPCTransport(render_frame); #endif + UserResourceController::instance()->renderFrameCreated(render_frame); new QtWebEngineCore::ContentSettingsObserverQt(render_frame); @@ -166,17 +183,41 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_fr render_frame, base::WrapUnique(new PrintWebViewHelperDelegateQt())); #endif // QT_CONFIG(webengine_printing_and_pdf) +#if BUILDFLAG(ENABLE_EXTENSIONS) + auto registry = std::make_unique<service_manager::BinderRegistry>(); + ExtensionsRendererClientQt::GetInstance()->RenderFrameCreated(render_frame, render_frame_observer->registry()); +#endif } -void ContentRendererClientQt::RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) +void ContentRendererClientQt::RunScriptsAtDocumentStart(content::RenderFrame *render_frame) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RunScriptsAtDocumentStart(render_frame); + // |render_frame| might be dead by now. +#endif +} + +void ContentRendererClientQt::RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) { // Check whether the render_frame has been created and has not been detached yet. // Otherwise the WebFrame is not available. RenderFrameObserverQt *render_frame_observer = RenderFrameObserverQt::Get(render_frame); - if (!render_frame_observer || render_frame_observer->isFrameDetached()) - return; // The frame is invisible to scripts. - UserResourceController::instance()->RunScriptsAtDocumentEnd(render_frame); + if (render_frame_observer && !render_frame_observer->isFrameDetached()) + UserResourceController::instance()->RunScriptsAtDocumentEnd(render_frame); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RunScriptsAtDocumentEnd(render_frame); + // |render_frame| might be dead by now. +#endif +} + +void ContentRendererClientQt::RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->RunScriptsAtDocumentIdle(render_frame); + // |render_frame| might be dead by now. +#endif } bool ContentRendererClientQt::HasErrorPage(int httpStatusCode) @@ -230,6 +271,7 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF error_page::LocalizedError::GetStrings( error.reason(), error.domain(), error.url(), isPost, error.stale_copy_in_cache(), false, false, + error_page::LocalizedError::OfflineContentOnNetErrorFeatureState::kDisabled, locale, std::unique_ptr<error_page::ErrorPageParams>(), &errorStrings); resourceId = IDR_NET_ERROR_HTML; @@ -259,6 +301,29 @@ blink::WebPrescientNetworking *ContentRendererClientQt::GetPrescientNetworking() return m_prescientNetworkingDispatcher.get(); } +bool ContentRendererClientQt::OverrideCreatePlugin( + content::RenderFrame* render_frame, + const blink::WebPluginParams& params, blink::WebPlugin** plugin) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (!ExtensionsRendererClientQt::GetInstance()->OverrideCreatePlugin(render_frame, params)) + return false; +#endif //ENABLE_EXTENSIONS + return content::ContentRendererClient::OverrideCreatePlugin(render_frame, params, plugin); +} + +content::BrowserPluginDelegate* ContentRendererClientQt::CreateBrowserPluginDelegate(content::RenderFrame *render_frame, + const content::WebPluginInfo &info, + const std::string &mime_type, + const GURL &original_url) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + return ExtensionsRendererClientQt::GetInstance()->CreateBrowserPluginDelegate(render_frame, info, mime_type, original_url); +#else + return nullptr; +#endif +} + void ContentRendererClientQt::OnStart() { context()->connector()->BindConnectorRequest(std::move(m_connectorRequest)); @@ -487,6 +552,21 @@ void ContentRendererClientQt::InitSpellCheck() } #endif +void ContentRendererClientQt::WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + ExtensionsRendererClientQt::GetInstance()->WillSendRequest(frame, transition_type, url, initiator_origin, new_url, attach_same_site_cookies); + if (!new_url->is_empty()) + return; +#endif + content::ContentRendererClient::WillSendRequest(frame, transition_type, url, initiator_origin, new_url, attach_same_site_cookies); +} + void ContentRendererClientQt::CreateRendererService(service_manager::mojom::ServiceRequest service_request) { m_serviceContext = std::make_unique<service_manager::ServiceContext>( diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h index 2a353caa6..8955a3797 100644 --- a/src/core/renderer/content_renderer_client_qt.h +++ b/src/core/renderer/content_renderer_client_qt.h @@ -96,7 +96,20 @@ public: blink::WebPrescientNetworking* GetPrescientNetworking() override; void AddSupportedKeySystems(std::vector<std::unique_ptr<media::KeySystemProperties>>* key_systems) override; - void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override; + void RunScriptsAtDocumentStart(content::RenderFrame *render_frame) override; + void RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) override; + void RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) override; + bool OverrideCreatePlugin(content::RenderFrame* render_frame, + const blink::WebPluginParams& params, blink::WebPlugin** plugin) override; + content::BrowserPluginDelegate* CreateBrowserPluginDelegate(content::RenderFrame* render_frame, + const content::WebPluginInfo& info, const std::string& mime_type, const GURL& original_url) override; + + void WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies) override; void CreateRendererService(service_manager::mojom::ServiceRequest service_request) override; diff --git a/src/core/renderer/content_settings_observer_qt.cpp b/src/core/renderer/content_settings_observer_qt.cpp index 045098457..c1495e1fe 100644 --- a/src/core/renderer/content_settings_observer_qt.cpp +++ b/src/core/renderer/content_settings_observer_qt.cpp @@ -93,8 +93,8 @@ bool ContentSettingsObserverQt::OnMessageReceived(const IPC::Message& message) return handled; } -void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool /*is_new_navigation*/, - bool is_same_document_navigation) +void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool is_same_document_navigation, + ui::PageTransition /*transition*/) { blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); if (frame->Parent()) diff --git a/src/core/renderer/content_settings_observer_qt.h b/src/core/renderer/content_settings_observer_qt.h index 981655f20..a9bee3d2d 100644 --- a/src/core/renderer/content_settings_observer_qt.h +++ b/src/core/renderer/content_settings_observer_qt.h @@ -80,8 +80,8 @@ private: // RenderFrameObserver implementation: bool OnMessageReceived(const IPC::Message &message) override; - void DidCommitProvisionalLoad(bool is_new_navigation, - bool is_same_document_navigation) override; + void DidCommitProvisionalLoad(bool is_same_document_navigation, + ui::PageTransition transition) override; void OnDestruct() override; // Message handlers. diff --git a/src/core/chromium_overrides.h b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.cpp index b27bf309c..418429330 100644 --- a/src/core/chromium_overrides.h +++ b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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,18 +37,16 @@ ** ****************************************************************************/ -#ifndef CHROMIUM_OVERRIDES_H -#define CHROMIUM_OVERRIDES_H +#include "extensions_dispatcher_delegate_qt.h" -#include "content/public/common/screen_info.h" -#include <QtGlobal> +namespace QtWebEngineCore { -QT_BEGIN_NAMESPACE -class QWindow; -QT_END_NAMESPACE +ExtensionsDispatcherDelegateQt::ExtensionsDispatcherDelegateQt() +{ +} -namespace QtWebEngineCore { -void GetScreenInfoFromNativeWindow(QWindow* window, content::ScreenInfo* results); +ExtensionsDispatcherDelegateQt::~ExtensionsDispatcherDelegateQt() +{ } -#endif +} //namespace QtWebEngineCore diff --git a/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.h b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.h new file mode 100644 index 000000000..25aa18e71 --- /dev/null +++ b/src/core/renderer/extensions/extensions_dispatcher_delegate_qt.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef EXTENSIONSDISPATCHERDELEGATEQT_H +#define EXTENSIONSDISPATCHERDELEGATEQT_H + +#include "base/macros.h" +#include "extensions/renderer/dispatcher_delegate.h" + +namespace QtWebEngineCore { + +class ExtensionsDispatcherDelegateQt : public extensions::DispatcherDelegate +{ +public: + ExtensionsDispatcherDelegateQt(); + ~ExtensionsDispatcherDelegateQt() override; + +private: + DISALLOW_COPY_AND_ASSIGN(ExtensionsDispatcherDelegateQt); +}; + +} // namespace QtWebEngineCore + +#endif // EXTENSIONSDISPATCHERDELEGATEQT_H diff --git a/src/core/renderer/extensions/extensions_renderer_client_qt.cpp b/src/core/renderer/extensions/extensions_renderer_client_qt.cpp new file mode 100644 index 000000000..c41d9e6a4 --- /dev/null +++ b/src/core/renderer/extensions/extensions_renderer_client_qt.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// based on chrome/renderer/extensions/chrome_extensions_renderer_client.cc: +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions_renderer_client_qt.h" + +#include "extensions_dispatcher_delegate_qt.h" +#include "renderer_permissions_policy_delegate_qt.h" +#include "resource_request_policy_qt.h" + +#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "content/public/common/content_constants.h" +#include "content/public/common/content_switches.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_thread.h" +#include "extensions/common/constants.h" +#include "extensions/common/switches.h" +#include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/extension_frame_helper.h" +#include "extensions/renderer/extensions_render_frame_observer.h" +#include "extensions/renderer/guest_view/extensions_guest_view_container.h" +#include "extensions/renderer/guest_view/extensions_guest_view_container_dispatcher.h" +#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h" +#include "extensions/renderer/renderer_extension_registry.h" +#include "extensions/renderer/script_context.h" +#include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/public/web/web_plugin_params.h" + +namespace chrome { +const char kExtensionInvalidRequestURL[] = "chrome-extension://invalid/"; +const char kExtensionResourceInvalidRequestURL[] = "chrome-extension-resource://invalid/"; +} + +namespace QtWebEngineCore { + +ExtensionsRendererClientQt::ExtensionsRendererClientQt() +{ +} + +ExtensionsRendererClientQt::~ExtensionsRendererClientQt() +{ +} + +// Returns true if the current render process was launched incognito. +bool ExtensionsRendererClientQt::IsIncognitoProcess() const +{ + return false; +} + +// Returns the lowest isolated world ID available to extensions. +// Must be greater than 0. See blink::WebFrame::executeScriptInIsolatedWorld +// (third_party/WebKit/public/web/WebFrame.h) for additional context. +int ExtensionsRendererClientQt::GetLowestIsolatedWorldId() const +{ + return 257; +} + +// static +ExtensionsRendererClientQt *ExtensionsRendererClientQt::GetInstance() +{ + static base::LazyInstance<ExtensionsRendererClientQt>::Leaky client = + LAZY_INSTANCE_INITIALIZER; + return client.Pointer(); +} + +extensions::Dispatcher *ExtensionsRendererClientQt::GetDispatcher() +{ + return extension_dispatcher_.get(); +} + +void ExtensionsRendererClientQt::OnExtensionLoaded(const extensions::Extension &extension) +{ + resource_request_policy_->OnExtensionLoaded(extension); +} + +void ExtensionsRendererClientQt::OnExtensionUnloaded(const extensions::ExtensionId &extension_id) +{ + resource_request_policy_->OnExtensionUnloaded(extension_id); +} + +void ExtensionsRendererClientQt::RenderThreadStarted() +{ + content::RenderThread *thread = content::RenderThread::Get(); + // ChromeRenderViewTest::SetUp() creates its own ExtensionDispatcher and + // injects it using SetExtensionDispatcher(). Don't overwrite it. + if (!extension_dispatcher_) + extension_dispatcher_.reset(new extensions::Dispatcher(std::make_unique<ExtensionsDispatcherDelegateQt>())); + permissions_policy_delegate_.reset(new RendererPermissionsPolicyDelegateQt(extension_dispatcher_.get())); + resource_request_policy_.reset(new extensions::ResourceRequestPolicyQt(extension_dispatcher_.get())); + guest_view_container_dispatcher_.reset(new extensions::ExtensionsGuestViewContainerDispatcher()); + + thread->AddObserver(extension_dispatcher_.get()); + thread->AddObserver(guest_view_container_dispatcher_.get()); +} + +void ExtensionsRendererClientQt::RenderFrameCreated(content::RenderFrame *render_frame, + service_manager::BinderRegistry *registry) +{ + new extensions::ExtensionsRenderFrameObserver(render_frame, registry); + new extensions::ExtensionFrameHelper(render_frame, + extension_dispatcher_.get()); + extension_dispatcher_->OnRenderFrameCreated(render_frame); +} + +bool ExtensionsRendererClientQt::OverrideCreatePlugin(content::RenderFrame *render_frame, + const blink::WebPluginParams ¶ms) +{ + if (params.mime_type.Utf8() != content::kBrowserPluginMimeType) + return true; + bool guest_view_api_available = false; + return !guest_view_api_available; +} + +void ExtensionsRendererClientQt::WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies) +{ + if (url.ProtocolIs(extensions::kExtensionScheme) && + !resource_request_policy_->CanRequestResource(url, frame, transition_type)) { + *new_url = GURL(chrome::kExtensionInvalidRequestURL); + } +} + +bool ExtensionsRendererClientQt::ShouldFork(blink::WebLocalFrame *frame, + const GURL &url, + bool is_initial_navigation, + bool is_server_redirect, + bool *send_referrer) +{ + return false; // TODO: Fix this to a sensible value +} + +content::BrowserPluginDelegate *ExtensionsRendererClientQt::CreateBrowserPluginDelegate(content::RenderFrame *render_frame, + const content::WebPluginInfo &info, + const std::string &mime_type, + const GURL &original_url) +{ + if (mime_type == content::kBrowserPluginMimeType) + return new extensions::ExtensionsGuestViewContainer(render_frame); + return new extensions::MimeHandlerViewContainer(render_frame, info, mime_type, original_url); +} + +void ExtensionsRendererClientQt::RunScriptsAtDocumentStart(content::RenderFrame *render_frame) +{ + extension_dispatcher_->RunScriptsAtDocumentStart(render_frame); +} + +void ExtensionsRendererClientQt::RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) +{ + extension_dispatcher_->RunScriptsAtDocumentEnd(render_frame); +} + +void ExtensionsRendererClientQt::RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) +{ + extension_dispatcher_->RunScriptsAtDocumentIdle(render_frame); +} + + +} // namespace QtWebEngineCore diff --git a/src/core/renderer/extensions/extensions_renderer_client_qt.h b/src/core/renderer/extensions/extensions_renderer_client_qt.h new file mode 100644 index 000000000..2d45d255a --- /dev/null +++ b/src/core/renderer/extensions/extensions_renderer_client_qt.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef EXTENSIONSRENDERERCLIENTQT_H +#define EXTENSIONSRENDERERCLIENTQT_H + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "extensions/renderer/extensions_renderer_client.h" +#include "services/service_manager/public/cpp/binder_registry.h" +#include "ui/base/page_transition_types.h" + +class GURL; + +namespace blink { +class WebLocalFrame; +struct WebPluginParams; +class WebURL; +} + +namespace content { +class BrowserPluginDelegate; +class RenderFrame; +class RenderView; +struct WebPluginInfo; +} + +namespace url { +class Origin; +} + +namespace extensions { +class Dispatcher; +class ExtensionsGuestViewContainerDispatcher; +class ResourceRequestPolicyQt; +} + +namespace QtWebEngineCore { + +class ExtensionsDispatcherDelegateQt; +class RendererPermissionsPolicyDelegateQt; + +class ExtensionsRendererClientQt : public extensions::ExtensionsRendererClient +{ +public: + ExtensionsRendererClientQt(); + ~ExtensionsRendererClientQt() override; + + // extensions::ExtensionsRendererClient implementation. + bool IsIncognitoProcess() const override; + int GetLowestIsolatedWorldId() const override; + extensions::Dispatcher *GetDispatcher() override; + void OnExtensionLoaded(const extensions::Extension &extension) override; + void OnExtensionUnloaded(const extensions::ExtensionId &extension_id) override; + + // Match ContentRendererClientQt's method names... + void RenderThreadStarted(); + void RenderFrameCreated(content::RenderFrame *, service_manager::BinderRegistry *); + bool OverrideCreatePlugin(content::RenderFrame *render_frame, + const blink::WebPluginParams ¶ms); + void WillSendRequest(blink::WebLocalFrame *frame, + ui::PageTransition transition_type, + const blink::WebURL &url, + const url::Origin *initiator_origin, + GURL *new_url, + bool *attach_same_site_cookies); + + static bool ShouldFork(blink::WebLocalFrame *frame, + const GURL &url, + bool is_initial_navigation, + bool is_server_redirect, + bool *send_referrer); + static content::BrowserPluginDelegate *CreateBrowserPluginDelegate(content::RenderFrame *render_frame, + const content::WebPluginInfo &info, + const std::string &mime_type, + const GURL &original_url); + + void RunScriptsAtDocumentStart(content::RenderFrame *render_frame); + void RunScriptsAtDocumentEnd(content::RenderFrame *render_frame); + void RunScriptsAtDocumentIdle(content::RenderFrame *render_frame); + + extensions::Dispatcher *extension_dispatcher() + { return extension_dispatcher_.get(); } + + static ExtensionsRendererClientQt *GetInstance(); + +private: + std::unique_ptr<ExtensionsDispatcherDelegateQt> extension_dispatcher_delegate_; + std::unique_ptr<RendererPermissionsPolicyDelegateQt> permissions_policy_delegate_; + std::unique_ptr<extensions::Dispatcher> extension_dispatcher_; + std::unique_ptr<extensions::ExtensionsGuestViewContainerDispatcher> guest_view_container_dispatcher_; + std::unique_ptr<extensions::ResourceRequestPolicyQt> resource_request_policy_; +}; + +} // namespace QtWebEngineCore + +#endif // EXTENSIONSRENDERERCLIENTQT_H diff --git a/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.cpp b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.cpp new file mode 100644 index 000000000..39412b76c --- /dev/null +++ b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 "renderer_permissions_policy_delegate_qt.h" + +#include "extensions/common/constants.h" +#include "extensions/common/extensions_client.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/switches.h" +#include "extensions/renderer/dispatcher.h" + +namespace QtWebEngineCore { + +RendererPermissionsPolicyDelegateQt::RendererPermissionsPolicyDelegateQt(extensions::Dispatcher *dispatcher) + : m_dispatcher(dispatcher) +{ + extensions::PermissionsData::SetPolicyDelegate(this); +} + +RendererPermissionsPolicyDelegateQt::~RendererPermissionsPolicyDelegateQt() +{ + extensions::PermissionsData::SetPolicyDelegate(nullptr); +} + +bool RendererPermissionsPolicyDelegateQt::IsRestrictedUrl(const GURL &, std::string *) +{ + return false; +} + +} // namespace QtWebEngineCore diff --git a/src/core/net/qrc_protocol_handler_qt.h b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.h index f2849c1ef..e2af47657 100644 --- a/src/core/net/qrc_protocol_handler_qt.h +++ b/src/core/renderer/extensions/renderer_permissions_policy_delegate_qt.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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,34 +37,32 @@ ** ****************************************************************************/ -#ifndef QRC_PROTOCOL_HANDLER_QT_H_ -#define QRC_PROTOCOL_HANDLER_QT_H_ +#ifndef RENDERERPERMISSIONSPOLICYDELEGATEQT_H +#define RENDERERPERMISSIONSPOLICYDELEGATEQT_H -#include "net/url_request/url_request_job_factory.h" +#include "base/macros.h" +#include "extensions/common/permissions/permissions_data.h" -namespace net { - -class NetworkDelegate; -class URLRequestJob; - -} // namespace +namespace extensions { +class Dispatcher; +} namespace QtWebEngineCore { -extern const char kQrcSchemeQt[]; - -// Implements a ProtocolHandler for qrc file jobs. If |network_delegate_| is NULL, -// then all file requests will fail with ERR_ACCESS_DENIED. -class QrcProtocolHandlerQt : public net::URLRequestJobFactory::ProtocolHandler { - +class RendererPermissionsPolicyDelegateQt : public extensions::PermissionsData::PolicyDelegate +{ public: - QrcProtocolHandlerQt(); - net::URLRequestJob *MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const override; + explicit RendererPermissionsPolicyDelegateQt(extensions::Dispatcher *dispatcher); + ~RendererPermissionsPolicyDelegateQt() override; + + bool IsRestrictedUrl(const GURL &, std::string *) override; private: - DISALLOW_COPY_AND_ASSIGN(QrcProtocolHandlerQt); + extensions::Dispatcher *m_dispatcher; + + DISALLOW_COPY_AND_ASSIGN(RendererPermissionsPolicyDelegateQt); }; } // namespace QtWebEngineCore -#endif // QRC_PROTOCOL_HANDLER_QT_H_ +#endif // RENDERERPERMISSIONSPOLICYDELEGATEQT_H diff --git a/src/core/renderer/extensions/resource_request_policy_qt.cpp b/src/core/renderer/extensions/resource_request_policy_qt.cpp new file mode 100644 index 000000000..dc5a90120 --- /dev/null +++ b/src/core/renderer/extensions/resource_request_policy_qt.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// based on chrome/renderer/extensions/resource_request_policy.cc: +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "resource_request_policy_qt.h" + +#include "base/strings/stringprintf.h" +#include "chrome/common/url_constants.h" +#include "extensions/common/constants.h" +#include "extensions/common/manifest_handlers/web_accessible_resources_info.h" +#include "extensions/common/manifest_handlers/webview_info.h" +#include "extensions/renderer/dispatcher.h" +#include "third_party/blink/public/web/web_console_message.h" +#include "third_party/blink/public/web/web_document.h" +#include "third_party/blink/public/web/web_local_frame.h" + +namespace extensions { +ResourceRequestPolicyQt::ResourceRequestPolicyQt(Dispatcher *dispatcher) + : m_dispatcher(dispatcher) +{ +} + +void ResourceRequestPolicyQt::OnExtensionLoaded(const Extension &extension) +{ + if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) + || WebviewInfo::HasWebviewAccessibleResources(extension, m_dispatcher->webview_partition_id()) +// // Hosted app icons are accessible. +// // TODO(devlin): Should we incorporate this into +// // WebAccessibleResourcesInfo? +// || (extension.is_hosted_app() && !IconsInfo::GetIcons(&extension).empty()) + ) { + m_web_accessible_ids.insert(extension.id()); + } +} + +void ResourceRequestPolicyQt::OnExtensionUnloaded(const ExtensionId &extension_id) +{ + m_web_accessible_ids.erase(extension_id); +} + +// Returns true if the chrome-extension:// |resource_url| can be requested +// from |frame_url|. In some cases this decision is made based upon how +// this request was generated. Web triggered transitions are more restrictive +// than those triggered through UI. +bool ResourceRequestPolicyQt::CanRequestResource(const GURL &resource_url, + blink::WebLocalFrame *frame, + ui::PageTransition transition_type) +{ + CHECK(resource_url.SchemeIs(kExtensionScheme)); + + GURL frame_url = frame->GetDocument().Url(); + + // The page_origin may be GURL("null") for unique origins like data URLs, + // but this is ok for the checks below. We only care if it matches the + // current extension or has a devtools scheme. + GURL page_origin = url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(); + + GURL extension_origin = resource_url.GetOrigin(); + + // We always allow loads in the following cases, regardless of web accessible + // resources: + + // Empty urls (needed for some edge cases when we have empty urls). + if (frame_url.is_empty()) + return true; + + // Extensions requesting their own resources (frame_url check is for images, + // page_url check is for iframes). + // TODO(devlin): We should be checking the ancestor chain, not just the + // top-level frame. Additionally, we should be checking the security origin + // of the frame, to account for about:blank subframes being scripted by an + // extension parent (though we'll still need the frame origin check for + // sandboxed frames). + if (frame_url.GetOrigin() == extension_origin || page_origin == extension_origin) + return true; + + if (!ui::PageTransitionIsWebTriggerable(transition_type)) + return true; + + // Unreachable web page error page (to allow showing the icon of the + // unreachable app on this page). + if (frame_url == content::kUnreachableWebDataURL) + return true; + + bool is_dev_tools = page_origin.SchemeIs(content::kChromeDevToolsScheme); + // Note: we check |web_accessible_ids_| (rather than first looking up the + // extension in the registry and checking that) to be more resistant against + // timing attacks. This way, determining access for an extension that isn't + // installed takes the same amount of time as determining access for an + // extension with no web accessible resources. We aren't worried about any + // extensions with web accessible resources, since those are inherently + // identifiable. + if (!is_dev_tools && !m_web_accessible_ids.count(extension_origin.host())) + return false; + + const Extension* extension = RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(resource_url); + if (is_dev_tools) { + // Allow the load in the case of a non-existent extension. We'll just get a + // 404 from the browser process. + // TODO(devlin): Can this happen? Does devtools potentially make requests + // to non-existent extensions? + if (!extension) + return true; +// // Devtools (chrome-extension:// URLs are loaded into frames of devtools to +// // support the devtools extension APIs). +// if (!chrome_manifest_urls::GetDevToolsPage(extension).is_empty()) +// return true; + } + + DCHECK(extension); + + // Disallow loading of packaged resources for hosted apps. We don't allow + // hybrid hosted/packaged apps. The one exception is access to icons, since + // some extensions want to be able to do things like create their own + // launchers. + base::StringPiece resource_root_relative_path = + resource_url.path_piece().empty() ? base::StringPiece() + : resource_url.path_piece().substr(1); + if (extension->is_hosted_app() /*&& !IconsInfo::GetIcons(extension).ContainsPath(resource_root_relative_path)*/) { + LOG(ERROR) << "Denying load of " << resource_url.spec() << " from " + << "hosted app."; + return false; + } + + // Disallow loading of extension resources which are not explicitly listed + // as web or WebView accessible if the manifest version is 2 or greater. + if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(extension, resource_url.path()) && + !WebviewInfo::IsResourceWebviewAccessible(extension, m_dispatcher->webview_partition_id(), resource_url.path())) + { + std::string message = base::StringPrintf( + "Denying load of %s. Resources must be listed in the " + "web_accessible_resources manifest key in order to be loaded by " + "pages outside the extension.", + resource_url.spec().c_str()); + frame->AddMessageToConsole(blink::WebConsoleMessage(blink::WebConsoleMessage::kLevelError, blink::WebString::FromUTF8(message))); + return false; + } + + return true; +} + +} // namespace extensions diff --git a/src/core/renderer/extensions/resource_request_policy_qt.h b/src/core/renderer/extensions/resource_request_policy_qt.h new file mode 100644 index 000000000..e6d4e79bb --- /dev/null +++ b/src/core/renderer/extensions/resource_request_policy_qt.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef RESOURCEREQUESTPOLICYQT_H +#define RESOURCEREQUESTPOLICYQT_H + +#include <set> + +#include "base/macros.h" +#include "extensions/common/extension_id.h" +#include "ui/base/page_transition_types.h" + +class GURL; + +namespace blink { +class WebLocalFrame; +} + +namespace extensions { + +class Dispatcher; +class Extension; + +// Encapsulates the policy for when chrome-extension:// and +// chrome-extension-resource:// URLs can be requested. +class ResourceRequestPolicyQt +{ +public: + explicit ResourceRequestPolicyQt(Dispatcher *dispatcher); + + void OnExtensionLoaded(const Extension &extension); + void OnExtensionUnloaded(const ExtensionId &extension); + + // Returns true if the chrome-extension:// |resource_url| can be requested + // from |frame_url|. In some cases this decision is made based upon how + // this request was generated. Web triggered transitions are more restrictive + // than those triggered through UI. + bool CanRequestResource(const GURL &resource_url, + blink::WebLocalFrame *frame, + ui::PageTransition transition_type); + +private: + Dispatcher *m_dispatcher; + + // The set of extension IDs with any potentially web- or webview-accessible + // resources. + std::set<ExtensionId> m_web_accessible_ids; + + DISALLOW_COPY_AND_ASSIGN(ResourceRequestPolicyQt); +}; +} // namespace extensions + +#endif // RESOURCEREQUESTPOLICYQT_H diff --git a/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp index 4acf69043..33c744f13 100644 --- a/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp +++ b/src/core/renderer/pepper/pepper_renderer_host_factory_qt.cpp @@ -44,9 +44,13 @@ #include "pepper_renderer_host_factory_qt.h" #include "pepper_flash_renderer_host_qt.h" +#include "qtwebenginecoreglobal_p.h" #include "base/memory/ptr_util.h" #include "chrome/renderer/pepper/pepper_flash_font_file_host.h" +#if QT_CONFIG(webengine_printing_and_pdf) +#include "components/pdf/renderer/pepper_pdf_host.h" +#endif // QT_CONFIG(webengine_printing_and_pdf) #include "content/public/renderer/renderer_ppapi_host.h" #include "ppapi/host/ppapi_host.h" #include "ppapi/host/resource_host.h" @@ -100,7 +104,7 @@ std::unique_ptr<ppapi::host::ResourceHost> PepperRendererHostFactoryQt::CreateRe // We should either rename PPB_FlashFont_File to PPB_FontFile_Private or get // rid of its use in PDF if possible. if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_FLASH) - || host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) { + || host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PDF)) { switch (message.type()) { case PpapiHostMsg_FlashFontFile_Create::ID: { ppapi::proxy::SerializedFontDescription description; @@ -115,14 +119,14 @@ std::unique_ptr<ppapi::host::ResourceHost> PepperRendererHostFactoryQt::CreateRe } } - if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) { +#if QT_CONFIG(webengine_printing_and_pdf) + if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_PDF)) { switch (message.type()) { case PpapiHostMsg_PDF_Create::ID: - // Not implemented - break; + return std::make_unique<pdf::PepperPDFHost>(host_, instance, resource); } } - +#endif // QT_CONFIG(webengine_printing_and_pdf) return nullptr; } diff --git a/src/core/renderer/print_web_view_helper_delegate_qt.cpp b/src/core/renderer/print_web_view_helper_delegate_qt.cpp index e693cf096..67cdd6b66 100644 --- a/src/core/renderer/print_web_view_helper_delegate_qt.cpp +++ b/src/core/renderer/print_web_view_helper_delegate_qt.cpp @@ -41,8 +41,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE.Chromium file. -#include "print_web_view_helper_delegate_qt.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_view.h" +#include "extensions/common/constants.h" +#include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_element.h" +#include "third_party/blink/public/web/web_local_frame.h" + +#include "print_web_view_helper_delegate_qt.h" #include "web_engine_library_info.h" namespace QtWebEngineCore { @@ -58,6 +64,15 @@ bool PrintWebViewHelperDelegateQt::CancelPrerender(content::RenderFrame *) blink::WebElement PrintWebViewHelperDelegateQt::GetPdfElement(blink::WebLocalFrame* frame) { + GURL url = frame->GetDocument().Url(); + if (url.SchemeIs(extensions::kExtensionScheme) && url.host() == extension_misc::kPdfExtensionId) + { + // <object> with id="plugin" is created in + // chrome/browser/resources/pdf/pdf.js. + auto plugin_element = frame->GetDocument().GetElementById("plugin"); + CHECK(!plugin_element.IsNull()); + return plugin_element; + } return blink::WebElement(); } diff --git a/src/core/renderer/render_frame_observer_qt.h b/src/core/renderer/render_frame_observer_qt.h index bca45bd8e..4c05422bb 100644 --- a/src/core/renderer/render_frame_observer_qt.h +++ b/src/core/renderer/render_frame_observer_qt.h @@ -44,6 +44,8 @@ #include "base/compiler_specific.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer_tracker.h" +#include "ppapi/buildflags/buildflags.h" +#include "services/service_manager/public/cpp/binder_registry.h" namespace content { class RenderFrame; @@ -67,10 +69,13 @@ public: bool isFrameDetached() const; + service_manager::BinderRegistry* registry() { return ®istry_; } + private: DISALLOW_COPY_AND_ASSIGN(RenderFrameObserverQt); bool m_isFrameDetached; + service_manager::BinderRegistry registry_; }; } // namespace QtWebEngineCore diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp index 920fda72e..46f5de2c2 100644 --- a/src/core/renderer/user_resource_controller.cpp +++ b/src/core/renderer/user_resource_controller.cpp @@ -103,7 +103,7 @@ static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url) matchFound = false; for (auto it = scriptData.urlPatterns.begin(), end = scriptData.urlPatterns.end(); it != end; ++it) { URLPattern urlPattern(validUserScriptSchemes()); - if (urlPattern.Parse(*it) == URLPattern::PARSE_SUCCESS && urlPattern.MatchesURL(url)) + if (urlPattern.Parse(*it) == URLPattern::ParseResult::kSuccess && urlPattern.MatchesURL(url)) matchFound = true; } if (!matchFound) @@ -137,7 +137,7 @@ public: private: // RenderFrameObserver implementation. - void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_document_navigation) override; + void DidCommitProvisionalLoad(bool is_same_document_navigation, ui::PageTransition transition) override; void DidClearWindowObject() override; void DidFinishDocumentLoad() override; void DidFinishLoad() override; @@ -230,8 +230,8 @@ UserResourceController::RenderViewObserverHelper::RenderViewObserverHelper(conte { } -void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(bool /* is_new_navigation */, - bool is_same_document_navigation) +void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(bool is_same_document_navigation, + ui::PageTransition /*transitionbool*/) { if (is_same_document_navigation) return; diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp index 1f496e810..f1da8289a 100644 --- a/src/core/renderer/web_channel_ipc_transport.cpp +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -137,6 +137,8 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) args->ThrowTypeError("Missing argument"); return; } + v8::Isolate *isolate = blink::MainThreadIsolate(); + v8::HandleScope handleScope(isolate); if (!jsonValue->IsString()) { args->ThrowTypeError("Expected string"); @@ -144,10 +146,10 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) } v8::Local<v8::String> jsonString = v8::Local<v8::String>::Cast(jsonValue); - QByteArray json(jsonString->Utf8Length(), 0); - jsonString->WriteUtf8(json.data(), json.size(), - nullptr, - v8::String::REPLACE_INVALID_UTF8); + 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); diff --git a/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp b/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp index 2c8b1246a..5d7c3973f 100644 --- a/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp +++ b/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp @@ -45,8 +45,10 @@ #include "pepper_isolated_file_system_message_filter.h" #include "base/macros.h" +#include "base/task/post_task.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_view_host.h" @@ -83,7 +85,7 @@ scoped_refptr<base::TaskRunner> PepperIsolatedFileSystemMessageFilter::OverrideT { // In order to reach ExtensionSystem, we need to get ProfileManager first. // ProfileManager lives in UI thread, so we need to do this in UI thread. - return content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI); + return base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI}); } int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived(const IPC::Message& msg, ppapi::host::HostMessageContext *context) diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp new file mode 100644 index 000000000..0a6adf4d6 --- /dev/null +++ b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE.Chromium file. + +#include "resource_dispatcher_host_delegate_qt.h" + +#include "base/bind.h" +#include "base/guid.h" +#include "base/strings/stringprintf.h" +#include "base/task/post_task.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/download_manager.h" +#include "content/public/browser/download_request_utils.h" +#include "content/public/browser/navigation_controller.h" + +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_dispatcher_host.h" +#include "content/public/browser/resource_request_info.h" +#include "content/public/browser/stream_info.h" +#include "content/public/browser/web_contents.h" + +#include "extensions/extension_system_qt.h" +#include "extensions/browser/info_map.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "extensions/common/manifest_handlers/mime_types_handler.h" + +#include "net/base/escape.h" +#include "net/url_request/url_request.h" + +#include "resource_context_qt.h" +#include "type_conversion.h" +#include "web_contents_delegate_qt.h" +#include "web_engine_settings.h" + +namespace QtWebEngineCore { + +void OnPdfStreamIntercepted( + const GURL& original_url, + std::string extension_id, + int frame_tree_node_id, + const content::ResourceRequestInfo::WebContentsGetter& + web_contents_getter) { + content::WebContents* web_contents = web_contents_getter.Run(); + if (!web_contents) + return; + + WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt*>(web_contents->GetDelegate()); + if (!contentsDelegate) + return; + + WebEngineSettings *settings = contentsDelegate->webEngineSettings(); + if (!settings->testAttribute(WebEngineSettings::PDFViewerEnabled) + || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) { + // If the applications has been set up to always download PDF files to open them in an + // external viewer, trigger the download. + std::unique_ptr<download::DownloadUrlParameters> params( + content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame( + web_contents, original_url, NO_TRAFFIC_ANNOTATION_YET)); + content::BrowserContext::GetDownloadManager(web_contents->GetBrowserContext()) + ->DownloadUrl(std::move(params)); + return; + } + + // The URL passes the original pdf resource url, that will be requested + // by the pdf viewer extension page. + content::NavigationController::LoadURLParams params( + GURL(base::StringPrintf("%s://%s/index.html?%s", extensions::kExtensionScheme, + extension_id.c_str(), + net::EscapeUrlEncodedData(original_url.spec(), false).c_str()))); + + params.frame_tree_node_id = frame_tree_node_id; + web_contents->GetController().LoadURLWithParams(params); +} + +bool ResourceDispatcherHostDelegateQt::ShouldInterceptResourceAsStream(net::URLRequest *request, + const std::string &mime_type, + GURL *origin, + std::string *payload) +{ + const content::ResourceRequestInfo* info = + content::ResourceRequestInfo::ForRequest(request); + + int render_process_host_id = -1; + int render_frame_id = -1; + if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_host_id, &render_frame_id)) + return false; + + ResourceContextQt *context = static_cast<ResourceContextQt *>(info->GetContext()); + std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist(); + + extensions::ExtensionSystemQt *extensionSystem = context->GetExtensionSystem(); + if (!extensionSystem) + return false; + + const scoped_refptr<const extensions::InfoMap> extension_info_map(extensionSystem->info_map()); + + for (const std::string &extension_id : whitelist) { + const extensions::Extension *extension = extension_info_map->extensions().GetByID(extension_id); + if (!extension) + continue; + + MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension); + if (!handler) + continue; + if (handler->CanHandleMIMEType(mime_type)) { + StreamTargetInfo target_info; + *origin = extensions::Extension::GetBaseURLFromExtensionId(extension_id); + target_info.extension_id = extension_id; + target_info.view_id = base::GenerateGUID(); + *payload = target_info.view_id; + stream_target_info_[request] = target_info; + return true; + } + } + return false; +} + +// Informs the delegate that a Stream was created. The Stream can be read from +// the blob URL of the Stream, but can only be read once. +void ResourceDispatcherHostDelegateQt::OnStreamCreated(net::URLRequest *request, + std::unique_ptr<content::StreamInfo> stream) +{ + const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request); + std::map<net::URLRequest *, StreamTargetInfo>::iterator ix = stream_target_info_.find(request); + CHECK(ix != stream_target_info_.end()); + int render_frame_id = -1; + int render_process_id = -1; + if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_id, &render_frame_id)) { + stream_target_info_.erase(request); + request->Cancel(); + return; + } + + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&OnPdfStreamIntercepted, + request->url(), ix->second.extension_id, + info->GetFrameTreeNodeId(), info->GetWebContentsGetterForRequest() + ) + ); + stream_target_info_.erase(request); +} + +} // namespace QtWebEngineCore diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h new file mode 100644 index 000000000..3039fd03e --- /dev/null +++ b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H +#define RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H + +#include "content/public/browser/resource_dispatcher_host_delegate.h" +#include "extensions/buildflags/buildflags.h" + +#include "web_contents_adapter_client.h" + +namespace QtWebEngineCore { + +class ResourceDispatcherHostDelegateQt : public content::ResourceDispatcherHostDelegate { +public: + // If the stream will be rendered in a BrowserPlugin, |payload| will contain + // the data that should be given to the old ResourceHandler to forward to the + // renderer process. + bool ShouldInterceptResourceAsStream(net::URLRequest *request, + const std::string &mime_type, + GURL *origin, + std::string *payload) override; + + // Informs the delegate that a Stream was created. The Stream can be read from + // the blob URL of the Stream, but can only be read once. + void OnStreamCreated(net::URLRequest *request, + std::unique_ptr<content::StreamInfo> stream) override; +private: +#if BUILDFLAG(ENABLE_EXTENSIONS) + struct StreamTargetInfo { + std::string extension_id; + std::string view_id; + }; + std::map<net::URLRequest *, StreamTargetInfo> stream_target_info_; +#endif + +}; + +} // namespace QtWebEngineCore + +#endif // RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H diff --git a/src/core/resource_bundle_qt.cpp b/src/core/resource_bundle_qt.cpp index 428faa34e..dc7507f34 100644 --- a/src/core/resource_bundle_qt.cpp +++ b/src/core/resource_bundle_qt.cpp @@ -71,6 +71,7 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id) return GetEmptyImage(); } +// static bool ResourceBundle::LocaleDataPakExists(const std::string& locale) { #if defined(OS_LINUX) diff --git a/src/core/resource_context_qt.cpp b/src/core/resource_context_qt.cpp index 6dfa5064e..78be72107 100644 --- a/src/core/resource_context_qt.cpp +++ b/src/core/resource_context_qt.cpp @@ -64,4 +64,11 @@ net::URLRequestContext* ResourceContextQt::GetRequestContext() return m_io_data->urlRequestContext(); } +#if BUILDFLAG(ENABLE_EXTENSIONS) +extensions::ExtensionSystemQt* ResourceContextQt::GetExtensionSystem() +{ + return m_io_data->GetExtensionSystem(); +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + } // namespace QtWebEngineCore diff --git a/src/core/resource_context_qt.h b/src/core/resource_context_qt.h index 6a5e7a74e..ccbe2c364 100644 --- a/src/core/resource_context_qt.h +++ b/src/core/resource_context_qt.h @@ -42,6 +42,20 @@ #include "content/public/browser/resource_context.h" +#include "extensions/buildflags/buildflags.h" + +namespace net { +class URLRequestContextGetter; +} + +#if BUILDFLAG(ENABLE_EXTENSIONS) +namespace extensions { +class ExtensionSystemQt; +} +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + +class GURL; + namespace QtWebEngineCore { class ProfileIODataQt; @@ -51,7 +65,11 @@ class ResourceContextQt : public content::ResourceContext public: ResourceContextQt(ProfileIODataQt *io_data); net::URLRequestContext *GetRequestContext() override; +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionSystemQt* GetExtensionSystem(); +#endif // BUILDFLAG(ENABLE_EXTENSIONS) private: + friend class ProfileIODataQt; ProfileIODataQt* m_io_data; DISALLOW_COPY_AND_ASSIGN(ResourceContextQt); }; diff --git a/src/core/service/service_qt.cpp b/src/core/service/service_qt.cpp index 30ed269e8..bb842232c 100644 --- a/src/core/service/service_qt.cpp +++ b/src/core/service/service_qt.cpp @@ -45,7 +45,9 @@ #include "service_qt.h" #include "base/no_destructor.h" +#include "base/task/post_task.h" #include "components/spellcheck/spellcheck_buildflags.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "services/service_manager/public/cpp/binder_registry.h" @@ -82,10 +84,10 @@ private: ServiceQt::IOThreadContext::IOThreadContext() { - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI); #if BUILDFLAG(ENABLE_SPELLCHECK) - m_registry_with_source_info.AddInterface(base::Bind(&SpellCheckHostChromeImpl::Create), ui_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = + base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI}); + m_registry_with_source_info.AddInterface(base::BindRepeating(&SpellCheckHostChromeImpl::Create), ui_task_runner); #endif } @@ -97,7 +99,7 @@ void ServiceQt::IOThreadContext::BindConnector(service_manager::mojom::Connector // on the IO thread. Post a task instead. As long as this task is posted // before any code attempts to connect to the chrome service, there's no // race. - content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)->PostTask( + base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})->PostTask( FROM_HERE, base::BindOnce(&IOThreadContext::BindConnectorOnIOThread, base::Unretained(this), diff --git a/src/core/touch_handle_drawable_client.h b/src/core/touch_handle_drawable_client.h new file mode 100644 index 000000000..42d907d75 --- /dev/null +++ b/src/core/touch_handle_drawable_client.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef TOUCH_HANDLE_DRAWABLE_CLIENT_H +#define TOUCH_HANDLE_DRAWABLE_CLIENT_H + +#include "qtwebenginecoreglobal_p.h" +#include <QRect> + +namespace QtWebEngineCore { + +class QWEBENGINECORE_PRIVATE_EXPORT TouchHandleDrawableClient { +public: + virtual ~TouchHandleDrawableClient() { } + + virtual void setImage(int orientation) = 0; + virtual void setBounds(const QRect &bounds) = 0; + virtual void setVisible(bool visible) = 0; + virtual void setOpacity(float opacity) = 0; +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_HANDLE_DRAWABLE_CLIENT_H diff --git a/src/core/touch_handle_drawable_qt.cpp b/src/core/touch_handle_drawable_qt.cpp new file mode 100644 index 000000000..66b1cf40e --- /dev/null +++ b/src/core/touch_handle_drawable_qt.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE.Chromium file. + +// This implementation is based on chromium/ui/touch_selection/touch_handle_drawable_aura.cc + +#include "render_widget_host_view_qt.h" +#include "touch_handle_drawable_client.h" +#include "touch_handle_drawable_qt.h" +#include "type_conversion.h" +#include "web_contents_adapter_client.h" + +#include "ui/gfx/image/image.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/resources/grit/ui_resources.h" + +namespace QtWebEngineCore { + +namespace { +// The distance by which a handle image is offset from the focal point (i.e. +// text baseline) downwards. +const int kSelectionHandleVerticalVisualOffset = 2; + +// The padding around the selection handle image can be used to extend the +// handle window so that touch events near the selection handle image are +// targeted to the selection handle window. +const int kSelectionHandlePadding = 0; + +// Epsilon value used to compare float values to zero. +const float kEpsilon = 1e-8f; + +// Returns the appropriate handle image based on the handle orientation. +gfx::Image* GetHandleImage(ui::TouchHandleOrientation orientation) +{ + int resource_id = 0; + switch (orientation) { + case ui::TouchHandleOrientation::LEFT: + resource_id = IDR_TEXT_SELECTION_HANDLE_LEFT; + break; + case ui::TouchHandleOrientation::CENTER: + resource_id = IDR_TEXT_SELECTION_HANDLE_CENTER; + break; + case ui::TouchHandleOrientation::RIGHT: + resource_id = IDR_TEXT_SELECTION_HANDLE_RIGHT; + break; + case ui::TouchHandleOrientation::UNDEFINED: + NOTREACHED() << "Invalid touch handle bound type."; + return nullptr; + }; + return &ui::ResourceBundle::GetSharedInstance().GetImageNamed(resource_id); +} + +bool IsNearlyZero(float value) +{ + return std::abs(value) < kEpsilon; +} + +} // namespace + +TouchHandleDrawableQt::TouchHandleDrawableQt(RenderWidgetHostViewQt *rwhv) + : m_rwhv(rwhv) + , m_enabled(false) + , m_alpha(0) + , m_orientation(ui::TouchHandleOrientation::UNDEFINED) +{ + QMap<int, QImage> images; + for (int orientation = 0; orientation < static_cast<int>(ui::TouchHandleOrientation::UNDEFINED); ++orientation) { + gfx::Image* image = GetHandleImage(static_cast<ui::TouchHandleOrientation>(orientation)); + images.insert(orientation, toQImage(image->AsBitmap())); + } + + Q_ASSERT(m_rwhv); + Q_ASSERT(m_rwhv->adapterClient()); + m_client.reset(m_rwhv->adapterClient()->createTouchHandle(images)); +} + +TouchHandleDrawableQt::~TouchHandleDrawableQt() +{ +} + +void TouchHandleDrawableQt::UpdateBounds() +{ + if (!m_client) + return; + + gfx::RectF newBounds = m_relativeBounds; + newBounds.Offset(m_originPosition.x(), m_originPosition.y()); + m_client->setBounds(toQt(gfx::ToEnclosingRect(newBounds))); +} + +bool TouchHandleDrawableQt::IsVisible() const +{ + return m_enabled && !IsNearlyZero(m_alpha); +} + +void TouchHandleDrawableQt::SetEnabled(bool enabled) +{ + if (!m_client) + return; + + if (enabled == m_enabled) + return; + + m_enabled = enabled; + m_client->setVisible(enabled); +} + +void TouchHandleDrawableQt::SetOrientation(ui::TouchHandleOrientation orientation, bool mirror_vertical, bool mirror_horizontal) +{ + if (!m_client) + return; + + // TODO: Implement adaptive handle orientation logic + DCHECK(!mirror_vertical); + DCHECK(!mirror_horizontal); + + if (m_orientation == orientation) + return; + m_orientation = orientation; + gfx::Image* image = GetHandleImage(orientation); + m_client->setImage(static_cast<int>(orientation)); + + // Calculate the relative bounds. + gfx::Size image_size = image->Size(); + int window_width = image_size.width() + 2 * kSelectionHandlePadding; + int window_height = image_size.height() + 2 * kSelectionHandlePadding; + m_relativeBounds = + gfx::RectF(-kSelectionHandlePadding, + kSelectionHandleVerticalVisualOffset - kSelectionHandlePadding, + window_width, window_height); + UpdateBounds(); +} + +void TouchHandleDrawableQt::SetOrigin(const gfx::PointF& position) +{ + m_originPosition = position; + UpdateBounds(); +} + +void TouchHandleDrawableQt::SetAlpha(float alpha) +{ + if (!m_client) + return; + + if (alpha == m_alpha) + return; + + m_alpha = alpha; + m_client->setOpacity(m_alpha); + m_client->setVisible(IsVisible()); +} + +gfx::RectF TouchHandleDrawableQt::GetVisibleBounds() const +{ + gfx::RectF bounds = m_relativeBounds; + bounds.Offset(m_originPosition.x(), m_originPosition.y()); + + gfx::RectF visibleBounds(bounds); + visibleBounds.Inset(kSelectionHandlePadding, + kSelectionHandlePadding + kSelectionHandleVerticalVisualOffset, + kSelectionHandlePadding, + kSelectionHandlePadding); + return visibleBounds; +} + +float TouchHandleDrawableQt::GetDrawableHorizontalPaddingRatio() const +{ + // Qt does not have any transparent padding for its handle drawable. + return 0.0; +} + +} // namespace QtWebEngineCore diff --git a/src/core/touch_handle_drawable_qt.h b/src/core/touch_handle_drawable_qt.h new file mode 100644 index 000000000..46fa217b7 --- /dev/null +++ b/src/core/touch_handle_drawable_qt.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef TOUCH_HANDLE_DRAWABLE_QT_H +#define TOUCH_HANDLE_DRAWABLE_QT_H + +#include "ui/touch_selection/touch_handle.h" +#include "ui/touch_selection/touch_handle_orientation.h" + +#include <QtCore/QScopedPointer> + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQt; +class TouchHandleDrawableClient; + +class TouchHandleDrawableQt : public ui::TouchHandleDrawable +{ +public: + explicit TouchHandleDrawableQt(RenderWidgetHostViewQt *rwhv); + ~TouchHandleDrawableQt() override; + +private: + void UpdateBounds(); + bool IsVisible() const; + + // ui::TouchHandleDrawable overrides + void SetEnabled(bool enabled) override; + void SetOrientation(ui::TouchHandleOrientation orientation, + bool mirror_vertical, + bool mirror_horizontal) override; + void SetOrigin(const gfx::PointF& position) override; + void SetAlpha(float alpha) override; + gfx::RectF GetVisibleBounds() const override; + float GetDrawableHorizontalPaddingRatio() const override; + + RenderWidgetHostViewQt *m_rwhv; + QScopedPointer<TouchHandleDrawableClient> m_client; + + bool m_enabled; + float m_alpha; + ui::TouchHandleOrientation m_orientation; + gfx::RectF m_relativeBounds; + gfx::PointF m_originPosition; + + DISALLOW_COPY_AND_ASSIGN(TouchHandleDrawableQt); +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_HANDLE_DRAWABLE_QT_H diff --git a/src/core/touch_selection_controller_client_qt.cpp b/src/core/touch_selection_controller_client_qt.cpp new file mode 100644 index 000000000..da3c78b8a --- /dev/null +++ b/src/core/touch_selection_controller_client_qt.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** 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 "render_widget_host_view_qt.h" +#include "touch_handle_drawable_qt.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" + +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "ui/gfx/geometry/size_conversions.h" + +#include <QClipboard> +#include <QGuiApplication> + +namespace QtWebEngineCore { + +TouchSelectionControllerClientQt::TouchSelectionControllerClientQt(RenderWidgetHostViewQt *rwhv) + : m_rwhv(rwhv) + , m_menuController(new TouchSelectionMenuController(this)) + , m_menuShowing(false) + , m_menuRequested(false) + , m_touchDown(false) + , m_scrollInProgress(false) + , m_handleDragInProgress(false) +{ + Q_ASSERT(rwhv); +} + +TouchSelectionControllerClientQt::~TouchSelectionControllerClientQt() +{ +} + +bool TouchSelectionControllerClientQt::handleContextMenu(const content::ContextMenuParams& params) +{ + if ((params.source_type == ui::MENU_SOURCE_LONG_PRESS || + params.source_type == ui::MENU_SOURCE_LONG_TAP) && + params.is_editable && params.selection_text.empty()) { + m_menuRequested = true; + updateMenu(); + return true; + } + + const bool from_touch = params.source_type == ui::MENU_SOURCE_LONG_PRESS || + params.source_type == ui::MENU_SOURCE_LONG_TAP || + params.source_type == ui::MENU_SOURCE_TOUCH; + if (from_touch && !params.selection_text.empty()) + return true; + + GetTouchSelectionController()->HideAndDisallowShowingAutomatically(); + return false; +} + +void TouchSelectionControllerClientQt::onTouchDown() +{ + m_touchDown = true; + updateMenu(); +} + +void TouchSelectionControllerClientQt::onTouchUp() +{ + m_touchDown = false; + updateMenu(); +} + +void TouchSelectionControllerClientQt::onScrollBegin() +{ + m_scrollInProgress = true; + GetTouchSelectionController()->SetTemporarilyHidden(true); + updateMenu(); +} + +void TouchSelectionControllerClientQt::onScrollEnd() +{ + m_scrollInProgress = false; + GetTouchSelectionController()->SetTemporarilyHidden(false); + updateMenu(); +} + +bool TouchSelectionControllerClientQt::IsCommandIdEnabled(int command_id) const +{ + bool editable = m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_NONE; + bool readable = m_rwhv->getTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD; + bool hasSelection = !m_rwhv->GetSelectedText().empty(); + + switch (command_id) { + case TouchSelectionMenuController::Cut: + return editable && readable && hasSelection; + case TouchSelectionMenuController::Copy: + return readable && hasSelection; + case TouchSelectionMenuController::Paste: + return editable && !QGuiApplication::clipboard()->text().isEmpty(); + default: + return false; + } +} + +void TouchSelectionControllerClientQt::ExecuteCommand(int command_id, int event_flags) +{ + Q_UNUSED(event_flags); + GetTouchSelectionController()->HideAndDisallowShowingAutomatically(); + + WebContentsAdapterClient *adapterClient = m_rwhv->adapterClient(); + Q_ASSERT(adapterClient); + WebContentsAdapter *adapter = adapterClient->webContentsAdapter(); + Q_ASSERT(adapter); + + switch (command_id) { + case TouchSelectionMenuController::Cut: + adapter->cut(); + break; + case TouchSelectionMenuController::Copy: + adapter->copy(); + break; + case TouchSelectionMenuController::Paste: + adapter->paste(); + break; + default: + NOTREACHED(); + break; + } +} + +void TouchSelectionControllerClientQt::RunContextMenu() +{ + gfx::RectF anchorRect = GetTouchSelectionController()->GetRectBetweenBounds(); + gfx::PointF anchorPoint = gfx::PointF(anchorRect.CenterPoint().x(), anchorRect.y()); + + content::RenderWidgetHostImpl *host = m_rwhv->host(); + host->ShowContextMenuAtPoint(gfx::ToRoundedPoint(anchorPoint), + ui::MENU_SOURCE_TOUCH_EDIT_MENU); + + // Hide selection handles after getting rect-between-bounds from touch + // selection controller; otherwise, rect would be empty and the above + // calculations would be invalid. + GetTouchSelectionController()->HideAndDisallowShowingAutomatically(); +} + +void TouchSelectionControllerClientQt::DidStopFlinging() +{ + onScrollEnd(); +} + +void TouchSelectionControllerClientQt::UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end) +{ + UpdateClientSelectionBounds(start, end, this, this); +} + +void TouchSelectionControllerClientQt::UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end, + ui::TouchSelectionControllerClient* client, + ui::TouchSelectionMenuClient* menu_client) +{ + Q_UNUSED(client); + Q_UNUSED(menu_client); + + GetTouchSelectionController()->OnSelectionBoundsChanged(start, end); +} + +void TouchSelectionControllerClientQt::InvalidateClient(ui::TouchSelectionControllerClient* client) +{ + Q_UNUSED(client); +} + +ui::TouchSelectionController* TouchSelectionControllerClientQt::GetTouchSelectionController() +{ + return m_rwhv->getTouchSelectionController(); +} + +void TouchSelectionControllerClientQt::AddObserver(Observer* observer) +{ + Q_UNUSED(observer); +} + +void TouchSelectionControllerClientQt::RemoveObserver(Observer* observer) +{ + Q_UNUSED(observer); +} + +bool TouchSelectionControllerClientQt::SupportsAnimation() const +{ + return false; +} + +void TouchSelectionControllerClientQt::SetNeedsAnimate() +{ + NOTREACHED(); +} + +void TouchSelectionControllerClientQt::MoveCaret(const gfx::PointF& position) +{ + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (!frameInputHandler) + return; + + frameInputHandler->MoveCaret(gfx::ToRoundedPoint(position)); +} + +void TouchSelectionControllerClientQt::MoveRangeSelectionExtent(const gfx::PointF& extent) +{ + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (!frameInputHandler) + return; + + frameInputHandler->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent)); +} + +void TouchSelectionControllerClientQt::SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) +{ + content::mojom::FrameInputHandler *frameInputHandler = m_rwhv->getFrameInputHandler(); + if (!frameInputHandler) + return; + + frameInputHandler->SelectRange(gfx::ToRoundedPoint(base), gfx::ToRoundedPoint(extent)); +} + +void TouchSelectionControllerClientQt::OnSelectionEvent(ui::SelectionEventType event) +{ + switch (event) { + case ui::SELECTION_HANDLES_SHOWN: + m_menuRequested = true; + break; + case ui::INSERTION_HANDLE_SHOWN: + break; + case ui::SELECTION_HANDLES_CLEARED: + case ui::INSERTION_HANDLE_CLEARED: + m_menuRequested = false; + break; + case ui::SELECTION_HANDLE_DRAG_STARTED: + case ui::INSERTION_HANDLE_DRAG_STARTED: + m_handleDragInProgress = true; + break; + case ui::SELECTION_HANDLE_DRAG_STOPPED: + case ui::INSERTION_HANDLE_DRAG_STOPPED: + m_handleDragInProgress = false; + break; + case ui::SELECTION_HANDLES_MOVED: + case ui::INSERTION_HANDLE_MOVED: + break; + case ui::INSERTION_HANDLE_TAPPED: + m_menuRequested = !m_menuRequested; + break; + } + + updateMenu(); +} + +void TouchSelectionControllerClientQt::OnDragUpdate(const gfx::PointF& position) +{ + Q_UNUSED(position); +} + +std::unique_ptr<ui::TouchHandleDrawable> TouchSelectionControllerClientQt::CreateDrawable() +{ + return std::unique_ptr<ui::TouchHandleDrawable>(new TouchHandleDrawableQt(m_rwhv)); +} + +void TouchSelectionControllerClientQt::DidScroll() +{ +} + +void TouchSelectionControllerClientQt::showMenu() +{ + gfx::RectF rect = GetTouchSelectionController()->GetRectBetweenBounds(); + gfx::PointF origin = rect.origin(); + gfx::PointF bottom_right = rect.bottom_right(); + + gfx::Vector2dF diagonal = bottom_right - origin; + gfx::SizeF size(diagonal.x(), diagonal.y()); + gfx::RectF anchor_rect(origin, size); + + // Calculate maximum handle image size; + gfx::SizeF max_handle_size = GetTouchSelectionController()->GetStartHandleRect().size(); + max_handle_size.SetToMax(GetTouchSelectionController()->GetEndHandleRect().size()); + + WebContentsAdapterClient *adapterClient = m_rwhv->adapterClient(); + Q_ASSERT(adapterClient); + adapterClient->showTouchSelectionMenu(m_menuController.get(), + QRect(toQt(gfx::ToEnclosingRect(anchor_rect))), + QSize(toQt(gfx::ToRoundedSize(max_handle_size)))); + m_menuShowing = true; +} + +void TouchSelectionControllerClientQt::hideMenu() +{ + WebContentsAdapterClient *adapterClient = m_rwhv->adapterClient(); + Q_ASSERT(adapterClient); + adapterClient->hideTouchSelectionMenu(); + m_menuShowing = false; +} + +void TouchSelectionControllerClientQt::updateMenu() +{ + if (m_menuShowing) + hideMenu(); + + if (m_menuRequested && !m_touchDown && + !m_scrollInProgress && !m_handleDragInProgress) { + showMenu(); + } +} + +} // namespace QtWebEngineCore diff --git a/src/core/touch_selection_controller_client_qt.h b/src/core/touch_selection_controller_client_qt.h new file mode 100644 index 000000000..cdc45cac3 --- /dev/null +++ b/src/core/touch_selection_controller_client_qt.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H +#define TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H + +#include "content/public/browser/touch_selection_controller_client_manager.h" +#include "content/public/common/context_menu_params.h" +#include "ui/touch_selection/touch_selection_controller.h" +#include "ui/touch_selection/touch_selection_menu_runner.h" + +#include <QtCore/QScopedPointer> + +namespace QtWebEngineCore { + +class RenderWidgetHostViewQt; +class TouchSelectionMenuController; + +class TouchSelectionControllerClientQt + : public ui::TouchSelectionControllerClient + , public ui::TouchSelectionMenuClient + , public content::TouchSelectionControllerClientManager +{ +public: + explicit TouchSelectionControllerClientQt(RenderWidgetHostViewQt *rwhv); + ~TouchSelectionControllerClientQt() override; + + void UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end); + bool handleContextMenu(const content::ContextMenuParams& params); + void onTouchDown(); + void onTouchUp(); + void onScrollBegin(); + void onScrollEnd(); + + // ui::TouchSelectionMenuClient overrides + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + void RunContextMenu() override; + + // content::TouchSelectionControllerClientManager overrides + void DidStopFlinging() override; + void UpdateClientSelectionBounds(const gfx::SelectionBound& start, + const gfx::SelectionBound& end, + ui::TouchSelectionControllerClient* client, + ui::TouchSelectionMenuClient* menu_client) override; + void InvalidateClient(ui::TouchSelectionControllerClient* client) override; + ui::TouchSelectionController* GetTouchSelectionController() override; + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + + // ui::TouchSelectionControllerClient overrides + bool SupportsAnimation() const override; + void SetNeedsAnimate() override; + void MoveCaret(const gfx::PointF& position) override; + void MoveRangeSelectionExtent(const gfx::PointF& extent) override; + void SelectBetweenCoordinates(const gfx::PointF& base, const gfx::PointF& extent) override; + void OnSelectionEvent(ui::SelectionEventType event) override; + void OnDragUpdate(const gfx::PointF& position) override; + std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override; + void DidScroll() override; + +private: + void showMenu(); + void hideMenu(); + void updateMenu(); + + RenderWidgetHostViewQt *m_rwhv; + QScopedPointer<TouchSelectionMenuController> m_menuController; + + bool m_menuShowing; + bool m_menuRequested; + bool m_touchDown; + bool m_scrollInProgress; + bool m_handleDragInProgress; +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H diff --git a/src/core/touch_selection_menu_controller.cpp b/src/core/touch_selection_menu_controller.cpp new file mode 100644 index 000000000..cdec9a064 --- /dev/null +++ b/src/core/touch_selection_menu_controller.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 "touch_selection_controller_client_qt.h" +#include "touch_selection_menu_controller.h" + +namespace QtWebEngineCore { + +TouchSelectionMenuController::TouchSelectionMenuController(TouchSelectionControllerClientQt *touchSelectionControllerClient) + : m_touchSelectionControllerClient(touchSelectionControllerClient) +{ +} + +TouchSelectionMenuController::~TouchSelectionMenuController() +{ +} + +int TouchSelectionMenuController::buttonCount() +{ + int buttonCount = 1; + + for (int commandId = 0; commandId <= static_cast<int>(Paste); ++commandId) { + if (m_touchSelectionControllerClient->IsCommandIdEnabled(commandId)) + buttonCount++; + } + + return buttonCount; +} + +bool TouchSelectionMenuController::isCommandEnabled(TouchSelectionCommand command) +{ + return m_touchSelectionControllerClient->IsCommandIdEnabled(static_cast<int>(command)); +} + +void TouchSelectionMenuController::cut() +{ + m_touchSelectionControllerClient->ExecuteCommand(static_cast<int>(Cut), 0); +} + +void TouchSelectionMenuController::copy() +{ + m_touchSelectionControllerClient->ExecuteCommand(static_cast<int>(Copy), 0); +} + +void TouchSelectionMenuController::paste() +{ + m_touchSelectionControllerClient->ExecuteCommand(static_cast<int>(Paste), 0); +} + +void TouchSelectionMenuController::runContextMenu() +{ + return m_touchSelectionControllerClient->RunContextMenu(); +} + +} // namespace QtWebEngineCore diff --git a/src/core/touch_selection_menu_controller.h b/src/core/touch_selection_menu_controller.h new file mode 100644 index 000000000..fd61ae709 --- /dev/null +++ b/src/core/touch_selection_menu_controller.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef TOUCH_SELECTION_MENU_CONTROLLER_H +#define TOUCH_SELECTION_MENU_CONTROLLER_H + +#include "qtwebenginecoreglobal_p.h" +#include <QtCore/QObject> + +namespace QtWebEngineCore { + +class TouchSelectionControllerClientQt; + +class QWEBENGINECORE_PRIVATE_EXPORT TouchSelectionMenuController : public QObject { + Q_OBJECT +public: + enum TouchSelectionCommand { + Cut, + Copy, + Paste + }; + + TouchSelectionMenuController(TouchSelectionControllerClientQt *touchSelectionControllerClient); + ~TouchSelectionMenuController(); + int buttonCount(); + bool isCommandEnabled(TouchSelectionCommand); + +public Q_SLOTS: + void cut(); + void copy(); + void paste(); + void runContextMenu(); + +private: + TouchSelectionControllerClientQt *m_touchSelectionControllerClient; +}; + +} // namespace QtWebEngineCore + +#endif // TOUCH_SELECTION_CONTROLLER_CLIENT_QT_H diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index f69b2a297..02d2db448 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -42,7 +42,9 @@ #include <content/public/common/favicon_url.h> #include <ui/events/event_constants.h> #include <ui/gfx/image/image_skia.h> + #include <QtCore/qcoreapplication.h> +#include <QtGui/qmatrix4x4.h> namespace QtWebEngineCore { @@ -131,7 +133,7 @@ QImage toQImage(const SkBitmap &bitmap) QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep) { - QImage image = toQImage(imageSkiaRep.sk_bitmap()); + QImage image = toQImage(imageSkiaRep.GetBitmap()); if (!image.isNull() && imageSkiaRep.scale() != 1.0f) image.setDevicePixelRatio(imageSkiaRep.scale()); return image; @@ -243,4 +245,15 @@ FaviconInfo toFaviconInfo(const content::FaviconURL &favicon_url) return info; } +void convertToQt(const SkMatrix44 &m, QMatrix4x4 &c) +{ + QMatrix4x4 qtMatrix( + m.get(0, 0), m.get(0, 1), m.get(0, 2), m.get(0, 3), + m.get(1, 0), m.get(1, 1), m.get(1, 2), m.get(1, 3), + m.get(2, 0), m.get(2, 1), m.get(2, 2), m.get(2, 3), + m.get(3, 0), m.get(3, 1), m.get(3, 2), m.get(3, 3)); + qtMatrix.optimize(); + c = qtMatrix; +} + } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index afc3c3336..7b1f1b4d6 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -45,7 +45,6 @@ #include <QDir> #include <QIcon> #include <QImage> -#include <QMatrix4x4> #include <QNetworkCookie> #include <QRect> #include <QString> @@ -64,6 +63,8 @@ #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" +QT_FORWARD_DECLARE_CLASS(QMatrix4x4) + namespace content { struct FaviconURL; } @@ -171,6 +172,11 @@ inline gfx::SizeF toGfx(const QSizeF& size) return gfx::SizeF(size.width(), size.height()); } +inline gfx::Rect toGfx(const QRect &rect) +{ + return gfx::Rect(rect.x(), rect.y(), rect.width(), rect.height()); +} + inline QSizeF toQt(const gfx::SizeF &size) { return QSizeF(size.width(), size.height()); @@ -198,16 +204,7 @@ SkBitmap toSkBitmap(const QImage &image); QIcon toQIcon(const std::vector<SkBitmap> &bitmaps); -inline QMatrix4x4 toQt(const SkMatrix44 &m) -{ - QMatrix4x4 qtMatrix( - m.get(0, 0), m.get(0, 1), m.get(0, 2), m.get(0, 3), - m.get(1, 0), m.get(1, 1), m.get(1, 2), m.get(1, 3), - m.get(2, 0), m.get(2, 1), m.get(2, 2), m.get(2, 3), - m.get(3, 0), m.get(3, 1), m.get(3, 2), m.get(3, 3)); - qtMatrix.optimize(); - return qtMatrix; -} +void convertToQt(const SkMatrix44 &m, QMatrix4x4 &c); inline QDateTime toQt(base::Time time) { diff --git a/src/core/user_notification_controller.cpp b/src/core/user_notification_controller.cpp new file mode 100644 index 000000000..82cb57e51 --- /dev/null +++ b/src/core/user_notification_controller.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** 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 "user_notification_controller.h" + +#include "type_conversion.h" + +#include "base/callback.h" +#include "content/public/browser/notification_event_dispatcher.h" +#include "third_party/blink/public/common/notifications/notification_resources.h" +#include "third_party/blink/public/common/notifications/platform_notification_data.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +#include <memory> + +namespace QtWebEngineCore { + +static Qt::LayoutDirection toDirection(blink::PlatformNotificationData::Direction direction) +{ + switch (direction) { + case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT: + return Qt::LeftToRight; + case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT: + return Qt::RightToLeft; + case blink::PlatformNotificationData::DIRECTION_AUTO: + default: + break; + } + return Qt::LayoutDirectionAuto; +} + +class UserNotificationControllerPrivate { +public: + UserNotificationControllerPrivate(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin) + : m_params(params) + , m_origin(origin) + , m_delegate(nullptr) + , m_resources(resources) + , m_client(nullptr) + , m_iconGenerated(false) + , m_imageGenerated(false) + , m_badgeGenerated(false) + , m_shown(false) + { } + + blink::PlatformNotificationData m_params; + GURL m_origin; + std::unique_ptr<UserNotificationController::Delegate> m_delegate; + blink::NotificationResources m_resources; + UserNotificationController::Client *m_client; + QIcon m_icon; + QImage m_image; + QImage m_badge; + bool m_iconGenerated; + bool m_imageGenerated; + bool m_badgeGenerated; + bool m_shown; +}; + + +UserNotificationController::UserNotificationController(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin, + Delegate *delegate) + : d(new UserNotificationControllerPrivate(params, resources, origin)) +{ + d->m_delegate.reset(delegate); +} + +UserNotificationController::~UserNotificationController() +{ + delete d; + d = nullptr; +} + +void UserNotificationController::notificationDisplayed() +{ + if (!d->m_shown) { + d->m_shown = true; + if (d->m_delegate) + d->m_delegate->shown(); + } +} + +void UserNotificationController::notificationClosed() +{ + d->m_shown = false; + if (d->m_delegate) + d->m_delegate->closed(true); +} + +void UserNotificationController::notificationClicked() +{ + if (d->m_delegate) + d->m_delegate->clicked(); +} + +void UserNotificationController::closeNotification() +{ + d->m_shown = false; + if (d->m_client) + d->m_client->notificationClosed(this); +} + +void UserNotificationController::setClient(UserNotificationController::Client* client) +{ + d->m_client = client; +} + +UserNotificationController::Client* UserNotificationController::client() +{ + return d->m_client; +} + +QUrl UserNotificationController::origin() const +{ + return toQt(d->m_origin); +} + +QIcon UserNotificationController::icon() const +{ + if (!d->m_iconGenerated) { + d->m_iconGenerated = true; + if (!d->m_resources.notification_icon.isNull()) { + QImage image = toQImage(d->m_resources.notification_icon); + if (!image.isNull()) + d->m_icon = QIcon(QPixmap::fromImage(std::move(image), Qt::NoFormatConversion)); + } + } + return d->m_icon; +} + +QImage UserNotificationController::image() const +{ + if (d->m_imageGenerated) + return d->m_image; + d->m_image = toQImage(d->m_resources.image); + d->m_imageGenerated = true; + return d->m_image; +} + +QImage UserNotificationController::badge() const +{ + if (d->m_badgeGenerated) + return d->m_badge; + d->m_badge = toQImage(d->m_resources.badge); + d->m_badgeGenerated = true; + return d->m_badge; +} + +QString UserNotificationController::title() const +{ + return toQt(d->m_params.title); +} + +QString UserNotificationController::body() const +{ + return toQt(d->m_params.body); +} + +QString UserNotificationController::tag() const +{ + return toQt(d->m_params.tag); +} + +QString UserNotificationController::language() const +{ + return toQt(d->m_params.lang); +} + +Qt::LayoutDirection UserNotificationController::direction() const +{ + return toDirection(d->m_params.direction); +} + +bool UserNotificationController::isShown() const +{ + return d->m_shown; +} + +} // namespace QtWebEngineCore diff --git a/src/core/user_notification_controller.h b/src/core/user_notification_controller.h new file mode 100644 index 000000000..840074843 --- /dev/null +++ b/src/core/user_notification_controller.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef DESKTOP_NOTIFICATION_CONTROLLER_H +#define DESKTOP_NOTIFICATION_CONTROLLER_H + +#include "qtwebenginecoreglobal.h" + +#include <QtCore/QSharedPointer> +#include <QtCore/QUrl> +#include <QtGui/QIcon> + +class GURL; + +namespace blink { + struct NotificationResources; + struct PlatformNotificationData; +} + +namespace QtWebEngineCore { + +class UserNotificationControllerPrivate; + +// Works as an accessor and owner of chromium objects related to showing desktop notifications. +class QWEBENGINECORE_EXPORT UserNotificationController : public QEnableSharedFromThis<UserNotificationController> { +public: + struct Delegate { + virtual ~Delegate() { } + virtual void shown() = 0; + virtual void clicked() = 0; + virtual void closed(bool byUser) = 0; + }; + + UserNotificationController(const blink::PlatformNotificationData ¶ms, + const blink::NotificationResources &resources, + const GURL &origin, + Delegate *delegate); + ~UserNotificationController(); + + // The notification was shown. + void notificationDisplayed(); + + // The notification was closed. + void notificationClosed(); + + // The user clicked on the notification. + void notificationClicked(); + + // Chromium requests to close the notification. + void closeNotification(); + + QUrl origin() const; + QIcon icon() const; + QImage image() const; + QImage badge() const; + QString title() const; + QString body() const; + QString tag() const; + QString language() const; + Qt::LayoutDirection direction() const; + + bool isShown() const; + + class Client { + public: + virtual ~Client() { } + virtual void notificationClosed(const UserNotificationController *) = 0; + }; + void setClient(Client *client); + Client* client(); + +private: + UserNotificationControllerPrivate *d; +}; + +} // namespace QtWebEngineCore + +#endif // DESKTOP_NOTIFICATION_CONTROLLER_H diff --git a/src/core/visited_links_manager_qt.cpp b/src/core/visited_links_manager_qt.cpp index ac27446b8..d4885e8e8 100644 --- a/src/core/visited_links_manager_qt.cpp +++ b/src/core/visited_links_manager_qt.cpp @@ -39,7 +39,6 @@ #include "visited_links_manager_qt.h" -#include "profile_adapter.h" #include "content_browser_client_qt.h" #include "profile_qt.h" #include "type_conversion.h" @@ -106,14 +105,13 @@ static void ensureDirectoryExists(const base::FilePath &path) errorstr.c_str()); } -VisitedLinksManagerQt::VisitedLinksManagerQt(ProfileAdapter *adapter) +VisitedLinksManagerQt::VisitedLinksManagerQt(ProfileQt *profile, bool persistVisitedLinks) : m_delegate(new VisitedLinkDelegateQt) { - Q_ASSERT(adapter && adapter->profile()); - ProfileQt *profile = adapter->profile(); - if (adapter->persistVisitedLinks()) + Q_ASSERT(profile); + if (persistVisitedLinks) ensureDirectoryExists(profile->GetPath()); - m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(profile, m_delegate.data(), adapter->persistVisitedLinks())); + m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(profile, m_delegate.data(), persistVisitedLinks)); m_visitedLinkMaster->Init(); } diff --git a/src/core/visited_links_manager_qt.h b/src/core/visited_links_manager_qt.h index 8d9a7495b..5bbcc5983 100644 --- a/src/core/visited_links_manager_qt.h +++ b/src/core/visited_links_manager_qt.h @@ -67,14 +67,14 @@ class GURL; namespace QtWebEngineCore { -class ProfileAdapter; +class ProfileQt; class VisitedLinkDelegateQt; class QWEBENGINECORE_PRIVATE_EXPORT VisitedLinksManagerQt { public: virtual~VisitedLinksManagerQt(); - VisitedLinksManagerQt(ProfileAdapter *profileAdapter); + VisitedLinksManagerQt(ProfileQt *profile, bool persistVisitedLinks); void deleteAllVisitedLinkData(); void deleteVisitedLinkDataForUrls(const QList<QUrl> &); diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 21540f5da..607412e16 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -43,15 +43,14 @@ #include "web_contents_adapter.h" -#include "browser_accessibility_qt.h" -#include "profile_adapter_client.h" -#include "profile_adapter.h" #include "devtools_frontend_qt.h" #include "download_manager_delegate_qt.h" #include "media_capture_devices_dispatcher.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "printing/print_view_manager_qt.h" #endif +#include "profile_adapter_client.h" +#include "profile_adapter.h" #include "profile_qt.h" #include "qwebenginecallback_p.h" #include "render_view_observer_host_qt.h" @@ -63,9 +62,11 @@ #include "base/command_line.h" #include "base/run_loop.h" +#include "base/task/post_task.h" #include "base/values.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/download_manager.h" @@ -83,7 +84,9 @@ #include "content/public/common/url_constants.h" #include "content/public/common/web_preferences.h" #include "content/public/common/webrtc_ip_handling_policy.h" -#include "third_party/blink/public/web/web_find_options.h" +#include "extensions/buildflags/buildflags.h" +#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h" +//#include "third_party/blink/public/web/web_find_options.h" #include "third_party/blink/public/web/web_media_player_action.h" #include "printing/buildflags/buildflags.h" #include "ui/base/clipboard/clipboard.h" @@ -95,6 +98,10 @@ #include <QtWebChannel/QWebChannel> #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/extension_web_contents_observer_qt.h" +#endif + #include <QDir> #include <QGuiApplication> #include <QPageLayout> @@ -105,10 +112,14 @@ #include <QtCore/qelapsedtimer.h> #include <QtCore/qmimedata.h> #include <QtCore/qtemporarydir.h> -#include <QtGui/qaccessible.h> #include <QtGui/qdrag.h> #include <QtGui/qpixmap.h> +// Can't include headers as qaccessible.h conflicts with Chromium headers. +namespace content { +extern QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *acc); +} + namespace QtWebEngineCore { #define CHECK_INITIALIZED(return_value) \ @@ -117,7 +128,7 @@ namespace QtWebEngineCore { #define CHECK_VALID_RENDER_WIDGET_HOST_VIEW(render_view_host) \ if (!render_view_host->IsRenderViewLive() && render_view_host->GetWidget()->GetView()) { \ - qWarning("Ignore navigation due to terminated render process with invalid RenderWidgetHostView."); \ + LOG(WARNING) << "Ignore navigation due to terminated render process with invalid RenderWidgetHostView."; \ return; \ } @@ -190,7 +201,7 @@ static QVariant fromJSValue(const base::Value *result) } case base::Value::Type::BINARY: { - QByteArray data(result->GetBlob().data(), result->GetBlob().size()); + QByteArray data(reinterpret_cast<const char *>(result->GetBlob().data()), result->GetBlob().size()); ret.setValue(data); break; } @@ -210,10 +221,10 @@ static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint6 #if QT_CONFIG(webengine_printing_and_pdf) static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, int requestId, - const std::vector<char>& result) + QSharedPointer<QByteArray> result) { if (requestId) - adapterClient->didPrintPage(requestId, QByteArray(result.data(), result.size())); + adapterClient->didPrintPage(requestId, result); } static void callbackOnPdfSavingFinished(WebContentsAdapterClient *adapterClient, @@ -229,9 +240,13 @@ static std::unique_ptr<content::WebContents> createBlankWebContents(WebContentsA content::WebContents::CreateParams create_params(browserContext, NULL); create_params.routing_id = MSG_ROUTING_NONE; create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight); - create_params.context = reinterpret_cast<gfx::NativeView>(adapterClient); create_params.initially_hidden = true; - return content::WebContents::Create(create_params); + + std::unique_ptr<content::WebContents> webContents = content::WebContents::Create(create_params); + WebContentsViewQt* contentsView = static_cast<WebContentsViewQt*>(static_cast<content::WebContentsImpl*>(webContents.get())->GetView()); + contentsView->setClient(adapterClient); + + return webContents; } static void serializeNavigationHistory(const content::NavigationController &controller, QDataStream &output) @@ -457,7 +472,6 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) if (!m_webContents) { content::WebContents::CreateParams create_params(m_profileAdapter->profile(), site); create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight); - create_params.context = reinterpret_cast<gfx::NativeView>(m_adapterClient); create_params.initially_hidden = true; m_webContents = content::WebContents::Create(create_params); } @@ -495,7 +509,7 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) // Let the WebContent's view know about the WebContentsAdapterClient. WebContentsViewQt* contentsView = static_cast<WebContentsViewQt*>(static_cast<content::WebContentsImpl*>(m_webContents.get())->GetView()); - contentsView->initialize(m_adapterClient); + contentsView->setClient(m_adapterClient); // This should only be necessary after having restored the history to a new WebContentsAdapter. m_webContents->GetController().LoadIfNecessary(); @@ -503,6 +517,9 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) #if QT_CONFIG(webengine_printing_and_pdf) PrintViewManagerQt::CreateForWebContents(webContents()); #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::ExtensionWebContentsObserverQt::CreateForWebContents(webContents()); +#endif // Create an instance of WebEngineVisitedLinksManager to catch the first // content::NOTIFICATION_RENDERER_PROCESS_CREATED event. This event will @@ -630,13 +647,12 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) "HTTP-POST data can only be sent over HTTP(S) protocol")); return; } + params.post_data = network::ResourceRequestBody::CreateFromBytes( + (const char*)request.postData().constData(), + request.postData().length()); break; } - params.post_data = network::ResourceRequestBody::CreateFromBytes( - (const char*)request.postData().constData(), - request.postData().length()); - // 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) { @@ -662,8 +678,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request) if (resizeNeeded) { // Schedule navigation on the event loop. - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, base::BindOnce(navigate, this, std::move(params))); + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(navigate, this, std::move(params))); } else { navigate(this, params); } @@ -800,7 +816,7 @@ void WebContentsAdapter::selectAll() void WebContentsAdapter::requestClose() { CHECK_INITIALIZED(); - m_webContents->DispatchBeforeUnload(); + m_webContents->DispatchBeforeUnload(false /* auto_cancel */); } void WebContentsAdapter::unselect() @@ -932,8 +948,8 @@ QAccessibleInterface *WebContentsAdapter::browserAccessible() if (!manager) // FIXME! return nullptr; content::BrowserAccessibility *acc = manager->GetRoot(); - content::BrowserAccessibilityQt *accQt = static_cast<content::BrowserAccessibilityQt*>(acc); - return accQt; + + return content::toQAccessibleInterface(acc); } #endif // QT_NO_ACCESSIBILITY @@ -990,16 +1006,16 @@ quint64 WebContentsAdapter::findText(const QString &subString, bool caseSensitiv m_adapterClient->didFindText(m_lastFindRequestId, 0); } - blink::WebFindOptions options; - options.forward = !findBackward; - options.match_case = caseSensitively; - options.find_next = subString == m_webContentsDelegate->lastSearchedString(); + blink::mojom::FindOptionsPtr options = blink::mojom::FindOptions::New(); + options->forward = !findBackward; + options->match_case = caseSensitively; + options->find_next = subString == m_webContentsDelegate->lastSearchedString(); m_webContentsDelegate->setLastSearchedString(subString); // Find already allows a request ID as input, but only as an int. // Use the same counter but mod it to MAX_INT, this keeps the same likeliness of request ID clashing. int shrunkRequestId = m_nextRequestId++ & 0x7fffffff; - m_webContents->Find(shrunkRequestId, toString16(subString), options); + m_webContents->Find(shrunkRequestId, toString16(subString), std::move(options)); m_lastFindRequestId = shrunkRequestId; return shrunkRequestId; } @@ -1257,6 +1273,12 @@ void WebContentsAdapter::runGeolocationRequestCallback(const QUrl &securityOrigi m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::GeolocationPermission, allowed); } +void WebContentsAdapter::runUserNotificationRequestCallback(const QUrl &securityOrigin, bool allowed) +{ + CHECK_INITIALIZED(); + m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::NotificationPermission, allowed); +} + void WebContentsAdapter::grantMouseLockPermission(bool granted) { CHECK_INITIALIZED(); @@ -1271,16 +1293,6 @@ void WebContentsAdapter::grantMouseLockPermission(bool granted) m_webContents->GotResponseToLockMouseRequest(granted); } -void WebContentsAdapter::dpiScaleChanged() -{ - CHECK_INITIALIZED(); - content::RenderWidgetHostImpl* impl = NULL; - if (m_webContents->GetRenderViewHost()) - impl = content::RenderWidgetHostImpl::From(m_webContents->GetRenderViewHost()->GetWidget()); - if (impl) - impl->NotifyScreenInfoChanged(); -} - void WebContentsAdapter::setBackgroundColor(const QColor &color) { CHECK_INITIALIZED(); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index e8e5359be..c6e4f2256 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -183,8 +183,8 @@ public: void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed); void grantMouseLockPermission(bool granted); + void runUserNotificationRequestCallback(const QUrl &securityOrigin, bool allowed); - void dpiScaleChanged(); void setBackgroundColor(const QColor &color); QAccessibleInterface *browserAccessible(); ProfileQt* profile(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 28be33c23..cdfcae450 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -66,6 +66,7 @@ QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QVariant) QT_FORWARD_DECLARE_CLASS(QWebEngineQuotaRequest) QT_FORWARD_DECLARE_CLASS(QWebEngineRegisterProtocolHandlerRequest) +QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInfo) namespace content { struct DropData; @@ -81,6 +82,8 @@ class JavaScriptDialogController; class RenderWidgetHostViewQt; class RenderWidgetHostViewQtDelegate; class RenderWidgetHostViewQtDelegateClient; +class TouchHandleDrawableClient; +class TouchSelectionMenuController; class WebContentsAdapter; class WebContentsDelegateQt; class WebEngineSettings; @@ -421,7 +424,6 @@ public: virtual void selectionChanged() = 0; virtual void recentlyAudibleChanged(bool recentlyAudible) = 0; virtual QRectF viewportRect() const = 0; - virtual qreal dpiScale() const = 0; virtual QColor backgroundColor() const = 0; virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0; virtual void loadCommitted() = 0; @@ -444,7 +446,7 @@ public: virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) = 0; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0; virtual void didFindText(quint64 requestId, int matchCount) = 0; - virtual void didPrintPage(quint64 requestId, const QByteArray &result) = 0; + virtual void didPrintPage(quint64 requestId, QSharedPointer<QByteArray>) = 0; virtual void didPrintPageToPdf(const QString &filePath, bool success) = 0; virtual void passOnFocus(bool reverse) = 0; // returns the last QObject (QWidget/QQuickItem) based object in the accessibility @@ -457,6 +459,7 @@ public: virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runQuotaRequest(QWebEngineQuotaRequest) = 0; virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0; + virtual void runUserNotificationPermissionRequest(const QUrl &securityOrigin) = 0; virtual WebEngineSettings *webEngineSettings() const = 0; RenderProcessTerminationStatus renderProcessExitStatus(int); virtual void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) = 0; @@ -475,6 +478,10 @@ public: virtual ClientType clientType() = 0; virtual void printRequested() = 0; virtual void widgetChanged(RenderWidgetHostViewQtDelegate *newWidget) = 0; + virtual void interceptRequest(QWebEngineUrlRequestInfo &) { } + 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; virtual ProfileAdapter *profileAdapter() = 0; virtual WebContentsAdapter* webContentsAdapter() = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 4bde93fd3..ade29c770 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -58,13 +58,16 @@ #include "visited_links_manager_qt.h" #include "web_contents_adapter_client.h" #include "web_contents_adapter.h" +#include "web_contents_view_qt.h" #include "web_engine_context.h" #include "web_engine_settings.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "components/web_cache/browser/web_cache_manager.h" #include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/file_select_listener.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" @@ -73,7 +76,6 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/favicon_url.h" -#include "content/public/common/file_chooser_params.h" #include "content/public/common/frame_navigate_params.h" #include "content/public/common/url_constants.h" #include "content/public/common/web_preferences.h" @@ -414,9 +416,11 @@ void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::Favic void WebContentsDelegateQt::WebContentsCreated(content::WebContents */*source_contents*/, int /*opener_render_process_id*/, int /*opener_render_frame_id*/, const std::string &/*frame_name*/, - const GURL &target_url, content::WebContents */*new_contents*/) + const GURL &target_url, content::WebContents *newContents) { m_initialTargetUrl = toQt(target_url); + if (auto *view = static_cast<content::WebContentsImpl *>(newContents)->GetView()) + static_cast<WebContentsViewQt *>(view)->setFactoryClient(m_viewClient); } content::ColorChooser *WebContentsDelegateQt::OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<blink::mojom::ColorSuggestionPtr> &suggestion) @@ -451,12 +455,14 @@ bool WebContentsDelegateQt::IsFullscreenForTabOrPending(const content::WebConten return m_viewClient->isFullScreenMode(); } -ASSERT_ENUMS_MATCH(FilePickerController::Open, content::FileChooserParams::Open) -ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParams::OpenMultiple) -ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) -ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) +ASSERT_ENUMS_MATCH(FilePickerController::Open, blink::mojom::FileChooserParams::Mode::kOpen) +ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, blink::mojom::FileChooserParams::Mode::kOpenMultiple) +ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, blink::mojom::FileChooserParams::Mode::kUploadFolder) +ASSERT_ENUMS_MATCH(FilePickerController::Save, blink::mojom::FileChooserParams::Mode::kSave) -void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost *frameHost, const content::FileChooserParams ¶ms) +void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost * /*frameHost*/, + std::unique_ptr<content::FileSelectListener> listener, + const blink::mojom::FileChooserParams& params) { QStringList acceptedMimeTypes; acceptedMimeTypes.reserve(params.accept_types.size()); @@ -464,7 +470,7 @@ void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost *frameHost, acceptedMimeTypes.append(toQt(*it)); m_filePickerController.reset(new FilePickerController(static_cast<FilePickerController::FileChooserMode>(params.mode), - frameHost, toQt(params.default_file_name.value()), acceptedMimeTypes)); + std::move(listener), toQt(params.default_file_name.value()), acceptedMimeTypes)); // Defer the call to not block base::MessageLoop::RunTask with modal dialogs. QTimer::singleShot(0, [this] () { @@ -583,6 +589,11 @@ void WebContentsDelegateQt::requestGeolocationPermission(const QUrl &requestingO m_viewClient->runGeolocationPermissionRequest(requestingOrigin); } +void WebContentsDelegateQt::requestUserNotificationPermission(const QUrl &requestingOrigin) +{ + m_viewClient->runUserNotificationPermissionRequest(requestingOrigin); +} + extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) @@ -633,7 +644,9 @@ void WebContentsDelegateQt::BeforeUnloadFired(content::WebContents *tab, bool pr m_viewClient->windowCloseRejected(); } -void WebContentsDelegateQt::BeforeUnloadFired(const base::TimeTicks &proceed_time) { +void WebContentsDelegateQt::BeforeUnloadFired(bool proceed, const base::TimeTicks &proceed_time) +{ + Q_UNUSED(proceed); Q_UNUSED(proceed_time); } diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 9c0f8f484..77f6cc389 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -114,7 +114,9 @@ public: void EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL &origin, const blink::WebFullscreenOptions &) override; void ExitFullscreenModeForTab(content::WebContents*) override; bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const override; - void RunFileChooser(content::RenderFrameHost* render_frame_host, const content::FileChooserParams& params) override; + void RunFileChooser(content::RenderFrameHost* render_frame_host, + std::unique_ptr<content::FileSelectListener> listener, + const blink::mojom::FileChooserParams& params) override; bool DidAddMessageToConsole(content::WebContents* source, int32_t level, const base::string16& message, int32_t line_no, const base::string16& source_id) override; void FindReply(content::WebContents *source, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) override; void RequestMediaAccessPermission(content::WebContents *web_contents, @@ -135,7 +137,7 @@ public: void DidFinishNavigation(content::NavigationHandle *navigation_handle) override; void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code, const base::string16& error_description) override; void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) override; - void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; + void BeforeUnloadFired(bool proceed, const base::TimeTicks& proceed_time) override; void DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) override; void OnVisibilityChanged(content::Visibility visibility) override; void DidFirstVisuallyNonEmptyPaint() override; @@ -146,6 +148,7 @@ public: void allowCertificateError(const QSharedPointer<CertificateErrorController> &); void selectClientCert(const QSharedPointer<ClientCertSelectController> &); void requestGeolocationPermission(const QUrl &requestingOrigin); + void requestUserNotificationPermission(const QUrl &requestingOrigin); void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture); FaviconManager *faviconManager(); diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 3c4465ae3..7177a8713 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -41,24 +41,40 @@ #include "profile_adapter.h" #include "content_browser_client_qt.h" +#include "render_widget_host_view_qt.h" #include "render_widget_host_view_qt_delegate.h" #include "render_widget_host_view_qt.h" +#include "touch_selection_controller_client_qt.h" #include "type_conversion.h" +#include "web_contents_adapter_client.h" #include "web_contents_adapter.h" #include "web_engine_context.h" +#include "web_contents_delegate_qt.h" #include "components/spellcheck/spellcheck_buildflags.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/common/context_menu_params.h" -#include <ui/gfx/image/image_skia.h> +#include "ui/gfx/image/image_skia.h" #include <QtGui/qpixmap.h> namespace QtWebEngineCore { -void WebContentsViewQt::initialize(WebContentsAdapterClient* client) +void WebContentsViewQt::setFactoryClient(WebContentsAdapterClient* client) +{ + if (m_factoryClient) + return; + m_factoryClient = 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)); + } +} + +void WebContentsViewQt::setClient(WebContentsAdapterClient* client) { m_client = client; m_factoryClient = client; @@ -74,15 +90,16 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForWidget(conten { RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); - Q_ASSERT(m_factoryClient); - view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); - if (m_client) - view->setAdapterClient(m_client); + if (m_factoryClient) { + view->setDelegate(m_factoryClient->CreateRenderWidgetHostViewQtDelegate(view)); + if (m_client) + view->setAdapterClient(m_client); + } return view; } -content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForPopupWidget(content::RenderWidgetHost* render_widget_host) +content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForChildWidget(content::RenderWidgetHost* render_widget_host) { RenderWidgetHostViewQt *view = new RenderWidgetHostViewQt(render_widget_host); @@ -95,15 +112,11 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForPopupWidget(c void WebContentsViewQt::CreateView(const gfx::Size& initial_size, gfx::NativeView context) { - // This is passed through content::WebContents::CreateParams::context either as the native view's client - // directly or, in the case of a page-created new window, the client of the creating window's native view. - m_factoryClient = reinterpret_cast<WebContentsAdapterClient *>(context); } gfx::NativeView WebContentsViewQt::GetNativeView() const { - // Hack to provide the client to WebContentsImpl::CreateNewWindow. - return reinterpret_cast<gfx::NativeView>(m_client); + return nullptr; } void WebContentsViewQt::GetContainerBounds(gfx::Rect* out) const @@ -186,6 +199,11 @@ static inline WebEngineContextMenuData fromParams(const content::ContextMenuPara 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(fromParams(params)); #if QT_CONFIG(webengine_spellchecker) // Do not use params.spellcheck_enabled, since it is never @@ -230,7 +248,7 @@ void WebContentsViewQt::StartDragging(const content::DropData &drop_data, QPixmap pixmap; QPoint hotspot; - pixmap = QPixmap::fromImage(toQImage(image.GetRepresentation(m_client->dpiScale()))); + pixmap = QPixmap::fromImage(toQImage(image.GetRepresentation(1.0))); if (!pixmap.isNull()) { hotspot.setX(image_offset.x()); hotspot.setY(image_offset.y()); diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index d1a2ff81e..7cd3910f2 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -63,17 +63,17 @@ public: : m_webContents(webContents) , m_client(nullptr) , m_factoryClient(nullptr) - , m_allowOtherViews(false) { } - void initialize(WebContentsAdapterClient* client); + void setFactoryClient(WebContentsAdapterClient* client); + void setClient(WebContentsAdapterClient* client); WebContentsAdapterClient *client() { return m_client; } content::RenderWidgetHostViewBase *CreateViewForWidget(content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) override; void CreateView(const gfx::Size& initial_size, gfx::NativeView context) override; - content::RenderWidgetHostViewBase* CreateViewForPopupWidget(content::RenderWidgetHost* render_widget_host) override; + content::RenderWidgetHostViewBase *CreateViewForChildWidget(content::RenderWidgetHost* render_widget_host) override; void SetPageTitle(const base::string16& title) override { } @@ -83,29 +83,29 @@ public: void RenderViewHostChanged(content::RenderViewHost*, content::RenderViewHost*) override { } - void SetOverscrollControllerEnabled(bool enabled) override { QT_NOT_YET_IMPLEMENTED } + void SetOverscrollControllerEnabled(bool enabled) override { } gfx::NativeView GetNativeView() const override; - gfx::NativeView GetContentNativeView() const override { QT_NOT_USED return 0; } + gfx::NativeView GetContentNativeView() const override { return nullptr; } - gfx::NativeWindow GetTopLevelNativeWindow() const override { QT_NOT_USED return 0; } + gfx::NativeWindow GetTopLevelNativeWindow() const override { return nullptr; } void GetContainerBounds(gfx::Rect* out) const override; - void SizeContents(const gfx::Size& size) override { QT_NOT_YET_IMPLEMENTED } + void SizeContents(const gfx::Size& size) override { } void Focus() override; void SetInitialFocus() override; - void StoreFocus() override { QT_NOT_USED } + void StoreFocus() override { } - void RestoreFocus() override { QT_NOT_USED } + void RestoreFocus() override { } content::DropData* GetDropData() const override { QT_NOT_YET_IMPLEMENTED return nullptr; } - gfx::Rect GetViewBounds() const override { QT_NOT_YET_IMPLEMENTED return gfx::Rect(); } + gfx::Rect GetViewBounds() const override { return gfx::Rect(); } void StartDragging(const content::DropData& drop_data, blink::WebDragOperationsMask allowed_ops, const gfx::ImageSkia& image, const gfx::Vector2d& image_offset, @@ -122,8 +122,6 @@ public: #if defined(OS_MACOSX) - void SetAllowOtherViews(bool allow) override { m_allowOtherViews = allow; } - bool GetAllowOtherViews() const override { return m_allowOtherViews; } void CloseTabAfterEventTracking() override { QT_NOT_YET_IMPLEMENTED } bool IsEventTracking() const override { QT_NOT_YET_IMPLEMENTED; return false; } #endif // defined(OS_MACOSX) @@ -132,7 +130,6 @@ private: content::WebContents *m_webContents; WebContentsAdapterClient *m_client; WebContentsAdapterClient *m_factoryClient; - bool m_allowOtherViews; }; } // namespace QtWebEngineCore diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index edae5c47d..e9a941bf2 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -46,21 +46,23 @@ #include "base/files/file_path.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/task/post_task.h" #include "base/threading/thread_restrictions.h" #include "cc/base/switches.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "chrome/browser/printing/print_job_manager.h" +#include "components/printing/browser/features.h" #endif #include "components/viz/common/features.h" #include "components/web_cache/browser/web_cache_manager.h" #include "content/browser/devtools/devtools_http_handler.h" -#include "content/browser/gpu/gpu_main_thread_factory.h" -#include "content/browser/renderer_host/render_process_host_impl.h" -#include "content/browser/utility_process_host.h" -#include "content/gpu/in_process_gpu_thread.h" +#include "content/browser/scheduler/browser_task_executor.h" +#include "content/browser/startup_helper.h" #include "content/public/app/content_main.h" #include "content/public/app/content_main_runner.h" #include "content/public/browser/browser_main_runner.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -68,9 +70,8 @@ #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" -#include "content/renderer/in_process_renderer_thread.h" -#include "content/utility/in_process_utility_thread.h" #include "gpu/command_buffer/service/gpu_switches.h" +#include "gpu/command_buffer/service/sync_point_manager.h" #include "gpu/ipc/host/gpu_switches.h" #include "media/audio/audio_manager.h" #include "mojo/core/embedder/embedder.h" @@ -86,20 +87,24 @@ #include "content/public/app/sandbox_helper_win.h" #endif // OS_WIN +#ifndef QT_NO_ACCESSIBILITY +#include "accessibility_activation_observer.h" +#endif #include "api/qwebengineurlscheme.h" -#include "profile_adapter.h" #include "content_browser_client_qt.h" #include "content_client_qt.h" #include "content_main_delegate_qt.h" #include "devtools_manager_delegate_qt.h" #include "media_capture_devices_dispatcher.h" #include "net/webui_controller_factory_qt.h" -#include "type_conversion.h" #include "ozone/gl_context_qt.h" +#include "profile_adapter.h" +#include "type_conversion.h" #include "web_engine_library_info.h" #include <QFileInfo> #include <QGuiApplication> +#include <QMutex> #include <QOffscreenSurface> #ifndef QT_NO_OPENGL # include <QOpenGLContext> @@ -108,7 +113,9 @@ #include <QStringList> #include <QSurfaceFormat> #include <QVector> -#include <qpa/qplatformnativeinterface.h> +#include <QNetworkProxy> +#include <QtGui/qpa/qplatformintegration.h> +#include <QtGui/private/qguiapplication_p.h> using namespace QtWebEngineCore; @@ -132,10 +139,13 @@ bool usingANGLE() #endif } -bool usingQtQuick2DRenderer() +bool usingDefaultSGBackend() { const QStringList args = QGuiApplication::arguments(); - QString device; + + //folow logic from contextFactory in src/quick/scenegraph/qsgcontextplugin.cpp + QString device = QQuickWindow::sceneGraphBackend(); + for (int index = 0; index < args.count(); ++index) { if (args.at(index).startsWith(QLatin1String("--device="))) { device = args.at(index).mid(9); @@ -144,16 +154,11 @@ bool usingQtQuick2DRenderer() } if (device.isEmpty()) - device = QQuickWindow::sceneGraphBackend(); - if (device.isEmpty()) device = QString::fromLocal8Bit(qgetenv("QT_QUICK_BACKEND")); if (device.isEmpty()) device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE")); - if (device.isEmpty()) - device = QLatin1String("default"); - // Anything other than the default OpenGL device will need to render in 2D mode. - return device != QLatin1String("default"); + return device.isEmpty(); } #endif //QT_NO_OPENGL #if QT_CONFIG(webengine_pepper_plugins) @@ -166,6 +171,8 @@ void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&) namespace QtWebEngineCore { +extern std::unique_ptr<base::MessagePump> messagePumpFactory(); + bool usingSoftwareDynamicGL() { if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL)) @@ -224,6 +231,12 @@ void WebEngineContext::destroy() { if (m_devtoolsServer) m_devtoolsServer->stop(); + + // Normally the GPU thread is shut down when the GpuProcessHost is destroyed + // on IO thread (triggered by ~BrowserMainRunner). But by that time the UI + // task runner is not working anymore so we need to do this earlier. + destroyGpuProcess(); + base::MessagePump::Delegate *delegate = static_cast<base::MessageLoop *>(m_runLoop->delegate_); // Flush the UI message loop before quitting. @@ -273,6 +286,7 @@ WebEngineContext::~WebEngineContext() Q_ASSERT(!m_devtoolsServer); Q_ASSERT(!m_browserRunner); Q_ASSERT(m_profileAdapters.isEmpty()); + delete s_syncPointManager.fetchAndStoreRelaxed(nullptr); } WebEngineContext *WebEngineContext::current() @@ -312,7 +326,7 @@ void WebEngineContext::destroyContextPostRoutine() // Destroy WebEngineContext before its static pointer is zeroed and destructor called. // Before destroying MessageLoop via destroying BrowserMainRunner destructor // WebEngineContext's pointer is used. - m_handle->destroy(); + m_handle->destroy(); #if !defined(NDEBUG) if (!m_handle->HasOneRef()) qWarning("WebEngineContext leaked on exit, likely due to leaked WebEngine View or Page"); @@ -321,6 +335,18 @@ void WebEngineContext::destroyContextPostRoutine() m_destroyed = true; } +ProxyAuthentication WebEngineContext::qProxyNetworkAuthentication(QString host, int port) +{ + if (!QNetworkProxyFactory::usesSystemConfiguration()) { + QNetworkProxy proxy = QNetworkProxy::applicationProxy(); + if (host == proxy.hostName() && port == proxy.port() && !proxy.user().isEmpty() + && !proxy.password().isEmpty()) { + return std::make_tuple(true, proxy.user(), proxy.password()); + } + } + return std::make_tuple(false, QString(), QString()); +} + #ifndef CHROMIUM_VERSION #error Chromium version should be defined at gyp-time. Something must have gone wrong #define CHROMIUM_VERSION // This is solely to keep Qt Creator happy. @@ -347,6 +373,7 @@ WebEngineContext::WebEngineContext() base::TaskScheduler::Create("Browser"); m_contentRunner.reset(content::ContentMainRunner::Create()); m_browserRunner.reset(content::BrowserMainRunner::Create()); + #ifdef Q_OS_LINUX // Call qputenv before BrowserMainRunnerImpl::Initialize is called. // http://crbug.com/245466 @@ -367,33 +394,22 @@ WebEngineContext::WebEngineContext() // Allow us to inject javascript like any webview toolkit. content::RenderFrameHost::AllowInjectingJavaScriptForAndroidWebView(); - base::CommandLine::CreateEmpty(); - base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); QStringList appArgs = QCoreApplication::arguments(); - if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { - appArgs = appArgs.mid(0, 1); // Take application name and drop the rest - appArgs.append(QString::fromLocal8Bit(qgetenv(kChromiumFlagsEnv)).split(' ')); - } - bool enableWebGLSoftwareRendering = - appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); + // 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.removeAll(QStringLiteral("--disable-embedded-switches")); + useEmbeddedSwitches = !appArgs.contains(QStringLiteral("--disable-embedded-switches")); #else - useEmbeddedSwitches = appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); + useEmbeddedSwitches = appArgs.contains(QStringLiteral("--enable-embedded-switches")); #endif - base::CommandLine::StringVector argv; - argv.resize(appArgs.size()); -#if defined(Q_OS_WIN) - for (int i = 0; i < appArgs.size(); ++i) - argv[i] = toString16(appArgs[i]); -#else - for (int i = 0; i < appArgs.size(); ++i) - argv[i] = appArgs[i].toStdString(); -#endif - parsedCommandLine->InitFromArgv(argv); + + base::CommandLine* parsedCommandLine = commandLine(); parsedCommandLine->AppendSwitchPath(switches::kBrowserSubprocessPath, WebEngineLibraryInfo::getPath(content::CHILD_PROCESS_EXE)); @@ -426,8 +442,6 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kDisablePepper3DImageChromium); // Same problem with select popups. parsedCommandLine->AppendSwitch(switches::kDisableNativeGpuMemoryBuffers); - // SandboxV2 doesn't currently work for us - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kMacV2Sandbox.name); #endif #if defined(Q_OS_WIN) @@ -435,10 +449,23 @@ WebEngineContext::WebEngineContext() // 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. - // Given that Core profile is not currently supported on Windows anyway, pass this switch to - // get rid of the warnings. - parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext); + // 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 // Needed to allow navigations within pages that were set using setHtml(). One example is // tst_QWebEnginePage::acceptNavigationRequest. @@ -449,8 +476,12 @@ WebEngineContext::WebEngineContext() appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kEnableSurfaceSynchronization.name); // The video-capture service is not functioning at this moment (since 69) appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kMojoVideoCapture.name); - // We do not yet support the internal video capture API. - appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kUseVideoCaptureApiForDevToolsSnapshots.name); + + appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, features::kBackgroundFetch.name); + +#if QT_CONFIG(webengine_printing_and_pdf) + appendToFeatureSwitch(parsedCommandLine, switches::kDisableFeatures, printing::features::kUsePdfCompositorServiceForPrint.name); +#endif if (useEmbeddedSwitches) { // embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc @@ -470,22 +501,18 @@ WebEngineContext::WebEngineContext() const char *glType = 0; #ifndef QT_NO_OPENGL - bool tryGL = - !usingANGLE() - && (!usingSoftwareDynamicGL() - // If user requested WebGL 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. - || enableWebGLSoftwareRendering - ) - && !usingQtQuick2DRenderer(); - + 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, and finally Ozone demands GL ES/2 too. + // 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")) + || !strcmp(qt_gl_global_share_context()->nativeHandle().typeName(), + "QEGLNativeContext") + || usingANGLE()) { if (qt_gl_global_share_context()->isOpenGLES()) { glType = gl::kGLImplementationEGLName; @@ -543,7 +570,7 @@ WebEngineContext::WebEngineContext() if (glType) { parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); parsedCommandLine->AppendSwitch(switches::kInProcessGPU); - if (enableWebGLSoftwareRendering) { + if (enableGLSoftwareRendering) { parsedCommandLine->AppendSwitch(switches::kDisableGpuRasterization); parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlacklist); } @@ -551,9 +578,16 @@ WebEngineContext::WebEngineContext() parsedCommandLine->AppendSwitch(switches::kDisableGpu); } - content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); - content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); - content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread); + bool threadedGpu = true; +#ifndef QT_NO_OPENGL + threadedGpu = QOpenGLContext::supportsThreadedOpenGL(); +#endif + registerMainThreadFactories(threadedGpu); + + SetContentClient(new ContentClientQt); + + content::StartBrowserTaskScheduler(); + content::BrowserTaskExecutor::Create(); mojo::core::Init(); @@ -605,6 +639,10 @@ WebEngineContext::WebEngineContext() m_printJobManager.reset(new printing::PrintJobManager()); #endif +#ifndef QT_NO_ACCESSIBILITY + m_accessibilityActivationObserver.reset(new AccessibilityActivationObserver()); +#endif + content::WebUIControllerFactory::RegisterFactory(WebUIControllerFactoryQt::GetInstance()); } @@ -614,4 +652,48 @@ printing::PrintJobManager* WebEngineContext::getPrintJobManager() return m_printJobManager.get(); } #endif + +static QMutex s_spmMutex; +QAtomicPointer<gpu::SyncPointManager> WebEngineContext::s_syncPointManager; + +gpu::SyncPointManager *WebEngineContext::syncPointManager() +{ + if (gpu::SyncPointManager *spm = s_syncPointManager.loadAcquire()) + return spm; + QMutexLocker lock(&s_spmMutex); + if (!s_syncPointManager) + s_syncPointManager.store(new gpu::SyncPointManager()); + return s_syncPointManager.load(); +} + +base::CommandLine* WebEngineContext::commandLine() { + if (base::CommandLine::CreateEmpty()) { + base::CommandLine* parsedCommandLine = base::CommandLine::ForCurrentProcess(); + QStringList appArgs = QCoreApplication::arguments(); + if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) { + appArgs = appArgs.mid(0, 1); // Take application name and drop the rest + appArgs.append(QString::fromLocal8Bit(qgetenv(kChromiumFlagsEnv)).split(' ')); + } +#ifdef Q_OS_WIN + appArgs.removeAll(QStringLiteral("--enable-webgl-software-rendering")); +#endif + appArgs.removeAll(QStringLiteral("--disable-embedded-switches")); + appArgs.removeAll(QStringLiteral("--enable-embedded-switches")); + + base::CommandLine::StringVector argv; + argv.resize(appArgs.size()); +#if defined(Q_OS_WIN) + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = toString16(appArgs[i]); +#else + for (int i = 0; i < appArgs.size(); ++i) + argv[i] = appArgs[i].toStdString(); +#endif + parsedCommandLine->InitFromArgv(argv); + return parsedCommandLine; + } else { + return base::CommandLine::ForCurrentProcess(); + } +} + } // namespace diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index 604c85a61..2364bacbe 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -47,11 +47,20 @@ namespace base { class RunLoop; +class CommandLine; } namespace content { class BrowserMainRunner; class ContentMainRunner; +class GpuProcess; +class GpuThreadController; +class InProcessChildThreadParams; +} + +namespace gpu { +struct GpuPreferences; +class SyncPointManager; } #if QT_CONFIG(webengine_printing_and_pdf) @@ -64,16 +73,20 @@ QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { -class ProfileAdapter; +class AccessibilityActivationObserver; class ContentMainDelegateQt; class DevToolsServerQt; +class ProfileAdapter; bool usingSoftwareDynamicGL(); +typedef std::tuple<bool, QString, QString> ProxyAuthentication; + class WebEngineContext : public base::RefCounted<WebEngineContext> { public: static WebEngineContext *current(); static void destroyContextPostRoutine(); + static ProxyAuthentication qProxyNetworkAuthentication(QString host, int port); ProfileAdapter *createDefaultProfileAdapter(); ProfileAdapter *defaultProfileAdapter(); @@ -86,6 +99,9 @@ public: void addProfileAdapter(ProfileAdapter *profileAdapter); void removeProfileAdapter(ProfileAdapter *profileAdapter); void destroy(); + static base::CommandLine* commandLine(); + + static gpu::SyncPointManager *syncPointManager(); private: friend class base::RefCounted<WebEngineContext>; @@ -93,6 +109,9 @@ private: WebEngineContext(); ~WebEngineContext(); + static void registerMainThreadFactories(bool threaded); + static void destroyGpuProcess(); + std::unique_ptr<base::RunLoop> m_runLoop; std::unique_ptr<ContentMainDelegateQt> m_mainDelegate; std::unique_ptr<content::ContentMainRunner> m_contentRunner; @@ -101,12 +120,16 @@ private: std::unique_ptr<ProfileAdapter> m_defaultProfileAdapter; std::unique_ptr<DevToolsServerQt> m_devtoolsServer; QVector<ProfileAdapter*> m_profileAdapters; +#ifndef QT_NO_ACCESSIBILITY + std::unique_ptr<AccessibilityActivationObserver> m_accessibilityActivationObserver; +#endif #if QT_CONFIG(webengine_printing_and_pdf) std::unique_ptr<printing::PrintJobManager> m_printJobManager; #endif static scoped_refptr<QtWebEngineCore::WebEngineContext> m_handle; static bool m_destroyed; + static QAtomicPointer<gpu::SyncPointManager> s_syncPointManager; }; } // namespace diff --git a/src/core/web_engine_context_threads.cpp b/src/core/web_engine_context_threads.cpp new file mode 100644 index 000000000..07a86cc69 --- /dev/null +++ b/src/core/web_engine_context_threads.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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 "web_engine_context.h" + +#include "base/bind.h" +#include "base/task/post_task.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread_restrictions.h" +#include "content/browser/gpu/gpu_main_thread_factory.h" +#include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/browser/utility_process_host.h" +#include "content/gpu/gpu_child_thread.h" +#include "content/gpu/gpu_process.h" +#include "content/gpu/in_process_gpu_thread.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/renderer/in_process_renderer_thread.h" +#include "content/utility/in_process_utility_thread.h" + +#include <memory> + +namespace QtWebEngineCore { + +struct GpuThreadControllerQt : content::GpuThreadController +{ + GpuThreadControllerQt(const content::InProcessChildThreadParams ¶ms, const gpu::GpuPreferences &gpuPreferences) + { + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&GpuThreadControllerQt::createGpuProcess, params, gpuPreferences)); + } + ~GpuThreadControllerQt() override + { + base::PostTaskWithTraits( + FROM_HERE, { content::BrowserThread::UI }, + base::BindOnce(&GpuThreadControllerQt::destroyGpuProcess)); + } + + static void createGpuProcess( + const content::InProcessChildThreadParams ¶ms, + const gpu::GpuPreferences &gpuPreferences) + { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (s_gpuProcessDestroyed) + return; + + s_gpuProcess = std::make_unique<content::GpuProcess>(base::ThreadPriority::NORMAL); + auto gpuInit = std::make_unique<gpu::GpuInit>(); + gpuInit->InitializeInProcess(base::CommandLine::ForCurrentProcess(), gpuPreferences); + auto childThread = new content::GpuChildThread(params, std::move(gpuInit)); + childThread->Init(base::Time::Now()); + s_gpuProcess->set_main_thread(childThread); + } + + static void destroyGpuProcess() + { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (s_gpuProcessDestroyed) + return; + + // viz::GpuServiceImpl::~GpuServiceImpl waits for io task. + base::ScopedAllowBaseSyncPrimitivesForTesting allow; + s_gpuProcess.reset(); + s_gpuProcessDestroyed = true; + } + + static std::unique_ptr<content::GpuProcess> s_gpuProcess; + static bool s_gpuProcessDestroyed; +}; + +std::unique_ptr<content::GpuProcess> GpuThreadControllerQt::s_gpuProcess; +bool GpuThreadControllerQt::s_gpuProcessDestroyed = false; + +static std::unique_ptr<content::GpuThreadController> createGpuThreadController( + const content::InProcessChildThreadParams ¶ms, + const gpu::GpuPreferences &gpuPreferences) +{ + return std::make_unique<GpuThreadControllerQt>(params, gpuPreferences); +} + +// static +void WebEngineContext::destroyGpuProcess() +{ + GpuThreadControllerQt::destroyGpuProcess(); +} + +// static +void WebEngineContext::registerMainThreadFactories(bool threaded) +{ + content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); + content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); + if (threaded) + content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread); + else + content::RegisterGpuMainThreadFactory(createGpuThreadController); +} + +} // namespace QtWebEngineCore diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 3899ced25..12ffd91e6 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -54,6 +54,7 @@ #include <QDir> #include <QFileInfo> #include <QLibraryInfo> +#include <QLocale> #include <QStandardPaths> #include <QString> diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 664951e66..705c0c106 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -283,6 +283,11 @@ void WebEngineSettings::initDefaults() s_defaultAttributes.insert(WebRTCPublicInterfacesOnly, false); s_defaultAttributes.insert(JavascriptCanPaste, false); s_defaultAttributes.insert(DnsPrefetchEnabled, false); +#if QT_CONFIG(webengine_extensions) + s_defaultAttributes.insert(PDFViewerEnabled, true); +#else + s_defaultAttributes.insert(PDFViewerEnabled, false); +#endif } if (s_defaultFontFamilies.isEmpty()) { diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index 8930d7c27..8e1bb741c 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -103,6 +103,7 @@ public: WebRTCPublicInterfacesOnly, JavascriptCanPaste, DnsPrefetchEnabled, + PDFViewerEnabled, }; // Must match the values from the public API in qwebenginesettings.h. diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index fc6287dd9..b97696030 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -101,7 +101,7 @@ static KeyboardDriver keyboardDriverImpl() if (platformName == QLatin1Literal("xcb") || platformName == QLatin1Literal("wayland")) return KeyboardDriver::Xkb; -#if QT_CONFIG(libinput) && QT_CONFIG(xkbcommon) +#if QT_CONFIG(libinput) // Based on QEglFSIntegration::createInputHandlers and QLibInputKeyboard::processKey. if (platformName == QLatin1Literal("eglfs") && !qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT")) return KeyboardDriver::Xkb; @@ -1354,10 +1354,10 @@ static WebPointerProperties::PointerType pointerTypeForTabletEvent(const QTablet } #endif -WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) +WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - WebFloatPoint(ev->x() / dpiScale, ev->y() / dpiScale), + WebFloatPoint(ev->x(), ev->y()), WebFloatPoint(ev->globalX(), ev->globalY()), mouseButtonForEvent<QMouseEvent>(ev), 0, @@ -1369,14 +1369,14 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QMouseEvent *ev, double dpiScale) return webKitEvent; } -WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale) +WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev) { WebMouseEvent webKitEvent; webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); webKitEvent.SetType(webEventTypeForEvent(ev)); - webKitEvent.SetPositionInWidget(ev->pos().x() / dpiScale, ev->pos().y() / dpiScale); + 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.pointer_type = WebPointerProperties::PointerType::kMouse; @@ -1385,10 +1385,10 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev, double dpiScale) } #if QT_CONFIG(tabletevent) -WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev, double dpiScale) +WebMouseEvent WebEventFactory::toWebMouseEvent(QTabletEvent *ev) { WebMouseEvent webKitEvent(webEventTypeForEvent(ev), - WebFloatPoint(ev->x() / dpiScale, ev->y() / dpiScale), + WebFloatPoint(ev->x(), ev->y()), WebFloatPoint(ev->globalX(), ev->globalY()), mouseButtonForEvent<QTabletEvent>(ev), 0, @@ -1416,17 +1416,17 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QEvent *ev) } #ifndef QT_NO_GESTURES -WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev, double dpiScale) +WebGestureEvent WebEventFactory::toWebGestureEvent(QNativeGestureEvent *ev) { WebGestureEvent webKitEvent; webKitEvent.SetTimeStamp(base::TimeTicks::Now()); webKitEvent.SetModifiers(modifiersForEvent(ev)); - webKitEvent.SetPositionInWidget(WebFloatPoint(ev->localPos().x() / dpiScale, - ev->localPos().y() / dpiScale)); + webKitEvent.SetPositionInWidget(WebFloatPoint(ev->localPos().x(), + ev->localPos().y())); - webKitEvent.SetPositionInScreen(WebFloatPoint(ev->screenPos().x() / dpiScale, - ev->screenPos().y() / dpiScale)); + webKitEvent.SetPositionInScreen(WebFloatPoint(ev->screenPos().x(), + ev->screenPos().y())); webKitEvent.SetSourceDevice(blink::kWebGestureDeviceTouchpad); @@ -1484,13 +1484,13 @@ blink::WebMouseWheelEvent::Phase toBlinkPhase(QWheelEvent *ev) return blink::WebMouseWheelEvent::kPhaseNone; } -blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, double dpiScale) +blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev) { WebMouseWheelEvent webEvent; webEvent.SetType(webEventTypeForEvent(ev)); webEvent.SetModifiers(modifiersForEvent(ev)); webEvent.SetTimeStamp(base::TimeTicks::Now()); - webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); + webEvent.SetPositionInWidget(ev->x(), ev->y()); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; @@ -1506,7 +1506,7 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub return webEvent; } -bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev, double dpiScale) +bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, QWheelEvent *ev) { if (webEventTypeForEvent(ev) != webEvent.GetType()) return false; @@ -1520,7 +1520,7 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent, #endif webEvent.SetTimeStamp(base::TimeTicks::Now()); - webEvent.SetPositionInWidget(ev->x() / dpiScale, ev->y() / dpiScale); + webEvent.SetPositionInWidget(ev->x(), ev->y()); webEvent.SetPositionInScreen(ev->globalX(), ev->globalY()); webEvent.wheel_ticks_x += static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep; diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h index 4b22de7d7..526202cfb 100644 --- a/src/core/web_event_factory.h +++ b/src/core/web_event_factory.h @@ -66,17 +66,17 @@ QT_END_NAMESPACE class WebEventFactory { public: - static blink::WebMouseEvent toWebMouseEvent(QMouseEvent*, double dpiScale); - static blink::WebMouseEvent toWebMouseEvent(QHoverEvent*, double dpiScale); + static blink::WebMouseEvent toWebMouseEvent(QMouseEvent *); + static blink::WebMouseEvent toWebMouseEvent(QHoverEvent *); #ifndef QT_NO_TABLETEVENT - static blink::WebMouseEvent toWebMouseEvent(QTabletEvent*, double dpiScale); + static blink::WebMouseEvent toWebMouseEvent(QTabletEvent *); #endif static blink::WebMouseEvent toWebMouseEvent(QEvent *); #ifndef QT_NO_GESTURES - static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *, double dpiScale); + static blink::WebGestureEvent toWebGestureEvent(QNativeGestureEvent *); #endif - static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent*, double dpiScale); - static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent*, double dpiScale); + static blink::WebMouseWheelEvent toWebWheelEvent(QWheelEvent *); + static bool coalesceWebWheelEvent(blink::WebMouseWheelEvent &, QWheelEvent *); static content::NativeWebKeyboardEvent toWebKeyboardEvent(QKeyEvent*); static bool getEditCommand(QKeyEvent *event, std::string *editCommand); }; |