diff options
Diffstat (limited to 'src/core')
31 files changed, 1510 insertions, 243 deletions
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index 37f8885bb..cda01db40 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -35,6 +35,7 @@ HEADERS = \ qtwebenginecoreglobal_p.h \ qwebenginecookiestore.h \ qwebenginecookiestore_p.h \ + qwebenginehttprequest.h \ qwebengineurlrequestinterceptor.h \ qwebengineurlrequestinfo.h \ qwebengineurlrequestinfo_p.h \ @@ -44,6 +45,7 @@ HEADERS = \ SOURCES = \ qtwebenginecoreglobal.cpp \ qwebenginecookiestore.cpp \ + qwebenginehttprequest.cpp \ qwebengineurlrequestinfo.cpp \ qwebengineurlrequestjob.cpp \ qwebengineurlschemehandler.cpp diff --git a/src/core/api/qwebenginehttprequest.cpp b/src/core/api/qwebenginehttprequest.cpp new file mode 100644 index 000000000..b64af4466 --- /dev/null +++ b/src/core/api/qwebenginehttprequest.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** 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 "qplatformdefs.h" +#include <QtCore/qshareddata.h> +#include <QtWebEngineCore/qwebenginehttprequest.h> +#include <algorithm> + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineHttpRequest + \since 5.9 + \ingroup webengine + \inmodule QtWebEngineCore + + \brief The QWebEngineHttpRequest class holds a request to be sent with WebEngine. + + QWebEngineHttpRequest represents an HTTP request in the WebEngine networking stack. + It holds the information necessary to send a request over the network. It contains + a URL and some ancillary information that can be used to modify the request. + Both QWebEnginePage::load() and QWebEngineView::load() accept a QWebEngineHttpRequest + as a parameter. +*/ + +/*! + \enum QWebEngineHttpRequest::Method + \brief This enum type describes the method used to send the HTTP request: + + \value Get The GET method. + \value Post The POST method. +*/ + +class QWebEngineHttpRequestPrivate : public QSharedData +{ +public: + QUrl url; + QWebEngineHttpRequest::Method method; + typedef QPair<QByteArray, QByteArray> HeaderPair; + typedef QVector<HeaderPair> Headers; + Headers headers; + QByteArray postData; + + inline QWebEngineHttpRequestPrivate() + { + } + + ~QWebEngineHttpRequestPrivate() + { + } + + QWebEngineHttpRequestPrivate(const QWebEngineHttpRequestPrivate &other) + : QSharedData(other) + { + method = other.method; + url = other.url; + headers = other.headers; + } + + inline bool operator==(const QWebEngineHttpRequestPrivate &other) const + { + return method == other.method + && url == other.url + && headers == other.headers; + } + + Headers::ConstIterator findHeader(const QByteArray &key) const; + Headers allHeaders() const; + QVector<QByteArray> headersKeys() const; + void setHeader(const QByteArray &key, const QByteArray &value); + void unsetHeader(const QByteArray &key); + void setAllHeaders(const Headers &list); + +private: + void setHeaderInternal(const QByteArray &key, const QByteArray &value); +}; + +/*! + Constructs a QWebEngineHttpRequest object with \a url as the URL to be + requested and \a method as the method to be used. + + \sa url(), setUrl() +*/ +QWebEngineHttpRequest::QWebEngineHttpRequest(const QUrl &url, + const QWebEngineHttpRequest::Method &method) + : d(new QWebEngineHttpRequestPrivate) +{ + d->method = method; + d->url = url; +} + +/*! + Creates a copy of \a other. +*/ +QWebEngineHttpRequest::QWebEngineHttpRequest(const QWebEngineHttpRequest &other) + : d(other.d) +{ +} + +/*! + Disposes of the QWebEngineHttpRequest object. +*/ +QWebEngineHttpRequest::~QWebEngineHttpRequest() +{ + // QSharedDataPointer auto deletes + d = 0; +} + +/*! + Returns \c true if this object is the same as \a other (that is, if they + have the same method, URL, and headers). + + \sa operator!=() +*/ +bool QWebEngineHttpRequest::operator==(const QWebEngineHttpRequest &other) const +{ + return d == other.d || *d == *other.d; +} + +/*! + \fn bool QWebEngineHttpRequest::operator!=(const QWebEngineHttpRequest &other) const + + Returns \c false if this object is not the same as \a other. + + \sa operator==() +*/ + +/*! + Creates a copy of \a other. +*/ +QWebEngineHttpRequest &QWebEngineHttpRequest::operator=(const QWebEngineHttpRequest &other) +{ + d = other.d; + return *this; +} + +/*! + \fn void QWebEngineHttpRequest::swap(QWebEngineHttpRequest &other) + + Swaps this WebEngine request with \a other. This function is very + fast and never fails. +*/ + +/*! + Constructs a QWebEngineHttpRequest to \a url that uses the POST method. + + \note \a postData may contain arbitrary strings. They are translated + to appropriate raw data. + + \sa postData, setPostData() +*/ +QWebEngineHttpRequest QWebEngineHttpRequest::postRequest(const QUrl &url, + const QMap<QString, QString> &postData) +{ + QWebEngineHttpRequest result(url); + result.setMethod(QWebEngineHttpRequest::Post); + + QString buffer; + for (QMap<QString, QString>::const_iterator it = postData.begin(); it != postData.end(); it++) { + QByteArray key = QUrl::toPercentEncoding(it.key()); + QByteArray value = QUrl::toPercentEncoding(it.value()); + + if (buffer.length() > 0) + buffer += QLatin1Char('&'); + buffer += key + QLatin1Char('=') + value; + } + result.setPostData(buffer.toLatin1()); + + result.setHeader(QByteArrayLiteral("Content-Type"), + QByteArrayLiteral("application/x-www-form-urlencoded")); + return result; +} + + +/*! + Returns the method this WebEngine request is using. + + \sa setMethod() +*/ +QWebEngineHttpRequest::Method QWebEngineHttpRequest::method() const +{ + return d->method; +} + +/*! + Sets the method this WebEngine request is using to be \a method. + + \sa method() +*/ +void QWebEngineHttpRequest::setMethod(QWebEngineHttpRequest::Method method) +{ + d->method = method; +} + +/*! + Returns the URL this WebEngine request is referring to. + + \sa setUrl() +*/ +QUrl QWebEngineHttpRequest::url() const +{ + return d->url; +} + +/*! + Sets the URL this WebEngine request is referring to be \a url. + + \sa url() +*/ +void QWebEngineHttpRequest::setUrl(const QUrl &url) +{ + d->url = url; +} + +/*! + Returns the (raw) POST data this WebEngine request contains. + + \sa setPostData() +*/ +QByteArray QWebEngineHttpRequest::postData() const +{ + return d->postData; +} + +/*! + Sets the (raw) POST data this WebEngine request contains to be \a postData. + + \sa postData() +*/ +void QWebEngineHttpRequest::setPostData(const QByteArray &postData) +{ + d->postData = postData; +} + +/*! + Returns \c true if the header \a headerName is present in this + WebEngine request. + + \sa setHeader(), header(), unsetHeader(), headers() +*/ +bool QWebEngineHttpRequest::hasHeader(const QByteArray &headerName) const +{ + return d->findHeader(headerName) != d->headers.constEnd(); +} + +/*! + Returns the header specified by \a headerName. If no such header is + present, an empty QByteArray is returned, which may be + indistinguishable from a header that is present but has no content + (use hasHeader() to find out if the header exists or not). + + Headers can be set with setHeader(). + + \sa setHeader(), hasHeader(), unsetHeader(), headers() +*/ +QByteArray QWebEngineHttpRequest::header(const QByteArray &headerName) const +{ + QWebEngineHttpRequestPrivate::Headers::ConstIterator it = + d->findHeader(headerName); + if (it != d->headers.constEnd()) + return it->second; + return QByteArray(); +} + +/*! + Returns a list of all headers that are set in this WebEngine + request. The list is in the order that the headers were set. + + \sa setHeader(), header(), hasHeader(), unsetHeader() +*/ +QVector<QByteArray> QWebEngineHttpRequest::headers() const +{ + return d->headersKeys(); +} + +/*! + Sets the header \a headerName to be of value \a headerValue. + + \note Setting the same header twice overrides the previous + setting. To accomplish the behavior of multiple HTTP headers of + the same name, you should concatenate the two values, separating + them with a comma (",") and set one single header. + + \sa header(), hasHeader(), unsetHeader(), headers() +*/ +void QWebEngineHttpRequest::setHeader(const QByteArray &headerName, const QByteArray &headerValue) +{ + d->setHeader(headerName, headerValue); +} + +/*! + Removes the header specified by \a key, if present. + + \sa setHeader(), header(), hasHeader(), headers() +*/ +void QWebEngineHttpRequest::unsetHeader(const QByteArray &key) +{ + d->setHeader(key, QByteArray()); +} + +QWebEngineHttpRequestPrivate::Headers::ConstIterator +QWebEngineHttpRequestPrivate::findHeader(const QByteArray &key) const +{ + Headers::ConstIterator it = headers.constBegin(); + Headers::ConstIterator end = headers.constEnd(); + for ( ; it != end; ++it) + if (qstricmp(it->first.constData(), key.constData()) == 0) + return it; + + return end; // not found +} + +QWebEngineHttpRequestPrivate::Headers QWebEngineHttpRequestPrivate::allHeaders() const +{ + return headers; +} + +QVector<QByteArray> QWebEngineHttpRequestPrivate::headersKeys() const +{ + QVector<QByteArray> result; + result.reserve(headers.size()); + Headers::ConstIterator it = headers.constBegin(), + end = headers.constEnd(); + for ( ; it != end; ++it) + result << it->first; + + return result; +} + +/*! + \internal + Sets the header specified by \a key to \a value. +*/ +void QWebEngineHttpRequestPrivate::setHeader(const QByteArray &key, const QByteArray &value) +{ + if (key.isEmpty()) + // refuse to accept an empty header + return; + + setHeaderInternal(key, value); +} + +/*! + \internal + Removes the header specified by \a key, if present. +*/ +void QWebEngineHttpRequestPrivate::unsetHeader(const QByteArray &key) +{ + auto firstEqualsKey = [&key](const HeaderPair &header) { + return qstricmp(header.first.constData(), key.constData()) == 0; + }; + headers.erase(std::remove_if(headers.begin(), headers.end(), firstEqualsKey), + headers.end()); +} + +/*! + \internal + Sets the internal headers list to match \a list. +*/ +void QWebEngineHttpRequestPrivate::setAllHeaders(const Headers &list) +{ + headers = list; +} + +/*! + \internal + Sets the header specified by \a key to \a value. + \note key must not be empty. When unsure, use \a setHeader() instead. +*/ +void QWebEngineHttpRequestPrivate::setHeaderInternal(const QByteArray &key, const QByteArray &value) +{ + unsetHeader(key); + + if (value.isNull()) + return; // only wanted to erase key + + HeaderPair pair; + pair.first = key; + pair.second = value; + headers.append(pair); +} + +QT_END_NAMESPACE diff --git a/src/core/api/qwebenginehttprequest.h b/src/core/api/qwebenginehttprequest.h new file mode 100644 index 000000000..5b5948ba1 --- /dev/null +++ b/src/core/api/qwebenginehttprequest.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBENGINEHTTPREQUEST_H +#define QWEBENGINEHTTPREQUEST_H + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qvector.h> +#include <QtCore/qmap.h> +#include <QtCore/qstring.h> +#include <QtCore/qurl.h> + +QT_BEGIN_NAMESPACE + + +class QWebEngineHttpRequestPrivate; + +class QWEBENGINE_EXPORT QWebEngineHttpRequest +{ +public: + enum Method { + Get, + Post + }; + + explicit QWebEngineHttpRequest(const QUrl &url = QUrl(), + const QWebEngineHttpRequest::Method &method = QWebEngineHttpRequest::Get); + QWebEngineHttpRequest(const QWebEngineHttpRequest &other); + ~QWebEngineHttpRequest(); +#ifdef Q_COMPILER_RVALUE_REFS + QWebEngineHttpRequest &operator=(QWebEngineHttpRequest &&other) Q_DECL_NOTHROW { swap(other); + return *this; } +#endif + QWebEngineHttpRequest &operator=(const QWebEngineHttpRequest &other); + + static QWebEngineHttpRequest postRequest(const QUrl &url, + const QMap<QString, QString> &postData); + void swap(QWebEngineHttpRequest &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + + bool operator==(const QWebEngineHttpRequest &other) const; + inline bool operator!=(const QWebEngineHttpRequest &other) const + { return !operator==(other); } + + Method method() const; + void setMethod(QWebEngineHttpRequest::Method method); + + QUrl url() const; + void setUrl(const QUrl &url); + + QByteArray postData() const; + void setPostData(const QByteArray &postData); + + bool hasHeader(const QByteArray &headerName) const; + QVector<QByteArray> headers() const; + QByteArray header(const QByteArray &headerName) const; + void setHeader(const QByteArray &headerName, const QByteArray &value); + void unsetHeader(const QByteArray &headerName); + +private: + QSharedDataPointer<QWebEngineHttpRequestPrivate> d; + friend class QWebEngineHttpRequestPrivate; +}; + +Q_DECLARE_SHARED(QWebEngineHttpRequest) + +QT_END_NAMESPACE + +#endif diff --git a/src/core/browser_context_adapter_client.cpp b/src/core/browser_context_adapter_client.cpp new file mode 100644 index 000000000..3a7447686 --- /dev/null +++ b/src/core/browser_context_adapter_client.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** 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 "browser_context_adapter_client.h" +#include "content/public/browser/download_item.h" +#include "content/public/browser/save_page_type.h" + +#include <QCoreApplication> +#include <QString> + +namespace QtWebEngineCore { + +ASSERT_ENUMS_MATCH(content::DownloadItem::IN_PROGRESS, BrowserContextAdapterClient::DownloadInProgress) +ASSERT_ENUMS_MATCH(content::DownloadItem::COMPLETE, BrowserContextAdapterClient::DownloadCompleted) +ASSERT_ENUMS_MATCH(content::DownloadItem::CANCELLED, BrowserContextAdapterClient::DownloadCancelled) +ASSERT_ENUMS_MATCH(content::DownloadItem::INTERRUPTED, BrowserContextAdapterClient::DownloadInterrupted) + +ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_UNKNOWN, BrowserContextAdapterClient::UnknownSavePageFormat) +ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_AS_ONLY_HTML, BrowserContextAdapterClient::SingleHtmlSaveFormat) +ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, BrowserContextAdapterClient::CompleteHtmlSaveFormat) +ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_AS_MHTML, BrowserContextAdapterClient::MimeHtmlSaveFormat) + +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_NONE, BrowserContextAdapterClient::NoReason) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, BrowserContextAdapterClient::FileFailed) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED, BrowserContextAdapterClient::FileAccessDenied) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, BrowserContextAdapterClient::FileNoSpace) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG, BrowserContextAdapterClient::FileNameTooLong) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE, BrowserContextAdapterClient::FileTooLarge) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED, BrowserContextAdapterClient::FileVirusInfected) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR, BrowserContextAdapterClient::FileTransientError) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED, BrowserContextAdapterClient::FileBlocked) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED, BrowserContextAdapterClient::FileSecurityCheckFailed) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT, BrowserContextAdapterClient::FileTooShort) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH, BrowserContextAdapterClient::FileHashMismatch) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, BrowserContextAdapterClient::NetworkFailed) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT, BrowserContextAdapterClient::NetworkTimeout) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, BrowserContextAdapterClient::NetworkDisconnected) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN, BrowserContextAdapterClient::NetworkServerDown) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST, BrowserContextAdapterClient::NetworkInvalidRequest) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, BrowserContextAdapterClient::ServerFailed) +//ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE, BrowserContextAdapterClient::ServerNoRange) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT, BrowserContextAdapterClient::ServerBadContent) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED, BrowserContextAdapterClient::ServerUnauthorized) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM, BrowserContextAdapterClient::ServerCertProblem) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN, BrowserContextAdapterClient::ServerForbidden) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE, BrowserContextAdapterClient::ServerUnreachable) +ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, BrowserContextAdapterClient::UserCanceled) +//ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN, BrowserContextAdapterClient::UserShutdown) +//ASSERT_ENUMS_MATCH(content::DOWNLOAD_INTERRUPT_REASON_CRASH, BrowserContextAdapterClient::Crash) + +QString BrowserContextAdapterClient::downloadInterruptReasonToString(DownloadInterruptReason reason) +{ + switch (reason) { + default: + // Yield an error in debug mode, but fall through to some defined behavior + Q_UNREACHABLE(); + case NoReason: + return QCoreApplication::translate("DownloadInterruptReason", + "Unknown reason or not interrupted"); + case FileFailed: + return QCoreApplication::translate("DownloadInterruptReason", + "General file operation failure"); + case FileAccessDenied: + return QCoreApplication::translate("DownloadInterruptReason", + "The file cannot be written locally, due to access restrictions"); + case FileNoSpace: + return QCoreApplication::translate("DownloadInterruptReason", + "Insufficient space on the target drive"); + case FileNameTooLong: + return QCoreApplication::translate("DownloadInterruptReason", + "The directory or file name is too long"); + case FileTooLarge: + return QCoreApplication::translate("DownloadInterruptReason", + "The file size exceeds the file system limitation"); + case FileVirusInfected: + return QCoreApplication::translate("DownloadInterruptReason", + "The file is infected with a virus"); + case FileTransientError: + return QCoreApplication::translate("DownloadInterruptReason", + "Temporary problem (for example file in use, or too many open files)"); + case FileBlocked: + return QCoreApplication::translate("DownloadInterruptReason", + "The file was blocked due to local policy"); + case FileSecurityCheckFailed: + return QCoreApplication::translate("DownloadInterruptReason", + "Checking the safety of the download failed due to unexpected reasons"); + case FileTooShort: + return QCoreApplication::translate("DownloadInterruptReason", + "File seek past the end of a file (resuming previously interrupted download)"); + case FileHashMismatch: + return QCoreApplication::translate("DownloadInterruptReason", + "The partial file did not match the expected hash"); + case NetworkFailed: + return QCoreApplication::translate("DownloadInterruptReason", + "General network failure"); + case NetworkTimeout: + return QCoreApplication::translate("DownloadInterruptReason", + "The network operation has timed out"); + case NetworkDisconnected: + return QCoreApplication::translate("DownloadInterruptReason", + "The network connection has been terminated"); + case NetworkServerDown: + return QCoreApplication::translate("DownloadInterruptReason", + "The server has gone down"); + case NetworkInvalidRequest: + return QCoreApplication::translate("DownloadInterruptReason", + "The network request was invalid (for example, the URL or scheme is invalid)"); + case ServerFailed: + return QCoreApplication::translate("DownloadInterruptReason", + "General server failure"); + //case ServerNoRange: + // return QCoreApplication::translate("DownloadInterruptReason", + // "Server does not support range requests"); + case ServerBadContent: + return QCoreApplication::translate("DownloadInterruptReason", + "The server does not have the requested data"); + case ServerUnauthorized: + return QCoreApplication::translate("DownloadInterruptReason", + "The server did not authorize access to the resource"); + case ServerCertProblem: + return QCoreApplication::translate("DownloadInterruptReason", + "A problem with the server certificate occurred"); + case ServerForbidden: + return QCoreApplication::translate("DownloadInterruptReason", + "Access forbidden by the server"); + case ServerUnreachable: + return QCoreApplication::translate("DownloadInterruptReason", + "Unexpected server response"); + case UserCanceled: + return QCoreApplication::translate("DownloadInterruptReason", + "Download canceled by the user"); + //case UserShutdown: + // return QCoreApplication::translate("DownloadInterruptReason", + // "The user shut down the browser"); + //case Crash: + // return QCoreApplication::translate("DownloadInterruptReason", + // "The browser crashed"); + } +} + +} // namespace QtWebEngineCore diff --git a/src/core/browser_context_adapter_client.h b/src/core/browser_context_adapter_client.h index faba08591..e1fd02f96 100644 --- a/src/core/browser_context_adapter_client.h +++ b/src/core/browser_context_adapter_client.h @@ -76,6 +76,37 @@ public: SavePage }; + // Keep in sync with content::DownloadInterruptReason + enum DownloadInterruptReason { + NoReason = 0, + FileFailed = 1, + FileAccessDenied = 2, + FileNoSpace = 3, + FileNameTooLong = 5, + FileTooLarge = 6, + FileVirusInfected = 7, + FileTransientError = 10, + FileBlocked = 11, + FileSecurityCheckFailed = 12, + FileTooShort = 13, + FileHashMismatch = 14, + NetworkFailed = 20, + NetworkTimeout = 21, + NetworkDisconnected = 22, + NetworkServerDown = 23, + NetworkInvalidRequest = 24, + ServerFailed = 30, + //ServerNoRange = 31, + ServerBadContent = 33, + ServerUnauthorized = 34, + ServerCertProblem = 35, + ServerForbidden = 36, + ServerUnreachable = 37, + UserCanceled = 40, + //UserShutdown = 41, + //Crash = 50 + }; + struct DownloadItemInfo { const quint32 id; const QUrl url; @@ -88,12 +119,14 @@ public: int savePageFormat; bool accepted; int downloadType; + int downloadInterruptReason; }; virtual ~BrowserContextAdapterClient() { } virtual void downloadRequested(DownloadItemInfo &info) = 0; virtual void downloadUpdated(const DownloadItemInfo &info) = 0; + static QString downloadInterruptReasonToString(DownloadInterruptReason reason); }; } // namespace diff --git a/src/core/config/common.pri b/src/core/config/common.pri index b5bb23684..f822ab7cc 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -13,3 +13,21 @@ sanitize_address: GYP_CONFIG += asan=1 sanitize_thread: GYP_CONFIG += tsan=1 sanitize_memory: GYP_CONFIG += msan=1 sanitize_undefined: GYP_CONFIG += ubsan=1 + +use?(printing) { + GYP_CONFIG += enable_basic_printing=1 enable_print_preview=1 +} else { + GYP_CONFIG += enable_basic_printing=0 enable_print_preview=0 +} + +use?(pdf) { + GYP_CONFIG += enable_pdf=1 +} else { + GYP_CONFIG += enable_pdf=0 +} + +use?(pepper_plugins) { + GYP_CONFIG += enable_plugins=1 enable_widevine=1 +} else { + GYP_CONFIG += enable_plugins=0 enable_widevine=0 +} diff --git a/src/core/config/desktop_linux.pri b/src/core/config/desktop_linux.pri index 23044619b..92491fc1c 100644 --- a/src/core/config/desktop_linux.pri +++ b/src/core/config/desktop_linux.pri @@ -3,11 +3,7 @@ GYP_ARGS += "-D qt_os=\"desktop_linux\"" include(linux.pri) GYP_CONFIG += \ - desktop_linux=1 \ - enable_widevine=1 \ - enable_basic_printing=1 \ - enable_print_preview=1 \ - enable_pdf=1 + desktop_linux=1 clang { GYP_CONFIG += werror= diff --git a/src/core/config/embedded_linux.pri b/src/core/config/embedded_linux.pri index 7a909f1e2..08c8c1661 100644 --- a/src/core/config/embedded_linux.pri +++ b/src/core/config/embedded_linux.pri @@ -9,16 +9,12 @@ GYP_CONFIG += \ embedded=1 \ enable_autofill_dialog=0 \ enable_automation=0 \ - enable_basic_printing=0 \ enable_captive_portal_detection=0 \ enable_extensions=0 \ enable_google_now=0 \ enable_language_detection=0 \ enable_managed_users=0 \ - enable_pdf=0 \ enable_plugin_installation=0 \ - enable_plugins=0 \ - enable_print_preview=0 \ enable_session_service=0 \ enable_task_manager=0 \ enable_themes=0 \ @@ -39,6 +35,6 @@ GYP_CONFIG += \ use_x11=0 \ v8_use_snapshot=false \ want_separate_host_toolset=1 \ - angle_enable_gl=0Â \ + angle_enable_gl=0 WEBENGINE_CONFIG *= reduce_binary_size diff --git a/src/core/config/embedded_qnx.pri b/src/core/config/embedded_qnx.pri index 3effdb816..f24888776 100644 --- a/src/core/config/embedded_qnx.pri +++ b/src/core/config/embedded_qnx.pri @@ -4,9 +4,6 @@ include(common.pri) GYP_CONFIG += \ disable_nacl=1 \ - enable_basic_printing=0 \ - enable_pdf=0 \ - enable_plugins=0 \ enable_webrtc=0 \ use_ash=0 \ use_aura=1 \ diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 4111236ed..dfc8d840b 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -24,11 +24,7 @@ GYP_CONFIG += \ mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" \ mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ make_clang_dir=\"$${QMAKE_CLANG_DIR}\" \ - clang_use_chrome_plugins=0 \ - enable_widevine=1 \ - enable_basic_printing=1 \ - enable_print_preview=1 \ - enable_pdf=1 + clang_use_chrome_plugins=0 # Force touch API is used in 49-based Chromium, which is included starting with 10.10.3 SDK, so we # disable the API usage if the SDK version is lower. diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index 7f87e885d..334675481 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -5,11 +5,7 @@ include(common.pri) GYP_CONFIG += \ disable_nacl=1 \ remoting=0 \ - use_ash=0 \ - enable_widevine=1 \ - enable_basic_printing=1 \ - enable_print_preview=1 \ - enable_pdf=1 + use_ash=0 # Libvpx build needs additional search path on Windows. GYP_ARGS += "-D qtwe_chromium_obj_dir=\"$$OUT_PWD/$$getConfigDir()/obj/$${getChromiumSrcDir()}\"" @@ -21,10 +17,18 @@ GYP_ARGS += "-D perl_exe=\"perl.exe\" -D bison_exe=\"bison.exe\" -D gperf_exe=\" GYP_ARGS += "--no-parallel" qtConfig(angle) { + #FIXME: Expect LIBQTANGLE_NAME to be always set + #FIXME: Replace qt_egl_library and qt_glesv2_library into qt_angle_library + LIB_EGL=libEGL + LIB_GLESV2=libGLESv2 + !isEmpty(LIBQTANGLE_NAME) { + LIB_EGL=$$LIBQTANGLE_NAME + LIB_GLESV2=$$LIBQTANGLE_NAME + } CONFIG(release, debug|release) { - GYP_ARGS += "-D qt_egl_library=\"libEGL.lib\" -D qt_glesv2_library=\"libGLESv2.lib\"" + GYP_ARGS += "-D qt_egl_library=\"$${LIB_EGL}.lib\" -D qt_glesv2_library=\"$${LIB_GLESV2}.lib\"" } else { - GYP_ARGS += "-D qt_egl_library=\"libEGLd.lib\" -D qt_glesv2_library=\"libGLESv2d.lib\"" + GYP_ARGS += "-D qt_egl_library=\"$${LIB_EGL}d.lib\" -D qt_glesv2_library=\"$${LIB_GLESV2}d.lib\"" } GYP_ARGS += "-D qt_gl=\"angle\"" } else { diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 095e54caa..80d4e9827 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -48,7 +48,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_paths.h" #include "ui/base/resource/resource_bundle.h" -#include "grit/net_resources.h" +#include "net/grit/net_resources.h" #include "net/base/net_module.h" #include "content_client_qt.h" diff --git a/src/core/core.pro b/src/core/core.pro index a205d39a0..e495685eb 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -3,39 +3,49 @@ TEMPLATE = subdirs # core_headers is a dummy module to syncqt the headers so we can # use them by later targets core_headers.file = core_headers.pro - -# core_gyp_generator.pro is a dummy .pro file that is used by qmake -# to generate our main .gyp file -core_gyp_generator.file = core_gyp_generator.pro -core_gyp_generator.depends = core_headers - -# gyp_run.pro calls gyp through gyp_qtwebengine on the qmake step, and ninja on the make step. -gyp_run.file = gyp_run.pro -gyp_run.depends = core_gyp_generator - core_api.file = api/core_api.pro -core_api.depends = gyp_run # This will take the compile output of ninja, and link+deploy the final binary. core_module.file = core_module.pro core_module.depends = core_api -SUBDIRS += core_headers \ - core_gyp_generator - -!win32 { - # gyp_configure_host.pro and gyp_configure_target.pro are phony pro files that - # extract things like compiler and linker from qmake - # Do not use them on Windows, where Qt already expects the toolchain to be - # selected through environment varibles. - gyp_configure_host.file = gyp_configure_host.pro - gyp_configure_target.file = gyp_configure_target.pro - gyp_configure_target.depends = gyp_configure_host - - gyp_run.depends += gyp_configure_host gyp_configure_target - SUBDIRS += gyp_configure_host gyp_configure_target +# core_generator.pro is a dummy .pro file that is used by qmake +# to generate our main .gyp/BUILD.gn file +core_generator.file = core_generator.pro +core_generator.depends = core_headers + + +use?(gn) { + + gn_run.file = gn_run.pro + gn_run.depends = core_generator + + SUBDIRS += gn_run \ + core_headers \ + core_generator +} else { + + # gyp_run.pro calls gyp through gyp_qtwebengine on the qmake step, and ninja on the make step. + gyp_run.file = gyp_run.pro + gyp_run.depends = core_generator + core_api.depends = gyp_run + + SUBDIRS += gyp_run \ + core_api \ + core_module \ + core_headers \ + core_generator + + !win32 { + # gyp_configure_host.pro and gyp_configure_target.pro are phony pro files that + # extract things like compiler and linker from qmake + # Do not use them on Windows, where Qt already expects the toolchain to be + # selected through environment varibles. + gyp_configure_host.file = gyp_configure_host.pro + gyp_configure_target.file = gyp_configure_target.pro + gyp_configure_target.depends = gyp_configure_host + + gyp_run.depends += gyp_configure_host gyp_configure_target + SUBDIRS += gyp_configure_host gyp_configure_target + } } - -SUBDIRS += gyp_run \ - core_api \ - core_module diff --git a/src/core/core_gyp_generator.pro b/src/core/core_generator.pro index a09683ba6..e1e7ab1d9 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_generator.pro @@ -1,10 +1,9 @@ -# This is a dummy .pro file used to extract some aspects of the used configuration and feed them to gyp -# We want the gyp generation step to happen after all the other config steps. For that we need to prepend -# our gyp_generator.prf feature to the CONFIG variable since it is processed backwards -CONFIG = gyp_generator $$CONFIG -GYPFILE = $$OUT_PWD/core_generated.gyp -GYPINCLUDES += $$PWD/qtwebengine.gypi -GYPSRCDIR = $$PWD + +use?(gn) { + include(core_gn_config.pri) +} else { + include(core_gyp_config.pri) +} TEMPLATE = lib @@ -45,6 +44,7 @@ SOURCES = \ browser_accessibility_manager_qt.cpp \ browser_accessibility_qt.cpp \ browser_context_adapter.cpp \ + browser_context_adapter_client.cpp \ browser_context_qt.cpp \ browser_message_filter_qt.cpp \ certificate_error_controller.cpp \ @@ -75,7 +75,6 @@ SOURCES = \ native_web_keyboard_event_qt.cpp \ network_delegate_qt.cpp \ ozone_platform_eglfs.cpp \ - pdfium_document_wrapper_qt.cpp \ permission_manager_qt.cpp \ process_main.cpp \ proxy_config_service_qt.cpp \ @@ -83,15 +82,10 @@ SOURCES = \ render_view_observer_host_qt.cpp \ render_widget_host_view_qt.cpp \ renderer/content_renderer_client_qt.cpp \ - renderer/pepper/pepper_flash_renderer_host_qt.cpp \ - renderer/pepper/pepper_renderer_host_factory_qt.cpp \ renderer/render_frame_observer_qt.cpp \ renderer/render_view_observer_qt.cpp \ renderer/user_resource_controller.cpp \ renderer/web_channel_ipc_transport.cpp \ - renderer_host/pepper/pepper_flash_browser_host_qt.cpp \ - renderer_host/pepper/pepper_host_factory_qt.cpp \ - renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp \ renderer_host/resource_dispatcher_host_delegate_qt.cpp \ renderer_host/user_resource_controller_host.cpp \ renderer_host/web_channel_ipc_transport_host.cpp \ @@ -156,7 +150,6 @@ HEADERS = \ media_capture_devices_dispatcher.h \ network_delegate_qt.h \ ozone_platform_eglfs.h \ - pdfium_document_wrapper_qt.h \ permission_manager_qt.h \ process_main.h \ proxy_config_service_qt.h \ @@ -165,15 +158,10 @@ HEADERS = \ render_widget_host_view_qt.h \ render_widget_host_view_qt_delegate.h \ renderer/content_renderer_client_qt.h \ - renderer/pepper/pepper_flash_renderer_host_qt.h \ - renderer/pepper/pepper_renderer_host_factory_qt.h \ renderer/render_frame_observer_qt.h \ renderer/render_view_observer_qt.h \ renderer/user_resource_controller.h \ renderer/web_channel_ipc_transport.h \ - renderer_host/pepper/pepper_flash_browser_host_qt.h \ - renderer_host/pepper/pepper_host_factory_qt.h \ - renderer_host/pepper/pepper_isolated_file_system_message_filter.h \ renderer_host/resource_dispatcher_host_delegate_qt.h \ renderer_host/user_resource_controller_host.h \ renderer_host/web_channel_ipc_transport_host.h \ @@ -198,6 +186,42 @@ HEADERS = \ web_engine_visited_links_manager.h \ web_event_factory.h + +use?(pdf) { + SOURCES += pdfium_document_wrapper_qt.cpp + HEADERS += pdfium_document_wrapper_qt.h +} + +use?(pepper_plugins) { + SOURCES += \ + renderer_host/pepper/pepper_flash_browser_host_qt.cpp \ + renderer_host/pepper/pepper_host_factory_qt.cpp \ + renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp \ + renderer/pepper/pepper_flash_renderer_host_qt.cpp \ + renderer/pepper/pepper_renderer_host_factory_qt.cpp + + HEADERS += \ + renderer_host/pepper/pepper_flash_browser_host_qt.h \ + renderer_host/pepper/pepper_host_factory_qt.h \ + renderer_host/pepper/pepper_isolated_file_system_message_filter.h \ + renderer/pepper/pepper_flash_renderer_host_qt.h \ + renderer/pepper/pepper_renderer_host_factory_qt.h +} + +use?(printing) { + SOURCES += \ + printing_message_filter_qt.cpp \ + print_view_manager_base_qt.cpp \ + print_view_manager_qt.cpp \ + renderer/print_web_view_helper_delegate_qt.cpp + + HEADERS += \ + printing_message_filter_qt.h \ + print_view_manager_base_qt.h \ + print_view_manager_qt.h \ + renderer/print_web_view_helper_delegate_qt.h +} + contains(QT_CONFIG, opengl) { SOURCES += \ yuv_video_node.cpp \ diff --git a/src/core/core_gn_config.pri b/src/core/core_gn_config.pri new file mode 100644 index 000000000..ea45977f5 --- /dev/null +++ b/src/core/core_gn_config.pri @@ -0,0 +1,6 @@ +CONFIG = gn_generator $$CONFIG +GN_SRC_DIR = $$PWD +GN_FILE = $$OUT_PWD/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) + diff --git a/src/core/core_gyp_config.pri b/src/core/core_gyp_config.pri new file mode 100644 index 000000000..999d019f9 --- /dev/null +++ b/src/core/core_gyp_config.pri @@ -0,0 +1,5 @@ +CONFIG = gyp_generator $$CONFIG +GYPFILE = $$OUT_PWD/core_generated.gyp +GYPINCLUDES += $$PWD/qtwebengine.gypi +GYPSRCDIR = $$PWD + diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 65e46dcec..596993457 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -109,4 +109,6 @@ OTHER_FILES = \ $$files(../3rdparty/chromium/*.mm, true) \ $$files(../3rdparty/chromium/*.py, true) \ $$files(../3rdparty/chromium/*.gyp, true) \ - $$files(../3rdparty/chromium/*.gypi, true) + $$files(../3rdparty/chromium/*.gypi, true) \ + $$files(../3rdparty/chromium/*.gn, true) \ + $$files(../3rdparty/chromium/*.gni, true) diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index baf064025..4bc83163f 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -171,6 +171,245 @@ private: QSGGeometry m_geometry; }; +class DelegatedNodeTreeHandler +{ +public: + DelegatedNodeTreeHandler(QVector<QSGNode*> *sceneGraphNodes) + : m_sceneGraphNodes(sceneGraphNodes) + { + } + + virtual ~DelegatedNodeTreeHandler(){} + + virtual void setupRenderPassNode(QSGTexture *, const QRect &, QSGNode *) = 0; + virtual void setupTextureContentNode(QSGTexture *, const QRect &, QSGTexture::Filtering, + QSGTextureNode::TextureCoordinatesTransformMode, + QSGNode *) = 0; + virtual void setupTiledContentNode(QSGTexture *, const QRect &, const QRectF &, + QSGTexture::Filtering, QSGNode *) = 0; + virtual void setupSolidColorNode(const QRect &, const QColor &, QSGNode *) = 0; + virtual void setupDebugBorderNode(QSGGeometry *, QSGFlatColorMaterial *, QSGNode *) = 0; + +#ifndef QT_NO_OPENGL + virtual void setupYUVVideoNode(QSGTexture *, QSGTexture *, QSGTexture *, QSGTexture *, + const QRectF &, const QRectF &, const QSizeF &, const QSizeF &, + YUVVideoMaterial::ColorSpace, float, float, const QRectF &, + QSGNode *) = 0; +#ifdef GL_OES_EGL_image_external + virtual void setupStreamVideoNode(MailboxTexture *, const QRectF &, + const QMatrix4x4 &, QSGNode *) = 0; +#endif // GL_OES_EGL_image_external +#endif // QT_NO_OPENGL +protected: + QVector<QSGNode*> *m_sceneGraphNodes; +}; + +class DelegatedNodeTreeUpdater : public DelegatedNodeTreeHandler +{ +public: + DelegatedNodeTreeUpdater(QVector<QSGNode*> *sceneGraphNodes) + : DelegatedNodeTreeHandler(sceneGraphNodes) + , m_nodeIterator(sceneGraphNodes->begin()) + { + } + + void setupRenderPassNode(QSGTexture *layer, const QRect &rect, QSGNode *) Q_DECL_OVERRIDE + { + QSGInternalImageNode *imageNode = static_cast<QSGInternalImageNode*>(*m_nodeIterator++); + imageNode->setTargetRect(rect); + imageNode->setInnerTargetRect(rect); + imageNode->setTexture(layer); + imageNode->update(); + } + + void setupTextureContentNode(QSGTexture *texture, const QRect &rect, + QSGTexture::Filtering filtering, + QSGTextureNode::TextureCoordinatesTransformMode texCoordTransForm, + QSGNode *) Q_DECL_OVERRIDE + { + QSGTextureNode *textureNode = static_cast<QSGTextureNode*>(*m_nodeIterator++); + if (textureNode->texture() != texture) + textureNode->setTexture(texture); + if (textureNode->textureCoordinatesTransform() != texCoordTransForm) + textureNode->setTextureCoordinatesTransform(texCoordTransForm); + if (textureNode->rect() != rect) + textureNode->setRect(rect); + if (textureNode->filtering() != filtering) + textureNode->setFiltering(filtering); + } + void setupTiledContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect, + QSGTexture::Filtering filtering, QSGNode *) Q_DECL_OVERRIDE + { + QSGTextureNode *textureNode = static_cast<QSGTextureNode*>(*m_nodeIterator++); + + if (textureNode->rect() != rect) + textureNode->setRect(rect); + if (textureNode->sourceRect() != sourceRect) + textureNode->setSourceRect(sourceRect); + if (textureNode->filtering() != filtering) + textureNode->setFiltering(filtering); + if (textureNode->texture() != texture) + textureNode->setTexture(texture); + } + void setupSolidColorNode(const QRect &rect, const QColor &color, QSGNode *) Q_DECL_OVERRIDE + { + QSGRectangleNode *rectangleNode = static_cast<QSGRectangleNode*>(*m_nodeIterator++); + + if (rectangleNode->rect() != rect) + rectangleNode->setRect(rect); + if (rectangleNode->color() != color) + rectangleNode->setColor(color); + } + + void setupDebugBorderNode(QSGGeometry *geometry, QSGFlatColorMaterial *material, + QSGNode *) Q_DECL_OVERRIDE + { + QSGGeometryNode *geometryNode = static_cast<QSGGeometryNode*>(*m_nodeIterator++); + + geometryNode->setGeometry(geometry); + geometryNode->setMaterial(material); + } +#ifndef QT_NO_OPENGL + void setupYUVVideoNode(QSGTexture *, QSGTexture *, QSGTexture *, QSGTexture *, + const QRectF &, const QRectF &, const QSizeF &, const QSizeF &, + YUVVideoMaterial::ColorSpace, float, float, const QRectF &, + QSGNode *) Q_DECL_OVERRIDE + { + Q_UNREACHABLE(); + } +#ifdef GL_OES_EGL_image_external + void setupStreamVideoNode(MailboxTexture *, const QRectF &, + const QMatrix4x4 &, QSGNode *) Q_DECL_OVERRIDE + { + Q_UNREACHABLE(); + } +#endif // GL_OES_EGL_image_external +#endif // QT_NO_OPENGL + +private: + QVector<QSGNode*>::iterator m_nodeIterator; +}; + +class DelegatedNodeTreeCreator : public DelegatedNodeTreeHandler +{ +public: + DelegatedNodeTreeCreator(QVector<QSGNode*> *sceneGraphNodes, + RenderWidgetHostViewQtDelegate *apiDelegate) + : DelegatedNodeTreeHandler(sceneGraphNodes) + , m_apiDelegate(apiDelegate) + { + } + + void setupRenderPassNode(QSGTexture *layer, const QRect &rect, + QSGNode *layerChain) Q_DECL_OVERRIDE + { + // Only QSGInternalImageNode currently supports QSGLayer textures. + QSGInternalImageNode *imageNode = m_apiDelegate->createImageNode(); + imageNode->setTargetRect(rect); + imageNode->setInnerTargetRect(rect); + imageNode->setTexture(layer); + imageNode->update(); + + layerChain->appendChildNode(imageNode); + m_sceneGraphNodes->append(imageNode); + } + + void setupTextureContentNode(QSGTexture *texture, const QRect &rect, + QSGTexture::Filtering filtering, + QSGTextureNode::TextureCoordinatesTransformMode texCoordTransForm, + QSGNode *layerChain) Q_DECL_OVERRIDE + { + QSGTextureNode *textureNode = m_apiDelegate->createTextureNode(); + textureNode->setTextureCoordinatesTransform(texCoordTransForm); + textureNode->setRect(rect); + textureNode->setTexture(texture); + textureNode->setFiltering(filtering); + + layerChain->appendChildNode(textureNode); + m_sceneGraphNodes->append(textureNode); + } + + void setupTiledContentNode(QSGTexture *texture, const QRect &rect, const QRectF &sourceRect, + QSGTexture::Filtering filtering, + QSGNode *layerChain) Q_DECL_OVERRIDE + { + QSGTextureNode *textureNode = m_apiDelegate->createTextureNode(); + textureNode->setRect(rect); + textureNode->setSourceRect(sourceRect); + textureNode->setFiltering(filtering); + textureNode->setTexture(texture); + + layerChain->appendChildNode(textureNode); + m_sceneGraphNodes->append(textureNode); + } + + void setupSolidColorNode(const QRect &rect, const QColor &color, + QSGNode *layerChain) Q_DECL_OVERRIDE + { + QSGRectangleNode *rectangleNode = m_apiDelegate->createRectangleNode(); + rectangleNode->setRect(rect); + rectangleNode->setColor(color); + + layerChain->appendChildNode(rectangleNode); + m_sceneGraphNodes->append(rectangleNode); + } + + void setupDebugBorderNode(QSGGeometry *geometry, QSGFlatColorMaterial *material, + QSGNode *layerChain) Q_DECL_OVERRIDE + { + QSGGeometryNode *geometryNode = new QSGGeometryNode; + geometryNode->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); + + geometryNode->setGeometry(geometry); + geometryNode->setMaterial(material); + + layerChain->appendChildNode(geometryNode); + m_sceneGraphNodes->append(geometryNode); + } + +#ifndef QT_NO_OPENGL + void setupYUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, + QSGTexture *aTexture, const QRectF &yaTexCoordRect, + const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, + const QSizeF &uvTexSize, YUVVideoMaterial::ColorSpace colorspace, + float rMul, float rOff, const QRectF &rect, + QSGNode *layerChain) Q_DECL_OVERRIDE + { + YUVVideoNode *videoNode = new YUVVideoNode( + yTexture, + uTexture, + vTexture, + aTexture, + yaTexCoordRect, + uvTexCoordRect, + yaTexSize, + uvTexSize, + colorspace, + rMul, + rOff); + videoNode->setRect(rect); + + layerChain->appendChildNode(videoNode); + m_sceneGraphNodes->append(videoNode); + } +#ifdef GL_OES_EGL_image_external + void setupStreamVideoNode(MailboxTexture *texture, const QRectF &rect, + const QMatrix4x4 &textureMatrix, QSGNode *layerChain) Q_DECL_OVERRIDE + { + StreamVideoNode *svideoNode = new StreamVideoNode(texture, false, ExternalTarget); + svideoNode->setRect(rect); + svideoNode->setTextureMatrix(textureMatrix); + layerChain->appendChildNode(svideoNode); + m_sceneGraphNodes->append(svideoNode); + } +#endif // GL_OES_EGL_image_external +#endif // QT_NO_OPENGL + +private: + RenderWidgetHostViewQtDelegate *m_apiDelegate; +}; + + static inline QSharedPointer<QSGLayer> findRenderPassLayer(const cc::RenderPassId &id, const QVector<QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > > &list) { typedef QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > Pair; @@ -513,7 +752,67 @@ static YUVVideoMaterial::ColorSpace toQt(cc::YUVVideoDrawQuad::ColorSpace color_ return YUVVideoMaterial::REC_601; } -void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate) +static bool areSharedQuadStatesEqual(const cc::SharedQuadState *layerState, + const cc::SharedQuadState *prevLayerState) +{ + if (layerState->is_clipped != prevLayerState->is_clipped + || layerState->clip_rect != prevLayerState->clip_rect) + return false; + if (layerState->quad_to_target_transform != prevLayerState->quad_to_target_transform) + return false; + return qFuzzyCompare(layerState->opacity, prevLayerState->opacity); +} + +// 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(cc::DelegatedFrameData *frameData, + cc::DelegatedFrameData *previousFrameData) +{ + if (!previousFrameData) + return false; + + if (previousFrameData->render_pass_list.size() != frameData->render_pass_list.size()) + return false; + + for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { + cc::RenderPass *newPass = frameData->render_pass_list.at(i).get(); + cc::RenderPass *prevPass = previousFrameData->render_pass_list.at(i).get(); + + if (newPass->id != prevPass->id) + return false; + + if (newPass->quad_list.size() != prevPass->quad_list.size()) + return false; + + cc::QuadList::ConstBackToFrontIterator it = newPass->quad_list.BackToFrontBegin(); + cc::QuadList::ConstBackToFrontIterator end = newPass->quad_list.BackToFrontEnd(); + cc::QuadList::ConstBackToFrontIterator prevIt = prevPass->quad_list.BackToFrontBegin(); + cc::QuadList::ConstBackToFrontIterator prevEnd = prevPass->quad_list.BackToFrontEnd(); + for (; it != end && prevIt != prevEnd; ++it, ++prevIt) { + const cc::DrawQuad *quad = *it; + const cc::DrawQuad *prevQuad = *prevIt; + if (!areSharedQuadStatesEqual(quad->shared_quad_state, prevQuad->shared_quad_state)) + return false; + if (quad->material != prevQuad->material) + return false; +#ifndef QT_NO_OPENGL + if (quad->material == cc::DrawQuad::YUV_VIDEO_CONTENT) + return false; +#ifdef GL_OES_EGL_image_external + if (quad->material == cc::DrawQuad::STREAM_VIDEO_CONTENT) + return false; +#endif // GL_OES_EGL_image_external +#endif // QT_NO_OPENGL + + } + } + return true; +} + +void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, + cc::ReturnedResourceArray *resourcesToRelease, + RenderWidgetHostViewQtDelegate *apiDelegate) { m_chromiumCompositorData = chromiumCompositorData; cc::DelegatedFrameData* frameData = m_chromiumCompositorData->frameData.get(); @@ -524,13 +823,11 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, 1 / m_chromiumCompositorData->frameDevicePixelRatio); - setMatrix(matrix); + matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, + 1 / m_chromiumCompositorData->frameDevicePixelRatio); + if (QSGTransformNode::matrix() != matrix) + setMatrix(matrix); - // 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. - SGObjects previousSGObjects; - qSwap(m_sgObjects, previousSGObjects); QHash<unsigned, QSharedPointer<ResourceHolder> > resourceCandidates; qSwap(m_chromiumCompositorData->resourceHolders, resourceCandidates); @@ -547,14 +844,32 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, } frameData->resource_list.clear(); + QScopedPointer<DelegatedNodeTreeHandler> nodeHandler; - // There is currently no way to know which and how quads changed since the last frame. - // We have to reconstruct the node chain with their geometries on every update. - // Intermediate render pass node chains are going to be destroyed when previousSGObjects - // goes out of scope together with any QSGLayer that could reference them. - while (QSGNode *oldChain = firstChild()) - delete oldChain; + // We first compare if the render passes from the previous frame data are structurally + // equivalent to the render passes in the current frame data. If they are, we are going + // to reuse the old nodes. Otherwise, we will delete the old nodes and build a new tree. + cc::DelegatedFrameData *previousFrameData = m_chromiumCompositorData->previousFrameData.get(); + const bool buildNewTree = !areRenderPassStructuresEqual(frameData, previousFrameData); + m_chromiumCompositorData->previousFrameData = nullptr; + 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); + // 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); + nodeHandler.reset(new DelegatedNodeTreeUpdater(&m_sceneGraphNodes)); + } // The RenderPasses list is actually a tree where a parent RenderPass is connected // to its dependencies through a RenderPassId reference in one or more RenderPassQuads. // The list is already ordered with intermediate RenderPasses placed before their @@ -568,149 +883,168 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, QSGNode *renderPassParent = 0; if (pass != rootRenderPass) { - QSharedPointer<QSGLayer> rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers); - if (!rpLayer) { - rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); - // Avoid any premature texture update since we need to wait - // for the GPU thread to produce the dependent resources first. - rpLayer->setLive(false); - } - QSharedPointer<QSGRootNode> rootNode(new QSGRootNode); + QSharedPointer<QSGLayer> rpLayer; + if (buildNewTree) { + rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers); + if (!rpLayer) { + rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); + // Avoid any premature texture update since we need to wait + // for the GPU thread to produce the dependent resources first. + rpLayer->setLive(false); + } + QSharedPointer<QSGRootNode> rootNode(new QSGRootNode); + rpLayer->setItem(rootNode.data()); + m_sgObjects.renderPassLayers.append(QPair<cc::RenderPassId, + QSharedPointer<QSGLayer> >(pass->id, rpLayer)); + m_sgObjects.renderPassRootNodes.append(rootNode); + renderPassParent = rootNode.data(); + } else + rpLayer = findRenderPassLayer(pass->id, m_sgObjects.renderPassLayers); + rpLayer->setRect(toQt(pass->output_rect)); rpLayer->setSize(toQt(pass->output_rect.size())); rpLayer->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); - rpLayer->setItem(rootNode.data()); - m_sgObjects.renderPassLayers.append(QPair<cc::RenderPassId, QSharedPointer<QSGLayer> >(pass->id, rpLayer)); - m_sgObjects.renderPassRootNodes.append(rootNode); - renderPassParent = rootNode.data(); } else renderPassParent = this; - QSGNode *renderPassChain = buildRenderPassChain(renderPassParent); - const cc::SharedQuadState *currentLayerState = 0; - QSGNode *currentLayerChain = 0; + const cc::SharedQuadState *currentLayerState = nullptr; + QSGNode *currentLayerChain = nullptr; + + QSGNode *renderPassChain = nullptr; + if (buildNewTree) + renderPassChain = buildRenderPassChain(renderPassParent); cc::QuadList::ConstBackToFrontIterator it = pass->quad_list.BackToFrontBegin(); cc::QuadList::ConstBackToFrontIterator end = pass->quad_list.BackToFrontEnd(); for (; it != end; ++it) { const cc::DrawQuad *quad = *it; - if (currentLayerState != quad->shared_quad_state) { + if (buildNewTree && currentLayerState != quad->shared_quad_state) { currentLayerState = quad->shared_quad_state; currentLayerChain = buildLayerChain(renderPassChain, currentLayerState); } switch (quad->material) { case cc::DrawQuad::RENDER_PASS: { - const cc::RenderPassDrawQuad *renderPassQuad = cc::RenderPassDrawQuad::MaterialCast(quad); - QSGTexture *layer = findRenderPassLayer(renderPassQuad->render_pass_id, m_sgObjects.renderPassLayers).data(); + const cc::RenderPassDrawQuad *renderPassQuad + = cc::RenderPassDrawQuad::MaterialCast(quad); + QSGTexture *layer = findRenderPassLayer(renderPassQuad->render_pass_id, + m_sgObjects.renderPassLayers).data(); + // cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes. if (!layer) continue; - - // Only QSGInternalImageNode currently supports QSGLayer textures. - QSGInternalImageNode *imageNode = apiDelegate->createImageNode(); - imageNode->setTargetRect(toQt(quad->rect)); - imageNode->setInnerTargetRect(toQt(quad->rect)); - imageNode->setTexture(layer); - imageNode->update(); - currentLayerChain->appendChildNode(imageNode); + nodeHandler->setupRenderPassNode(layer, toQt(quad->rect), currentLayerChain); break; } case cc::DrawQuad::TEXTURE_CONTENT: { const cc::TextureDrawQuad *tquad = cc::TextureDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), resourceCandidates); - - QSGTextureNode *textureNode = apiDelegate->createTextureNode(); - textureNode->setTextureCoordinatesTransform(tquad->y_flipped ? QSGTextureNode::MirrorVertically : QSGTextureNode::NoTransform); - textureNode->setRect(toQt(quad->rect)); - textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); - textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); - currentLayerChain->appendChildNode(textureNode); + ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), + resourceCandidates); + + nodeHandler->setupTextureContentNode( + initAndHoldTexture(resource, + quad->ShouldDrawWithBlending(), + apiDelegate), + toQt(quad->rect), + resource->transferableResource().filter == GL_LINEAR + ? QSGTexture::Linear + : QSGTexture::Nearest, + tquad->y_flipped ? QSGTextureNode::MirrorVertically + : QSGTextureNode::NoTransform, + currentLayerChain); break; } case cc::DrawQuad::SOLID_COLOR: { const cc::SolidColorDrawQuad *scquad = cc::SolidColorDrawQuad::MaterialCast(quad); - QSGRectangleNode *rectangleNode = apiDelegate->createRectangleNode(); - // Qt only supports MSAA and this flag shouldn't be needed. // If we ever want to use QSGRectangleNode::setAntialiasing for this we should // try to see if we can do something similar for tile quads first. Q_UNUSED(scquad->force_anti_aliasing_off); - - rectangleNode->setRect(toQt(quad->rect)); - rectangleNode->setColor(toQt(scquad->color)); - currentLayerChain->appendChildNode(rectangleNode); + nodeHandler->setupSolidColorNode(toQt(quad->rect), toQt(scquad->color), + currentLayerChain); break; #ifndef QT_NO_OPENGL } case cc::DrawQuad::DEBUG_BORDER: { - const cc::DebugBorderDrawQuad *dbquad = cc::DebugBorderDrawQuad::MaterialCast(quad); - QSGGeometryNode *geometryNode = new QSGGeometryNode; + const cc::DebugBorderDrawQuad *dbquad + = cc::DebugBorderDrawQuad::MaterialCast(quad); - QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); + QSGGeometry *geometry + = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); geometry->setDrawingMode(GL_LINE_LOOP); geometry->setLineWidth(dbquad->width); - // QSGGeometry::updateRectGeometry would actually set the corners in the following order: - // top-left, bottom-left, top-right, bottom-right, leading to a nice criss cross, instead - // of having a closed loop. + // QSGGeometry::updateRectGeometry would actually set the + // corners in the following order: + // top-left, bottom-left, top-right, bottom-right, leading to a nice criss cross, + // instead of having a closed loop. const gfx::Rect &r(dbquad->rect); geometry->vertexDataAsPoint2D()[0].set(r.x(), r.y()); geometry->vertexDataAsPoint2D()[1].set(r.x() + r.width(), r.y()); geometry->vertexDataAsPoint2D()[2].set(r.x() + r.width(), r.y() + r.height()); geometry->vertexDataAsPoint2D()[3].set(r.x(), r.y() + r.height()); - geometryNode->setGeometry(geometry); QSGFlatColorMaterial *material = new QSGFlatColorMaterial; material->setColor(toQt(dbquad->color)); - geometryNode->setMaterial(material); - geometryNode->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); - currentLayerChain->appendChildNode(geometryNode); + nodeHandler->setupDebugBorderNode(geometry, material, currentLayerChain); break; #endif } case cc::DrawQuad::TILED_CONTENT: { const cc::TileDrawQuad *tquad = cc::TileDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(tquad->resource_id(), resourceCandidates); - - QSGTextureNode *textureNode = apiDelegate->createTextureNode(); - textureNode->setRect(toQt(quad->rect)); - textureNode->setSourceRect(toQt(tquad->tex_coord_rect)); - textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); - textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); - currentLayerChain->appendChildNode(textureNode); + ResourceHolder *resource + = findAndHoldResource(tquad->resource_id(), resourceCandidates); + nodeHandler->setupTiledContentNode( + initAndHoldTexture(resource, + quad->ShouldDrawWithBlending(), + apiDelegate), + toQt(quad->rect), toQt(tquad->tex_coord_rect), + resource->transferableResource().filter + == GL_LINEAR ? QSGTexture::Linear + : QSGTexture::Nearest, + currentLayerChain); break; #ifndef QT_NO_OPENGL } case cc::DrawQuad::YUV_VIDEO_CONTENT: { const cc::YUVVideoDrawQuad *vquad = cc::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 *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; - // This currently requires --enable-vp8-alpha-playback and needs a video with alpha data to be triggered. + // 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); - - YUVVideoNode *videoNode = new YUVVideoNode( - initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), - initAndHoldTexture(uResource, quad->ShouldDrawWithBlending()), - initAndHoldTexture(vResource, quad->ShouldDrawWithBlending()), - aResource ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) : 0, - toQt(vquad->ya_tex_coord_rect), toQt(vquad->uv_tex_coord_rect), - toQt(vquad->ya_tex_size), toQt(vquad->uv_tex_size), - toQt(vquad->color_space), - vquad->resource_multiplier, vquad->resource_offset); - videoNode->setRect(toQt(quad->rect)); - currentLayerChain->appendChildNode(videoNode); + aResource = findAndHoldResource(vquad->a_plane_resource_id(), + resourceCandidates); + + nodeHandler->setupYUVVideoNode( + initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), + initAndHoldTexture(uResource, quad->ShouldDrawWithBlending()), + initAndHoldTexture(vResource, quad->ShouldDrawWithBlending()), + aResource + ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) + : 0, + toQt(vquad->ya_tex_coord_rect), toQt(vquad->uv_tex_coord_rect), + toQt(vquad->ya_tex_size), toQt(vquad->uv_tex_size), + toQt(vquad->color_space), + vquad->resource_multiplier, vquad->resource_offset, + toQt(quad->rect), + currentLayerChain); break; #ifdef GL_OES_EGL_image_external } case cc::DrawQuad::STREAM_VIDEO_CONTENT: { const cc::StreamVideoDrawQuad *squad = cc::StreamVideoDrawQuad::MaterialCast(quad); - ResourceHolder *resource = findAndHoldResource(squad->resource_id(), resourceCandidates); - MailboxTexture *texture = static_cast<MailboxTexture *>(initAndHoldTexture(resource, quad->ShouldDrawWithBlending())); - texture->setTarget(GL_TEXTURE_EXTERNAL_OES); // since this is not default TEXTURE_2D type - - StreamVideoNode *svideoNode = new StreamVideoNode(texture, false, ExternalTarget); - svideoNode->setRect(toQt(squad->rect)); - svideoNode->setTextureMatrix(toQt(squad->matrix.matrix())); - currentLayerChain->appendChildNode(svideoNode); + ResourceHolder *resource = findAndHoldResource(squad->resource_id(), + resourceCandidates); + MailboxTexture *texture + = static_cast<MailboxTexture *>( + initAndHoldTexture(resource, quad->ShouldDrawWithBlending()) + ); + // since this is not default TEXTURE_2D type + texture->setTarget(GL_TEXTURE_EXTERNAL_OES); + + nodeHandler->setupStreamVideoNode(texture, toQt(squad->rect), + toQt(squad->matrix.matrix()), currentLayerChain); break; #endif // GL_OES_EGL_image_external #endif // QT_NO_OPENGL @@ -721,9 +1055,11 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, } } } + // 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; - // 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()); diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index 36ec20f1d..6178bd232 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -74,6 +74,7 @@ public: ChromiumCompositorData() : frameDevicePixelRatio(1) { } QHash<unsigned, QSharedPointer<ResourceHolder> > resourceHolders; std::unique_ptr<cc::DelegatedFrameData> frameData; + std::unique_ptr<cc::DelegatedFrameData> previousFrameData; qreal frameDevicePixelRatio; }; @@ -100,6 +101,7 @@ private: QVector<QSharedPointer<QSGRootNode> > renderPassRootNodes; QVector<QSharedPointer<QSGTexture> > textureStrongRefs; } m_sgObjects; + QVector<QSGNode*> m_sceneGraphNodes; int m_numPendingSyncPoints; QWaitCondition m_mailboxesFetchedWaitCond; QMutex m_mutex; diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index a1445d609..77469a8ea 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -61,16 +61,6 @@ namespace QtWebEngineCore { -ASSERT_ENUMS_MATCH(content::DownloadItem::IN_PROGRESS, BrowserContextAdapterClient::DownloadInProgress) -ASSERT_ENUMS_MATCH(content::DownloadItem::COMPLETE, BrowserContextAdapterClient::DownloadCompleted) -ASSERT_ENUMS_MATCH(content::DownloadItem::CANCELLED, BrowserContextAdapterClient::DownloadCancelled) -ASSERT_ENUMS_MATCH(content::DownloadItem::INTERRUPTED, BrowserContextAdapterClient::DownloadInterrupted) - -ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_UNKNOWN, BrowserContextAdapterClient::UnknownSavePageFormat) -ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_AS_ONLY_HTML, BrowserContextAdapterClient::SingleHtmlSaveFormat) -ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, BrowserContextAdapterClient::CompleteHtmlSaveFormat) -ASSERT_ENUMS_MATCH(content::SAVE_PAGE_TYPE_AS_MHTML, BrowserContextAdapterClient::MimeHtmlSaveFormat) - DownloadManagerDelegateQt::DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter) : m_contextAdapter(contextAdapter) , m_currentId(0) @@ -165,7 +155,8 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* i suggestedFilePath, BrowserContextAdapterClient::UnknownSavePageFormat, false /* accepted */, - m_downloadType + m_downloadType, + item->GetLastReason() }; Q_FOREACH (BrowserContextAdapterClient *client, clients) { @@ -254,7 +245,8 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content suggestedFilePath, suggestedSaveFormat, acceptedByDefault, - BrowserContextAdapterClient::SavePage + BrowserContextAdapterClient::SavePage, + BrowserContextAdapterClient::NoReason }; Q_FOREACH (BrowserContextAdapterClient *client, clients) { @@ -291,7 +283,8 @@ void DownloadManagerDelegateQt::OnDownloadUpdated(content::DownloadItem *downloa QString(), BrowserContextAdapterClient::UnknownSavePageFormat, true /* accepted */, - m_downloadType + m_downloadType, + download->GetLastReason() }; Q_FOREACH (BrowserContextAdapterClient *client, clients) { diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro new file mode 100644 index 000000000..c379f9510 --- /dev/null +++ b/src/core/gn_run.pro @@ -0,0 +1,39 @@ +isQtMinimum(5, 8) { + include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) + QT_FOR_CONFIG += webengine-private +} + +TEMPLATE = aux + +build_pass|!debug_and_release { + + ninja_binary = ninja + runninja.target = run_ninja + + !qtConfig(system-ninja) { + ninja_binary = $$shell_quote($$shell_path($$ninjaPath())) + buildninja.target = build_ninja + buildninja.commands = $$buildNinja() + QMAKE_EXTRA_TARGETS += buildninja + runninja.depends = buildninja + } + + !qtConfig(system-gn) { + buildgn.target = build_gn + buildgn.commands = $$buildGn() + !qtConfig(system-ninja): buildgn.depends = buildninja + QMAKE_EXTRA_TARGETS += buildgn + runninja.depends = buildgn + } + + runninja.commands = $$ninja_binary \$\(NINJAFLAGS\) -C $$shell_quote($$OUT_PWD/$$getConfigDir()) + QMAKE_EXTRA_TARGETS += runninja + + default_target.depends = buildgn + + QMAKE_EXTRA_TARGETS += default_target +} else { + # Special GNU make target for the meta Makefile that ensures that our debug and release Makefiles won't both run ninja in parallel. + notParallel.target = .NOTPARALLEL + QMAKE_EXTRA_TARGETS += notParallel +} diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro index dc22d14bf..c583845e9 100644 --- a/src/core/gyp_run.pro +++ b/src/core/gyp_run.pro @@ -2,6 +2,11 @@ # 1) invoking gyp through the gyp_qtwebengine script, which in turn makes use of the generated gypi include files # 2) produce a Makefile that will run ninja, and take care of actually building everything. +isQtMinimum(5, 8) { + include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) + QT_FOR_CONFIG += webengine-private +} + TEMPLATE = aux cross_compile { @@ -148,13 +153,24 @@ for (config, GYP_CONFIG): GYP_ARGS += "-D $$config" } build_pass|!debug_and_release { - ninja.target = invoke_ninja - ninja.commands = $$findOrBuildNinja() \$\(NINJAFLAGS\) -C "$$OUT_PWD/$$getConfigDir()" - QMAKE_EXTRA_TARGETS += ninja + + ninja_binary = ninja + runninja.target = run_ninja + + !qtConfig(system-ninja) { + ninja_binary = $$shell_quote($$shell_path($$ninjaPath())) + buildninja.target = build_ninja + buildninja.commands = $$buildNinja() + QMAKE_EXTRA_TARGETS += buildninja + runninja.depends = buildninja + } + + runninja.commands = $$ninja_binary \$\(NINJAFLAGS\) -C $$shell_quote($$OUT_PWD/$$getConfigDir()) + QMAKE_EXTRA_TARGETS += runninja build_pass:build_all: default_target.target = all else: default_target.target = first - default_target.depends = ninja + default_target.depends = runninja QMAKE_EXTRA_TARGETS += default_target } else { diff --git a/src/core/print_view_manager_qt.cpp b/src/core/print_view_manager_qt.cpp index 0231df8bd..6006c3bad 100644 --- a/src/core/print_view_manager_qt.cpp +++ b/src/core/print_view_manager_qt.cpp @@ -63,7 +63,8 @@ namespace { static const qreal kMicronsToMillimeter = 1000.0f; static std::vector<char> -GetStdVectorFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) { +GetStdVectorFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) +{ std::unique_ptr<base::SharedMemory> shared_buf( new base::SharedMemory(handle, true)); @@ -76,7 +77,8 @@ GetStdVectorFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) { } static scoped_refptr<base::RefCountedBytes> -GetBytesFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) { +GetBytesFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) +{ std::unique_ptr<base::SharedMemory> shared_buf( new base::SharedMemory(handle, true)); @@ -91,7 +93,10 @@ GetBytesFromHandle(base::SharedMemoryHandle handle, uint32_t data_size) { // Write the PDF file to disk. static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data, - const base::FilePath& path) { + const base::FilePath& path, + const QtWebEngineCore::PrintViewManagerQt::PrintToPDFFileCallback + &saveCallback) +{ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); DCHECK_GT(data->size(), 0U); @@ -100,8 +105,10 @@ static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data, base::File file(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - if (file.IsValid()) - metafile.SaveTo(&file); + bool success = file.IsValid() && metafile.SaveTo(&file); + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(saveCallback, success)); } static base::DictionaryValue *createPrintSettings() @@ -172,30 +179,43 @@ PrintViewManagerQt::~PrintViewManagerQt() } #if defined(ENABLE_BASIC_PRINTING) -bool PrintViewManagerQt::PrintToPDF(const QPageLayout &pageLayout, bool printInColor, const QString &filePath) +void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayout, + bool printInColor, const QString &filePath, + const PrintToPDFFileCallback& callback) { - if (m_printSettings || !filePath.length()) - return false; + if (callback.is_null()) + return; + + if (m_printSettings || !filePath.length()) { + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(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)); resetPdfState(); - return false; } - return true; } -bool PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, bool printInColor, const PrintToPDFCallback& callback) +void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, + bool printInColor, + const PrintToPDFCallback& callback) { if (callback.is_null()) - return false; + return; // 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>())); - return false; + return; } m_pdfPrintCallback = callback; @@ -205,9 +225,7 @@ bool PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, b base::Bind(callback, std::vector<char>())); resetPdfState(); - return false; } - return true; } bool PrintViewManagerQt::PrintToPDFInternal(const QPageLayout &pageLayout, bool printInColor) @@ -218,7 +236,8 @@ bool PrintViewManagerQt::PrintToPDFInternal(const QPageLayout &pageLayout, bool m_printSettings.reset(createPrintSettingsFromQPageLayout(pageLayout)); m_printSettings->SetBoolean(printing::kSettingShouldPrintBackgrounds , web_contents()->GetRenderViewHost()->GetWebkitPreferences().should_print_backgrounds); - m_printSettings->SetInteger(printing::kSettingColor, printInColor ? printing::COLOR : printing::GRAYSCALE); + m_printSettings->SetInteger(printing::kSettingColor, + printInColor ? printing::COLOR : printing::GRAYSCALE); return Send(new PrintMsg_InitiatePrintPreview(routing_id(), false)); } @@ -255,6 +274,7 @@ void PrintViewManagerQt::resetPdfState() { m_pdfOutputPath.clear(); m_pdfPrintCallback.Reset(); + m_pdfSaveCallback.Reset(); m_printSettings.reset(); } @@ -273,20 +293,23 @@ void PrintViewManagerQt::OnMetafileReadyForPrinting( // 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; base::FilePath pdfOutputPath = m_pdfOutputPath; resetPdfState(); if (!pdf_print_callback.is_null()) { - std::vector<char> data_vector = GetStdVectorFromHandle(params.metafile_data_handle, params.data_size); + std::vector<char> data_vector = GetStdVectorFromHandle(params.metafile_data_handle, + params.data_size); content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(pdf_print_callback, data_vector)); } else { - scoped_refptr<base::RefCountedBytes> data_bytes = GetBytesFromHandle(params.metafile_data_handle, params.data_size); + scoped_refptr<base::RefCountedBytes> data_bytes + = GetBytesFromHandle(params.metafile_data_handle, params.data_size); content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, - base::Bind(&SavePdfFile, data_bytes, pdfOutputPath)); + base::Bind(&SavePdfFile, data_bytes, pdfOutputPath, pdf_save_callback)); } } diff --git a/src/core/print_view_manager_qt.h b/src/core/print_view_manager_qt.h index 668516096..b2ba73b27 100644 --- a/src/core/print_view_manager_qt.h +++ b/src/core/print_view_manager_qt.h @@ -81,10 +81,16 @@ class PrintViewManagerQt public: ~PrintViewManagerQt() override; typedef base::Callback<void(const std::vector<char> &result)> PrintToPDFCallback; + typedef base::Callback<void(bool success)> PrintToPDFFileCallback; #if defined(ENABLE_BASIC_PRINTING) // Method to print a page to a Pdf document with page size \a pageSize in location \a filePath. - bool PrintToPDF(const QPageLayout &pageLayout, bool printInColor, const QString &filePath); - bool PrintToPDFWithCallback(const QPageLayout &pageLayout, bool printInColor, const PrintToPDFCallback &callback); + void PrintToPDFFileWithCallback(const QPageLayout &pageLayout, + bool printInColor, + const QString &filePath, + const PrintToPDFFileCallback& callback); + void PrintToPDFWithCallback(const QPageLayout &pageLayout, + bool printInColor, + const PrintToPDFCallback &callback); #endif // ENABLE_BASIC_PRINTING // PrintedPagesSource implementation. @@ -114,6 +120,7 @@ protected: base::FilePath m_pdfOutputPath; PrintToPDFCallback m_pdfPrintCallback; + PrintToPDFFileCallback m_pdfSaveCallback; private: friend class content::WebContentsUserData<PrintViewManagerQt>; diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index d0ab01534..5131ce8cc 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -126,16 +126,6 @@ '<(chromium_src_dir)/components/components.gyp:printing_browser', '<(chromium_src_dir)/components/components.gyp:printing_common', '<(chromium_src_dir)/components/components.gyp:printing_renderer', - ], - 'sources': [ - 'printing_message_filter_qt.cpp', - 'print_view_manager_base_qt.cpp', - 'print_view_manager_qt.cpp', - 'printing_message_filter_qt.h', - 'print_view_manager_base_qt.h', - 'print_view_manager_qt.h', - 'renderer/print_web_view_helper_delegate_qt.cpp', - 'renderer/print_web_view_helper_delegate_qt.h', ] }], ['icu_use_data_file_flag==1', { diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 70ffe0dcb..fef3831e3 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -666,6 +666,8 @@ void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32_t output_surface_id, c m_pendingOutputSurfaceId = output_surface_id; Q_ASSERT(frame.delegated_frame_data); Q_ASSERT(!m_chromiumCompositorData->frameData || m_chromiumCompositorData->frameData->resource_list.empty()); + if (m_chromiumCompositorData->frameData.get()) + m_chromiumCompositorData->previousFrameData = std::move(m_chromiumCompositorData->frameData); m_chromiumCompositorData->frameData = std::move(frame.delegated_frame_data); m_chromiumCompositorData->frameDevicePixelRatio = frame.metadata.device_scale_factor; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 91e457726..9de2085ba 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -77,6 +77,7 @@ #include "content/public/common/page_state.h" #include "content/public/common/page_zoom.h" #include "content/public/common/renderer_preferences.h" +#include "content/public/common/resource_request_body.h" #include "content/public/common/url_constants.h" #include "content/public/common/web_preferences.h" #include "third_party/WebKit/public/web/WebFindOptions.h" @@ -183,12 +184,23 @@ static void callbackOnEvaluateJS(WebContentsAdapterClient *adapterClient, quint6 adapterClient->didRunJavaScript(requestId, fromJSValue(result)); } -static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, int requestId, const std::vector<char>& result) +#if defined(ENABLE_BASIC_PRINTING) +static void callbackOnPrintingFinished(WebContentsAdapterClient *adapterClient, + int requestId, + const std::vector<char>& result) { if (requestId) adapterClient->didPrintPage(requestId, QByteArray(result.data(), result.size())); } +static void callbackOnPdfSavingFinished(WebContentsAdapterClient *adapterClient, + const QString& filePath, + bool success) +{ + adapterClient->didPrintPageToPdf(filePath, success); +} +#endif + static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient, content::BrowserContext *browserContext) { content::WebContents::CreateParams create_params(browserContext, NULL); @@ -488,6 +500,12 @@ void WebContentsAdapter::reloadAndBypassCache() void WebContentsAdapter::load(const QUrl &url) { + QWebEngineHttpRequest request(url); + load(request); +} + +void WebContentsAdapter::load(const QWebEngineHttpRequest &request) +{ // The situation can occur when relying on the editingFinished signal in QML to set the url // of the WebView. // When enter is pressed, onEditingFinished fires and the url of the webview is set, which @@ -502,21 +520,55 @@ void WebContentsAdapter::load(const QUrl &url) Q_UNUSED(guard); Q_D(WebContentsAdapter); - GURL gurl = toGurl(url); + GURL gurl = toGurl(request.url()); // Add URL scheme if missing from view-source URL. - if (url.scheme() == content::kViewSourceScheme) { - QUrl pageUrl = QUrl(url.toString().remove(0, strlen(content::kViewSourceScheme) + 1)); + if (request.url().scheme() == content::kViewSourceScheme) { + QUrl pageUrl = QUrl(request.url().toString().remove(0, + strlen(content::kViewSourceScheme) + 1)); if (pageUrl.scheme().isEmpty()) { QUrl extendedUrl = QUrl::fromUserInput(pageUrl.toString()); - extendedUrl = QUrl(QString("%1:%2").arg(content::kViewSourceScheme, extendedUrl.toString())); + extendedUrl = QUrl(QString("%1:%2").arg(content::kViewSourceScheme, + extendedUrl.toString())); gurl = toGurl(extendedUrl); } } content::NavigationController::LoadURLParams params(gurl); - params.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); + params.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED + | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; + + switch (request.method()) { + case QWebEngineHttpRequest::Get: + params.load_type = content::NavigationController::LOAD_TYPE_DEFAULT; + break; + + case QWebEngineHttpRequest::Post: + params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST; + // chromium accepts LOAD_TYPE_HTTP_POST only for the HTTP and HTTPS protocols + if (!params.url.SchemeIsHTTPOrHTTPS()) { + d->adapterClient->loadFinished(false, request.url(), false, + net::ERR_DISALLOWED_URL_SCHEME, + QCoreApplication::translate("WebContentsAdapter", + "HTTP-POST data can only be sent over HTTP(S) protocol")); + return; + } + break; + } + + params.post_data = content::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) { + if (params.extra_headers.length() > 0) + params.extra_headers += '\n'; + params.extra_headers += (*it).toStdString() + ": " + request.header(*it).toStdString(); + } + d->webContents->GetController().LoadURLWithParams(params); focusIfNecessary(); } @@ -563,15 +615,17 @@ QUrl WebContentsAdapter::activeUrl() const QUrl WebContentsAdapter::requestedUrl() const { Q_D(const WebContentsAdapter); - content::NavigationEntry* entry = d->webContents->GetController().GetVisibleEntry(); - content::NavigationEntry* pendingEntry = d->webContents->GetController().GetPendingEntry(); + if (d->webContents) { + content::NavigationEntry* entry = d->webContents->GetController().GetVisibleEntry(); + content::NavigationEntry* pendingEntry = d->webContents->GetController().GetPendingEntry(); - if (entry) { - if (!entry->GetOriginalRequestURL().is_empty()) - return toQt(entry->GetOriginalRequestURL()); + if (entry) { + if (!entry->GetOriginalRequestURL().is_empty()) + return toQt(entry->GetOriginalRequestURL()); - if (pendingEntry && pendingEntry == entry) - return toQt(entry->GetURL()); + if (pendingEntry && pendingEntry == entry) + return toQt(entry->GetURL()); + } } return QUrl(); } @@ -959,19 +1013,28 @@ void WebContentsAdapter::wasHidden() void WebContentsAdapter::printToPDF(const QPageLayout &pageLayout, const QString &filePath) { #if defined(ENABLE_BASIC_PRINTING) - PrintViewManagerQt::FromWebContents(webContents())->PrintToPDF(pageLayout, true, filePath); + Q_D(WebContentsAdapter); + PrintViewManagerQt::PrintToPDFFileCallback callback = base::Bind(&callbackOnPdfSavingFinished, + d->adapterClient, + filePath); + PrintViewManagerQt::FromWebContents(webContents())->PrintToPDFFileWithCallback(pageLayout, + true, + filePath, + callback); #endif // if defined(ENABLE_BASIC_PRINTING) } -quint64 WebContentsAdapter::printToPDFCallbackResult(const QPageLayout &pageLayout, const bool colorMode) +quint64 WebContentsAdapter::printToPDFCallbackResult(const QPageLayout &pageLayout, + const bool colorMode) { #if defined(ENABLE_BASIC_PRINTING) Q_D(WebContentsAdapter); - PrintViewManagerQt::PrintToPDFCallback callback = base::Bind(&callbackOnPrintingFinished - , d->adapterClient - , d->nextRequestId); - PrintViewManagerQt::FromWebContents(webContents())->PrintToPDFWithCallback(pageLayout, colorMode - , callback); + PrintViewManagerQt::PrintToPDFCallback callback = base::Bind(&callbackOnPrintingFinished, + d->adapterClient, + d->nextRequestId); + PrintViewManagerQt::FromWebContents(webContents())->PrintToPDFWithCallback(pageLayout, + colorMode, + callback); return d->nextRequestId++; #else return 0; diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 3befe6d27..cb7f9b461 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -42,6 +42,7 @@ #include "qtwebenginecoreglobal.h" #include "web_contents_adapter_client.h" +#include <QtWebEngineCore/qwebenginehttprequest.h> #include <QScopedPointer> #include <QSharedPointer> @@ -83,7 +84,8 @@ public: void stop(); void reload(); void reloadAndBypassCache(); - void load(const QUrl&); + void load(const QUrl &url); + void load(const QWebEngineHttpRequest &request); void setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl); void save(const QString &filePath = QString(), int savePageFormat = -1); QUrl activeUrl() const; diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 4e15df753..3112e4484 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -347,6 +347,7 @@ public: 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 didPrintPageToPdf(const QString &filePath, bool success) = 0; virtual void passOnFocus(bool reverse) = 0; // returns the last QObject (QWidget/QQuickItem) based object in the accessibility // hierarchy before going into the BrowserAccessibility tree diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 2e0669d4e..58f0a3e2c 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -242,6 +242,7 @@ void WebEngineSettings::initDefaults(bool offTheRecord) s_defaultAttributes.insert(FocusOnNavigationEnabled, true); s_defaultAttributes.insert(PrintElementBackgrounds, true); s_defaultAttributes.insert(AllowRunningInsecureContent, allowRunningInsecureContent); + s_defaultAttributes.insert(AllowGeolocationOnInsecureOrigins, false); } if (offTheRecord) m_attributes.insert(LocalStorageEnabled, false); @@ -325,6 +326,7 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p prefs->experimental_webgl_enabled = testAttribute(WebGLEnabled); prefs->should_print_backgrounds = testAttribute(PrintElementBackgrounds); prefs->allow_running_insecure_content = testAttribute(AllowRunningInsecureContent); + prefs->allow_geolocation_on_insecure_origins = testAttribute(AllowGeolocationOnInsecureOrigins); // Fonts settings. prefs->standard_font_family_map[content::kCommonScript] = toString16(fontFamily(StandardFont)); diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index 8459ba75b..4b0ce7b39 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -82,7 +82,8 @@ public: TouchIconsEnabled, FocusOnNavigationEnabled, PrintElementBackgrounds, - AllowRunningInsecureContent + AllowRunningInsecureContent, + AllowGeolocationOnInsecureOrigins }; // Must match the values from the public API in qwebenginesettings.h. |