diff options
42 files changed, 452 insertions, 139 deletions
diff --git a/examples/webenginewidgets/demobrowser/history.cpp b/examples/webenginewidgets/demobrowser/history.cpp index 32100e543..aaab44ac8 100644 --- a/examples/webenginewidgets/demobrowser/history.cpp +++ b/examples/webenginewidgets/demobrowser/history.cpp @@ -226,9 +226,9 @@ void HistoryManager::clear() { m_history.clear(); m_lastSavedUrl = QString(); + emit historyReset(); m_saveTimer->changeOccurred(); m_saveTimer->saveIfNeccessary(); - historyReset(); } void HistoryManager::loadSettings() diff --git a/examples/webenginewidgets/demobrowser/urllineedit.cpp b/examples/webenginewidgets/demobrowser/urllineedit.cpp index e56ab63a5..8203e4f0f 100644 --- a/examples/webenginewidgets/demobrowser/urllineedit.cpp +++ b/examples/webenginewidgets/demobrowser/urllineedit.cpp @@ -338,7 +338,7 @@ void UrlLineEdit::paintEvent(QPaintEvent *event) QColor loadingColor = QColor(116, 192, 250); painter.setBrush(generateGradient(loadingColor)); painter.setPen(Qt::transparent); - int mid = backgroundRect.width() / 100 * progress; + int mid = backgroundRect.width() / 100.0f * progress; QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height()); painter.drawRect(progressRect); } diff --git a/examples/webenginewidgets/demobrowser/webview.cpp b/examples/webenginewidgets/demobrowser/webview.cpp index 192df6836..633b72bf1 100644 --- a/examples/webenginewidgets/demobrowser/webview.cpp +++ b/examples/webenginewidgets/demobrowser/webview.cpp @@ -104,16 +104,6 @@ BrowserMainWindow *WebPage::mainWindow() return BrowserApplication::instance()->mainWindow(); } -bool WebPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) -{ - Q_UNUSED(type); - if (isMainFrame) { - m_loadingUrl = url; - emit loadingUrl(m_loadingUrl); - } - return true; -} - bool WebPage::certificateError(const QWebEngineCertificateError &error) { if (error.isOverridable()) { @@ -385,6 +375,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) } if (page()->contextMenuData().selectedText().isEmpty()) menu->addAction(page()->action(QWebEnginePage::SavePage)); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(event->globalPos()); } diff --git a/examples/webenginewidgets/demobrowser/webview.h b/examples/webenginewidgets/demobrowser/webview.h index a931d3702..e3df8f795 100644 --- a/examples/webenginewidgets/demobrowser/webview.h +++ b/examples/webenginewidgets/demobrowser/webview.h @@ -65,16 +65,11 @@ QT_END_NAMESPACE class BrowserMainWindow; class WebPage : public QWebEnginePage { Q_OBJECT - -signals: - void loadingUrl(const QUrl &url); - public: WebPage(QWebEngineProfile *profile, QObject *parent = 0); BrowserMainWindow *mainWindow(); protected: - bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type) Q_DECL_OVERRIDE; #if !defined(QT_NO_UITOOLS) QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); @@ -94,7 +89,6 @@ private: // set the webview mousepressedevent Qt::KeyboardModifiers m_keyboardModifiers; Qt::MouseButtons m_pressedButtons; - QUrl m_loadingUrl; }; class WebView : public QWebEngineView { diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp index d92545620..24835b10b 100644 --- a/examples/webenginewidgets/simplebrowser/webview.cpp +++ b/examples/webenginewidgets/simplebrowser/webview.cpp @@ -143,9 +143,11 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) if (it != actions.cend()) { (*it)->setText(tr("Open Link in This Tab")); ++it; - menu->insertAction(*it, page()->action(QWebEnginePage::OpenLinkInNewWindow)); - menu->insertAction(*it, page()->action(QWebEnginePage::OpenLinkInNewTab)); + QAction *before(it == actions.cend() ? nullptr : *it); + menu->insertAction(before, page()->action(QWebEnginePage::OpenLinkInNewWindow)); + menu->insertAction(before, page()->action(QWebEnginePage::OpenLinkInNewTab)); } + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(event->globalPos()); } diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index 116f39c68..8f004777f 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -78,6 +78,11 @@ QWEBENGINE_PRIVATE_EXPORT void initialize() qFatal("QtWebEngine::initialize() must be called after the construction of the application object."); return; } + + // Bail out silently if the user did not construct a QGuiApplication. + if (!qobject_cast<QGuiApplication *>(app)) + return; + if (app->thread() != QThread::currentThread()) { qFatal("QtWebEngine::initialize() must be called from the Qt gui thread."); return; diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp index 193c49e34..e0f933562 100644 --- a/src/core/browser_context_adapter.cpp +++ b/src/core/browser_context_adapter.cpp @@ -168,7 +168,7 @@ void BrowserContextAdapter::cancelDownload(quint32 downloadId) downloadManagerDelegate()->cancelDownload(downloadId); } -BrowserContextAdapter* BrowserContextAdapter::defaultContext() +QSharedPointer<BrowserContextAdapter> BrowserContextAdapter::defaultContext() { return WebEngineContext::current()->defaultBrowserContext(); } @@ -354,11 +354,16 @@ void BrowserContextAdapter::setHttpCacheMaxSize(int maxSize) m_browserContext->url_request_getter_->updateHttpCache(); } -QHash<QByteArray, QWebEngineUrlSchemeHandler *> &BrowserContextAdapter::customUrlSchemeHandlers() +const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &BrowserContextAdapter::customUrlSchemeHandlers() const { return m_customUrlSchemeHandlers; } +const QList<QByteArray> BrowserContextAdapter::customUrlSchemes() const +{ + return m_customUrlSchemeHandlers.keys(); +} + void BrowserContextAdapter::updateCustomUrlSchemeHandlers() { if (m_browserContext->url_request_getter_.get()) @@ -396,6 +401,12 @@ void BrowserContextAdapter::addCustomUrlSchemeHandler(const QByteArray &scheme, updateCustomUrlSchemeHandlers(); } +void BrowserContextAdapter::clearCustomUrlSchemeHandlers() +{ + m_customUrlSchemeHandlers.clear(); + updateCustomUrlSchemeHandlers(); +} + UserResourceControllerHost *BrowserContextAdapter::userResourceController() { if (!m_userResourceController) @@ -432,7 +443,21 @@ QString BrowserContextAdapter::httpAcceptLanguage() const void BrowserContextAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage) { + if (m_httpAcceptLanguage == httpAcceptLanguage) + return; m_httpAcceptLanguage = httpAcceptLanguage; + + std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents(); + Q_FOREACH (content::WebContentsImpl *web_contents, list) { + if (web_contents->GetBrowserContext() == m_browserContext.data()) { + content::RendererPreferences* rendererPrefs = web_contents->GetMutableRendererPrefs(); + rendererPrefs->accept_languages = httpAcceptLanguageWithoutQualities().toStdString(); + web_contents->GetRenderViewHost()->SyncRendererPrefs(); + } + } + + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateUserAgent(); } void BrowserContextAdapter::clearHttpCache() diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h index 3e1e6389c..c3c3f153d 100644 --- a/src/core/browser_context_adapter.h +++ b/src/core/browser_context_adapter.h @@ -42,10 +42,10 @@ #include "qtwebenginecoreglobal.h" +#include <QEnableSharedFromThis> #include <QList> #include <QPointer> #include <QScopedPointer> -#include <QSharedData> #include <QString> #include <QVector> @@ -63,14 +63,14 @@ class DownloadManagerDelegateQt; class UserResourceControllerHost; class WebEngineVisitedLinksManager; -class QWEBENGINE_EXPORT BrowserContextAdapter : public QSharedData +class QWEBENGINE_EXPORT BrowserContextAdapter : public QEnableSharedFromThis<BrowserContextAdapter> { public: explicit BrowserContextAdapter(bool offTheRecord = false); explicit BrowserContextAdapter(const QString &storagePrefix); virtual ~BrowserContextAdapter(); - static BrowserContextAdapter* defaultContext(); + static QSharedPointer<BrowserContextAdapter> defaultContext(); static QObject* globalQObjectRoot(); WebEngineVisitedLinksManager *visitedLinksManager(); @@ -156,8 +156,9 @@ public: bool trackVisitedLinks() const; bool persistVisitedLinks() const; - QHash<QByteArray, QWebEngineUrlSchemeHandler *> &customUrlSchemeHandlers(); - void updateCustomUrlSchemeHandlers(); + const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &customUrlSchemeHandlers() const; + const QList<QByteArray> customUrlSchemes() const; + void clearCustomUrlSchemeHandlers(); void addCustomUrlSchemeHandler(const QByteArray &, QWebEngineUrlSchemeHandler *); bool removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *); QWebEngineUrlSchemeHandler *takeCustomUrlSchemeHandler(const QByteArray &); @@ -173,6 +174,8 @@ public: void clearHttpCache(); private: + void updateCustomUrlSchemeHandlers(); + QString m_name; bool m_offTheRecord; QScopedPointer<BrowserContextQt> m_browserContext; diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index dc337493e..5b3115530 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -174,7 +174,7 @@ content::PushMessagingService *BrowserContextQt::GetPushMessagingService() content::SSLHostStateDelegate* BrowserContextQt::GetSSLHostStateDelegate() { if (!sslHostStateDelegate) - sslHostStateDelegate.reset(new SSLHostStateDelegateQt(m_adapter)); + sslHostStateDelegate.reset(new SSLHostStateDelegateQt()); return sslHostStateDelegate.get(); } @@ -191,13 +191,13 @@ content::BackgroundSyncController* BrowserContextQt::GetBackgroundSyncController content::PermissionManager *BrowserContextQt::GetPermissionManager() { if (!permissionManager) - permissionManager.reset(new PermissionManagerQt(m_adapter)); + permissionManager.reset(new PermissionManagerQt()); return permissionManager.get(); } net::URLRequestContextGetter *BrowserContextQt::CreateRequestContext(content::ProtocolHandlerMap *protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) { - url_request_getter_ = new URLRequestContextGetterQt(m_adapter, protocol_handlers, std::move(request_interceptors)); + url_request_getter_ = new URLRequestContextGetterQt(m_adapter->sharedFromThis(), protocol_handlers, std::move(request_interceptors)); return url_request_getter_.get(); } diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp index 3b3248559..cd57995ea 100644 --- a/src/core/clipboard_qt.cpp +++ b/src/core/clipboard_qt.cpp @@ -243,8 +243,7 @@ void ClipboardQt::WriteWebSmartPaste() void ClipboardQt::WriteBitmap(const SkBitmap& bitmap) { - QImage image(reinterpret_cast<const uchar *>(bitmap.getPixels()), bitmap.width(), bitmap.height(), QImage::Format_ARGB32); - getUncommittedData()->setImageData(image.copy()); + getUncommittedData()->setImageData(toQImage(bitmap).copy()); } void ClipboardQt::WriteBookmark(const char* title_data, size_t title_len, const char* url_data, size_t url_len) diff --git a/src/core/custom_protocol_handler.cpp b/src/core/custom_protocol_handler.cpp index 15eb82db1..402df04ba 100644 --- a/src/core/custom_protocol_handler.cpp +++ b/src/core/custom_protocol_handler.cpp @@ -46,8 +46,8 @@ namespace QtWebEngineCore { -CustomProtocolHandler::CustomProtocolHandler(QWebEngineUrlSchemeHandler *schemeHandler) - : m_schemeHandler(schemeHandler) +CustomProtocolHandler::CustomProtocolHandler(QWeakPointer<const BrowserContextAdapter> adapter) + : m_adapter(adapter) { } @@ -56,7 +56,7 @@ net::URLRequestJob *CustomProtocolHandler::MaybeCreateJob(net::URLRequest *reque if (!networkDelegate) return new net::URLRequestErrorJob(request, Q_NULLPTR, net::ERR_ACCESS_DENIED); - return new URLRequestCustomJob(request, networkDelegate, m_schemeHandler); + return new URLRequestCustomJob(request, networkDelegate, request->url().scheme(), m_adapter); } } // namespace diff --git a/src/core/custom_protocol_handler.h b/src/core/custom_protocol_handler.h index c56a983f8..38e17ffaf 100644 --- a/src/core/custom_protocol_handler.h +++ b/src/core/custom_protocol_handler.h @@ -45,10 +45,9 @@ #include <QtCore/QByteArray> #include <QtCore/QObject> -#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE +#include <QtCore/QWeakPointer> QT_FORWARD_DECLARE_CLASS(QIODevice) -QT_FORWARD_DECLARE_CLASS(QWebEngineUrlSchemeHandler) namespace net { class NetworkDelegate; @@ -64,13 +63,13 @@ class BrowserContextAdapter; class QWEBENGINE_EXPORT CustomProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { public: - CustomProtocolHandler(QWebEngineUrlSchemeHandler *); + CustomProtocolHandler(QWeakPointer<const BrowserContextAdapter> adapter); virtual net::URLRequestJob *MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const Q_DECL_OVERRIDE; private: DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler); - QWebEngineUrlSchemeHandler *m_schemeHandler; + QWeakPointer<const BrowserContextAdapter> m_adapter; }; } // namespace diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index fd57ad7b8..36ce476cd 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -69,9 +69,8 @@ BrowserContextAdapter::PermissionType toQt(content::PermissionType type) return BrowserContextAdapter::UnsupportedPermission; } -PermissionManagerQt::PermissionManagerQt(BrowserContextAdapter *contextAdapter) - : m_contextAdapter(contextAdapter) - , m_requestIdCount(0) +PermissionManagerQt::PermissionManagerQt() + : m_requestIdCount(0) , m_subscriberIdCount(0) { } diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h index 928f11c65..ff35357d8 100644 --- a/src/core/permission_manager_qt.h +++ b/src/core/permission_manager_qt.h @@ -52,7 +52,7 @@ namespace QtWebEngineCore { class PermissionManagerQt : public content::PermissionManager { public: - PermissionManagerQt(BrowserContextAdapter *); + PermissionManagerQt(); ~PermissionManagerQt(); typedef BrowserContextAdapter::PermissionType PermissionType; @@ -101,7 +101,6 @@ public: void UnsubscribePermissionStatusChange(int subscription_id) override; private: - BrowserContextAdapter *m_contextAdapter; QHash<QPair<QUrl, PermissionType>, bool> m_permissions; struct RequestOrSubscription { PermissionType type; diff --git a/src/core/ssl_host_state_delegate_qt.cpp b/src/core/ssl_host_state_delegate_qt.cpp index cf17b944c..506172aaa 100644 --- a/src/core/ssl_host_state_delegate_qt.cpp +++ b/src/core/ssl_host_state_delegate_qt.cpp @@ -72,8 +72,7 @@ void CertPolicy::Allow(const net::X509Certificate& cert, net::CertStatus error) m_allowed[fingerprint] |= error; } -SSLHostStateDelegateQt::SSLHostStateDelegateQt(BrowserContextAdapter *contextAdapter) - : m_contextAdapter(contextAdapter) +SSLHostStateDelegateQt::SSLHostStateDelegateQt() { } diff --git a/src/core/ssl_host_state_delegate_qt.h b/src/core/ssl_host_state_delegate_qt.h index 7c91fcb2d..64a430094 100644 --- a/src/core/ssl_host_state_delegate_qt.h +++ b/src/core/ssl_host_state_delegate_qt.h @@ -57,7 +57,7 @@ private: class SSLHostStateDelegateQt : public content::SSLHostStateDelegate { public: - SSLHostStateDelegateQt(BrowserContextAdapter *); + SSLHostStateDelegateQt(); ~SSLHostStateDelegateQt(); // content::SSLHostStateDelegate implementation: @@ -71,7 +71,6 @@ public: virtual bool HasAllowException(const std::string &host) const override; private: - BrowserContextAdapter *m_contextAdapter; std::map<std::string, CertPolicy> m_certPolicyforHost; }; diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index ccfc2fdc6..ef220b86c 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -197,5 +197,4 @@ FaviconInfo toFaviconInfo(const content::FaviconURL &favicon_url) return info; } - } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 84f91ec3e..e96a544e5 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -85,6 +85,11 @@ inline QString toQt(const std::string &string) return QString::fromStdString(string); } +inline QByteArray toQByteArray(const std::string &string) +{ + return QByteArray::fromStdString(string); +} + inline base::string16 toString16(const QString &qString) { #if defined(OS_WIN) diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index f80aa194b..afbb66b95 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -89,24 +89,28 @@ static const char kQrcSchemeQt[] = "qrc"; using content::BrowserThread; -URLRequestContextGetterQt::URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors) +URLRequestContextGetterQt::URLRequestContextGetterQt(QSharedPointer<BrowserContextAdapter> browserContext, content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors) : m_ignoreCertificateErrors(false) , m_browserContext(browserContext) + , m_baseJobFactory(0) , m_cookieDelegate(new CookieMonsterDelegateQt()) , m_requestInterceptors(std::move(request_interceptors)) { std::swap(m_protocolHandlers, *protocolHandlers); + m_cookieDelegate->setClient(m_browserContext->cookieStore()); updateStorageSettings(); } URLRequestContextGetterQt::~URLRequestContextGetterQt() { + m_cookieDelegate->setCookieMonster(0); // this will let CookieMonsterDelegateQt be deleted delete m_proxyConfigService.fetchAndStoreAcquire(0); } net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); if (!m_urlRequestContext) { m_urlRequestContext.reset(new net::URLRequestContext()); @@ -123,14 +127,16 @@ net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() void URLRequestContextGetterQt::updateStorageSettings() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + // m_proxyConfigService having a non-null value is used to indicate + // storage is already being updated. if (!m_proxyConfigService.loadAcquire()) { // We must create the proxy config service on the UI loop on Linux because it // must synchronously run on the glib message loop. This will be passed to // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). - m_proxyConfigService = new ProxyConfigServiceQt(net::ProxyService::CreateSystemProxyConfigService( + m_proxyConfigService.storeRelease(new ProxyConfigServiceQt(net::ProxyService::CreateSystemProxyConfigService( content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) - )); + ))); if (m_storage) { content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateStorage, this)); } @@ -154,6 +160,7 @@ void URLRequestContextGetterQt::cancelAllUrlRequests() void URLRequestContextGetterQt::generateStorage() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); // We must stop all requests before deleting their backends. @@ -206,14 +213,15 @@ void URLRequestContextGetterQt::generateStorage() void URLRequestContextGetterQt::updateCookieStore() { - if (m_urlRequestContext && !m_updateCookieStore && !m_proxyConfigService) { - m_updateCookieStore = 1; + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + // Do not trigger an update if another is already triggered, or we are not yet initialized. + if (m_urlRequestContext && !m_proxyConfigService && !m_updateCookieStore.fetchAndStoreRelaxed(1)) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateCookieStore, this)); - } } void URLRequestContextGetterQt::generateCookieStore() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); m_updateCookieStore = 0; @@ -221,7 +229,6 @@ void URLRequestContextGetterQt::generateCookieStore() // Unset it first to get a chance to destroy and flush the old cookie store before opening a new on possibly the same file. m_storage->set_cookie_store(0); m_cookieDelegate->setCookieMonster(0); - m_cookieDelegate->setClient(m_browserContext->cookieStore()); net::CookieStore* cookieStore = 0; switch (m_browserContext->persistentCookiesPolicy()) { @@ -262,51 +269,38 @@ void URLRequestContextGetterQt::generateCookieStore() void URLRequestContextGetterQt::updateUserAgent() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + // Do not trigger an update if all storage settings are already being updated if (m_urlRequestContext && !m_proxyConfigService) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateUserAgent, this)); } -class HttpUserAgentSettingsQt : public net::HttpUserAgentSettings -{ - const BrowserContextAdapter *m_browserContext; -public: - HttpUserAgentSettingsQt(const BrowserContextAdapter *ctx) - : m_browserContext(ctx) - { - } - - std::string GetAcceptLanguage() const Q_DECL_OVERRIDE - { - return m_browserContext->httpAcceptLanguage().toStdString(); - } - - std::string GetUserAgent() const Q_DECL_OVERRIDE - { - return m_browserContext->httpUserAgent().toStdString(); - } -}; - void URLRequestContextGetterQt::generateUserAgent() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); - m_storage->set_http_user_agent_settings(scoped_ptr<net::HttpUserAgentSettings>(new HttpUserAgentSettingsQt(m_browserContext.constData()))); + m_storage->set_http_user_agent_settings(scoped_ptr<net::HttpUserAgentSettings>( + new net::StaticHttpUserAgentSettings(m_browserContext->httpAcceptLanguage().toStdString(), m_browserContext->httpUserAgent().toStdString()))); } void URLRequestContextGetterQt::updateHttpCache() { - if (m_urlRequestContext && !m_updateHttpCache && !m_proxyConfigService) { - m_updateHttpCache = 1; + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + // Do not trigger a new update if another is already triggered + if (m_urlRequestContext && !m_proxyConfigService && !m_updateHttpCache.fetchAndStoreRelaxed(1)) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateHttpCache, this)); - } } void URLRequestContextGetterQt::updateJobFactory() { - Q_ASSERT(m_jobFactory); + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateJobFactory, this)); + if (m_urlRequestContext && !m_updateJobFactory.fetchAndStoreRelaxed(1)) + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestContextGetterQt::regenerateJobFactory, + this, m_browserContext->customUrlSchemes())); } static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &first, const net::HttpNetworkSession::Params &second) @@ -357,6 +351,7 @@ net::HttpNetworkSession::Params URLRequestContextGetterQt::generateNetworkSessio void URLRequestContextGetterQt::generateHttpCache() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); @@ -420,9 +415,10 @@ void URLRequestContextGetterQt::clearCurrentCacheBackend() void URLRequestContextGetterQt::generateJobFactory() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); + Q_ASSERT(!m_jobFactory); - m_jobFactory.reset(); scoped_ptr<net::URLRequestJobFactoryImpl> jobFactory(new net::URLRequestJobFactoryImpl()); { @@ -430,6 +426,7 @@ void URLRequestContextGetterQt::generateJobFactory() content::ProtocolHandlerMap::iterator it = m_protocolHandlers.find(url::kBlobScheme); Q_ASSERT(it != m_protocolHandlers.end()); jobFactory->SetProtocolHandler(it->first, scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(it->second.release())); + m_protocolHandlers.clear(); } jobFactory->SetProtocolHandler(url::kDataScheme, scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new net::DataProtocolHandler())); @@ -440,10 +437,12 @@ void URLRequestContextGetterQt::generateJobFactory() jobFactory->SetProtocolHandler(url::kFtpScheme, scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new net::FtpProtocolHandler(new net::FtpNetworkLayer(m_urlRequestContext->host_resolver())))); - QHash<QByteArray, QWebEngineUrlSchemeHandler*>::const_iterator it = m_browserContext->customUrlSchemeHandlers().constBegin(); - const QHash<QByteArray, QWebEngineUrlSchemeHandler*>::const_iterator end = m_browserContext->customUrlSchemeHandlers().constEnd(); - for (; it != end; ++it) - jobFactory->SetProtocolHandler(it.key().toStdString(), scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new CustomProtocolHandler(it.value()))); + m_installedCustomSchemes = m_browserContext->customUrlSchemes(); + Q_FOREACH (const QByteArray &scheme, m_installedCustomSchemes) { + jobFactory->SetProtocolHandler(scheme.toStdString(), scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new CustomProtocolHandler(m_browserContext))); + } + + m_baseJobFactory = jobFactory.get(); // Set up interceptors in the reverse order. scoped_ptr<net::URLRequestJobFactory> topJobFactory = std::move(jobFactory); @@ -458,6 +457,27 @@ void URLRequestContextGetterQt::generateJobFactory() m_urlRequestContext->set_job_factory(m_jobFactory.get()); } +void URLRequestContextGetterQt::regenerateJobFactory(const QList<QByteArray> customSchemes) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_jobFactory); + Q_ASSERT(m_baseJobFactory); + + m_updateJobFactory.storeRelease(0); + if (customSchemes == m_installedCustomSchemes) + return; + + Q_FOREACH (const QByteArray &scheme, m_installedCustomSchemes) { + m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), nullptr); + } + + m_installedCustomSchemes = customSchemes; + Q_FOREACH (const QByteArray &scheme, m_installedCustomSchemes) { + m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new CustomProtocolHandler(m_browserContext))); + } +} + scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetterQt::GetNetworkTaskRunner() const { return content::BrowserThread::GetMessageLoopProxyForThread(content::BrowserThread::IO); diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 13d6e2f72..7078c7a44 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -56,8 +56,9 @@ #include "cookie_monster_delegate_qt.h" #include "network_delegate_qt.h" -#include "qglobal.h" -#include <qatomic.h> +#include <QtCore/qglobal.h> +#include <QtCore/qatomic.h> +#include <QtCore/qsharedpointer.h> namespace net { class MappedHostResolver; @@ -70,7 +71,7 @@ class BrowserContextAdapter; class URLRequestContextGetterQt : public net::URLRequestContextGetter { public: - explicit URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors); + URLRequestContextGetterQt(QSharedPointer<BrowserContextAdapter> browserContext, content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors); virtual net::URLRequestContext *GetURLRequestContext() Q_DECL_OVERRIDE; virtual scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const Q_DECL_OVERRIDE; @@ -92,6 +93,7 @@ private: void generateHttpCache(); void generateUserAgent(); void generateJobFactory(); + void regenerateJobFactory(const QList<QByteArray> customSchemes); void clearCurrentCacheBackend(); void cancelAllUrlRequests(); net::HttpNetworkSession::Params generateNetworkSessionParams(); @@ -99,7 +101,8 @@ private: bool m_ignoreCertificateErrors; QAtomicInt m_updateCookieStore; QAtomicInt m_updateHttpCache; - QExplicitlySharedDataPointer<BrowserContextAdapter> m_browserContext; + QAtomicInt m_updateJobFactory; + QSharedPointer<BrowserContextAdapter> m_browserContext; content::ProtocolHandlerMap m_protocolHandlers; QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; @@ -107,10 +110,12 @@ private: scoped_ptr<NetworkDelegateQt> m_networkDelegate; scoped_ptr<net::URLRequestContextStorage> m_storage; scoped_ptr<net::URLRequestJobFactory> m_jobFactory; + net::URLRequestJobFactoryImpl *m_baseJobFactory; scoped_ptr<net::DhcpProxyScriptFetcherFactory> m_dhcpProxyScriptFetcherFactory; scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate; content::URLRequestInterceptorScopedVector m_requestInterceptors; scoped_ptr<net::HttpNetworkSession> m_httpNetworkSession; + QList<QByteArray> m_installedCustomSchemes; friend class NetworkDelegateQt; }; diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp index 79a54650c..921be0b41 100644 --- a/src/core/url_request_custom_job.cpp +++ b/src/core/url_request_custom_job.cpp @@ -42,6 +42,7 @@ #include "api/qwebengineurlrequestjob.h" #include "api/qwebengineurlschemehandler.h" +#include "browser_context_adapter.h" #include "type_conversion.h" #include "content/public/browser/browser_thread.h" @@ -57,9 +58,11 @@ using namespace net; namespace QtWebEngineCore { -URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, NetworkDelegate *networkDelegate, QWebEngineUrlSchemeHandler *schemeHandler) +URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, NetworkDelegate *networkDelegate, + const std::string &scheme, QWeakPointer<const BrowserContextAdapter> adapter) : URLRequestJob(request, networkDelegate) - , m_schemeHandler(schemeHandler) + , m_scheme(scheme) + , m_adapter(adapter) , m_shared(new URLRequestCustomJobShared(this)) { } @@ -328,11 +331,22 @@ void URLRequestCustomJobShared::startAsync() delete this; return; } - m_delegate = new URLRequestCustomJobDelegate(this); - m_asyncInitialized = true; - QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate); - if (m_job) - m_job->m_schemeHandler->requestStarted(requestJob); + + QWebEngineUrlSchemeHandler *schemeHandler = 0; + QSharedPointer<const BrowserContextAdapter> browserContext = m_job->m_adapter.toStrongRef(); + if (browserContext) + schemeHandler = browserContext->customUrlSchemeHandlers()[toQByteArray(m_job->m_scheme)]; + if (schemeHandler) { + m_delegate = new URLRequestCustomJobDelegate(this); + m_asyncInitialized = true; + QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate); + schemeHandler->requestStarted(requestJob); + } else { + lock.unlock(); + abort(); + delete this; + return; + } } } // namespace diff --git a/src/core/url_request_custom_job.h b/src/core/url_request_custom_job.h index e9f48216b..226c39e68 100644 --- a/src/core/url_request_custom_job.h +++ b/src/core/url_request_custom_job.h @@ -48,17 +48,17 @@ #include <QtCore/QPointer> QT_FORWARD_DECLARE_CLASS(QIODevice) -QT_FORWARD_DECLARE_CLASS(QWebEngineUrlSchemeHandler) namespace QtWebEngineCore { +class BrowserContextAdapter; class URLRequestCustomJobDelegate; class URLRequestCustomJobShared; // A request job that handles reading custom URL schemes class URLRequestCustomJob : public net::URLRequestJob { public: - URLRequestCustomJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate, QWebEngineUrlSchemeHandler *schemeHandler); + URLRequestCustomJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate, const std::string &scheme, QWeakPointer<const BrowserContextAdapter> adapter); virtual void Start() Q_DECL_OVERRIDE; virtual void Kill() Q_DECL_OVERRIDE; virtual int ReadRawData(net::IOBuffer* buf, int buf_size) Q_DECL_OVERRIDE;; @@ -70,7 +70,8 @@ protected: virtual ~URLRequestCustomJob(); private: - QWebEngineUrlSchemeHandler *m_schemeHandler; + std::string m_scheme; + QWeakPointer<const BrowserContextAdapter> m_adapter; URLRequestCustomJobShared *m_shared; friend class URLRequestCustomJobShared; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 1d937b62d..116cd704e 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -517,6 +517,7 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT params.virtual_url_for_data_url = baseUrl.isEmpty() ? GURL(url::kAboutBlankURL) : toGurl(baseUrl); params.can_load_local_resources = true; params.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_API); + params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; d->webContents->GetController().LoadURLWithParams(params); d->webContents->Focus(); } @@ -708,7 +709,15 @@ void WebContentsAdapter::setZoomFactor(qreal factor) Q_D(WebContentsAdapter); if (factor < content::kMinimumZoomFactor || factor > content::kMaximumZoomFactor) return; - content::HostZoomMap::SetZoomLevel(d->webContents.get(), content::ZoomFactorToZoomLevel(static_cast<double>(factor))); + + double zoomLevel = content::ZoomFactorToZoomLevel(static_cast<double>(factor)); + content::HostZoomMap *zoomMap = content::HostZoomMap::GetForWebContents(d->webContents.get()); + + if (zoomMap) { + int render_process_id = d->webContents->GetRenderProcessHost()->GetID(); + int render_view_id = d->webContents->GetRenderViewHost()->GetRoutingID(); + zoomMap->SetTemporaryZoomLevel(render_process_id, render_view_id, zoomLevel); + } } qreal WebContentsAdapter::currentZoomFactor() const diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index f99cedcad..80aabaa4d 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -258,8 +258,9 @@ public: virtual void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) = 0; - virtual BrowserContextAdapter* browserContextAdapter() = 0; + virtual QSharedPointer<BrowserContextAdapter> browserContextAdapter() = 0; virtual WebContentsAdapter* webContentsAdapter() = 0; + }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 0507ebf4a..5c0e83298 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -57,8 +57,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include <QExplicitlySharedDataPointer> #include <QScopedPointer> +#include <QSharedPointer> QT_FORWARD_DECLARE_CLASS(QTimer) QT_FORWARD_DECLARE_CLASS(QWebChannel) @@ -83,7 +83,7 @@ public: WebContentsAdapterPrivate(); ~WebContentsAdapterPrivate(); scoped_refptr<WebEngineContext> engineContext; - QExplicitlySharedDataPointer<BrowserContextAdapter> browserContextAdapter; + QSharedPointer<BrowserContextAdapter> browserContextAdapter; scoped_ptr<content::WebContents> webContents; scoped_ptr<WebContentsDelegateQt> webContentsDelegate; scoped_ptr<RenderViewObserverHostQt> renderViewObserverHost; diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index b3bfc432b..6da80e94d 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -164,7 +164,7 @@ namespace QtWebEngineCore { void WebEngineContext::destroyBrowserContext() { - m_defaultBrowserContext = 0; + m_defaultBrowserContext.reset(); } void WebEngineContext::destroy() @@ -198,11 +198,11 @@ scoped_refptr<WebEngineContext> WebEngineContext::current() return sContext; } -BrowserContextAdapter* WebEngineContext::defaultBrowserContext() +QSharedPointer<BrowserContextAdapter> WebEngineContext::defaultBrowserContext() { if (!m_defaultBrowserContext) - m_defaultBrowserContext = new BrowserContextAdapter(QStringLiteral("Default")); - return m_defaultBrowserContext.data(); + m_defaultBrowserContext = QSharedPointer<BrowserContextAdapter>::create(QStringLiteral("Default")); + return m_defaultBrowserContext; } QObject *WebEngineContext::globalQObject() diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index 3c69d87ca..960f8ed47 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -47,7 +47,7 @@ #include "base/values.h" #include "components/devtools_http_handler/devtools_http_handler.h" -#include <QExplicitlySharedDataPointer> +#include <QSharedPointer> namespace base { class RunLoop; @@ -76,7 +76,7 @@ class WebEngineContext : public base::RefCounted<WebEngineContext> { public: static scoped_refptr<WebEngineContext> current(); - QtWebEngineCore::BrowserContextAdapter *defaultBrowserContext(); + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> defaultBrowserContext(); QObject *globalQObject(); #if defined(ENABLE_BASIC_PRINTING) printing::PrintJobManager* getPrintJobManager(); @@ -94,7 +94,7 @@ private: scoped_ptr<content::ContentMainRunner> m_contentRunner; scoped_ptr<content::BrowserMainRunner> m_browserRunner; QObject* m_globalQObject; - QExplicitlySharedDataPointer<BrowserContextAdapter> m_defaultBrowserContext; + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_defaultBrowserContext; scoped_ptr<devtools_http_handler::DevToolsHttpHandler> m_devtools; #if defined(ENABLE_BASIC_PRINTING) scoped_ptr<printing::PrintJobManager> m_printJobManager; diff --git a/src/webengine/api/qquickwebenginehistory.cpp b/src/webengine/api/qquickwebenginehistory.cpp index 96a4415e0..8c7662028 100644 --- a/src/webengine/api/qquickwebenginehistory.cpp +++ b/src/webengine/api/qquickwebenginehistory.cpp @@ -223,7 +223,7 @@ QQuickWebEngineHistoryPrivate::~QQuickWebEngineHistoryPrivate() The WebEngineHistory type can be accessed by using the \l{WebEngineView::navigationHistory}{WebEngineView.navigationHistory} property. - The WebEngineHistory type providess the following WebEngineHistoryListModel data model objects: + The WebEngineHistory type provides the following WebEngineHistoryListModel data model objects: \list \li \c backItems, which contains the URLs of visited pages. @@ -283,9 +283,8 @@ QQuickWebEngineHistory::~QQuickWebEngineHistory() } /*! - \qmlproperty QQuickWebEngineHistoryListModel WebEngineHistory::items + \qmlproperty WebEngineHistoryListModel WebEngineHistory::items \readonly - \since QtWebEngine 1.1 URLs of back items, forward items, and the current item in the history. */ @@ -298,9 +297,8 @@ QQuickWebEngineHistoryListModel *QQuickWebEngineHistory::items() const } /*! - \qmlproperty QQuickWebEngineHistoryListModel WebEngineHistory::backItems + \qmlproperty WebEngineHistoryListModel WebEngineHistory::backItems \readonly - \since QtWebEngine 1.1 URLs of visited pages. */ @@ -313,9 +311,8 @@ QQuickWebEngineHistoryListModel *QQuickWebEngineHistory::backItems() const } /*! - \qmlproperty QQuickWebEngineHistoryListModel WebEngineHistory::forwardItems + \qmlproperty WebEngineHistoryListModel WebEngineHistory::forwardItems \readonly - \since QtWebEngine 1.1 URLs of the pages that were visited after visiting the current page. */ diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index f38422966..d7a84c106 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -134,7 +134,7 @@ ASSERT_ENUMS_MATCH(QQuickWebEngineDownloadItem::MimeHtmlSaveFormat, QtWebEngineC The \a download argument holds the state of the finished download instance. */ -QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext) +QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter> browserContext) : m_settings(new QQuickWebEngineSettings()) , m_browserContextRef(browserContext) { @@ -261,7 +261,7 @@ void QQuickWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info */ QQuickWebEngineProfile::QQuickWebEngineProfile(QObject *parent) : QObject(parent), - d_ptr(new QQuickWebEngineProfilePrivate(new BrowserContextAdapter(false))) + d_ptr(new QQuickWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter>::create(false))) { // Sets up the global WebEngineContext QQuickWebEngineProfile::defaultProfile(); @@ -822,8 +822,7 @@ void QQuickWebEngineProfile::removeUrlScheme(const QByteArray &scheme) void QQuickWebEngineProfile::removeAllUrlSchemeHandlers() { Q_D(QQuickWebEngineProfile); - d->browserContext()->customUrlSchemeHandlers().clear(); - d->browserContext()->updateCustomUrlSchemeHandlers(); + d->browserContext()->clearCustomUrlSchemeHandlers(); } void QQuickWebEngineProfile::destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler *obj) diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h index f9bb08500..1ba1eb53f 100644 --- a/src/webengine/api/qquickwebengineprofile_p.h +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -58,6 +58,7 @@ #include <QExplicitlySharedDataPointer> #include <QMap> #include <QPointer> +#include <QSharedPointer> QT_BEGIN_NAMESPACE @@ -67,10 +68,10 @@ class QQuickWebEngineSettings; class QQuickWebEngineProfilePrivate : public QtWebEngineCore::BrowserContextAdapterClient { public: Q_DECLARE_PUBLIC(QQuickWebEngineProfile) - QQuickWebEngineProfilePrivate(QtWebEngineCore::BrowserContextAdapter* browserContext); + QQuickWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext); ~QQuickWebEngineProfilePrivate(); - QtWebEngineCore::BrowserContextAdapter *browserContext() const { return m_browserContextRef.data(); } + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const { return m_browserContextRef; } QQuickWebEngineSettings *settings() const { return m_settings.data(); } void cancelDownload(quint32 downloadId); @@ -83,7 +84,7 @@ private: friend class QQuickWebEngineViewPrivate; QQuickWebEngineProfile *q_ptr; QScopedPointer<QQuickWebEngineSettings> m_settings; - QExplicitlySharedDataPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef; + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef; QMap<quint32, QPointer<QQuickWebEngineDownloadItem> > m_ongoingDownloads; }; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 122ae2350..0f50328e6 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -123,6 +123,7 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() , m_webChannelWorld(0) , m_dpiScale(1.0) , m_backgroundColor(Qt::white) + , m_defaultZoomFactor(1.0) { // The gold standard for mobile web content is 160 dpi, and the devicePixelRatio expected // is the (possibly quantized) ratio of device dpi to 160 dpi. @@ -652,7 +653,7 @@ QObject *QQuickWebEngineViewPrivate::accessibilityParentObject() } #endif // QT_NO_ACCESSIBILITY -BrowserContextAdapter *QQuickWebEngineViewPrivate::browserContextAdapter() +QSharedPointer<BrowserContextAdapter> QQuickWebEngineViewPrivate::browserContextAdapter() { return m_profile->d_ptr->browserContext(); } @@ -771,6 +772,10 @@ void QQuickWebEngineViewPrivate::adoptWebContents(WebContentsAdapter *webContent Q_FOREACH (QQuickWebEngineScript *script, m_userScripts) script->d_func()->bind(browserContextAdapter()->userResourceController(), adapter.data()); + // set the zoomFactor if it had been changed on the old adapter. + if (!qFuzzyCompare(adapter->currentZoomFactor(), m_defaultZoomFactor)) + q->setZoomFactor(m_defaultZoomFactor); + // Emit signals for values that might be different from the previous WebContentsAdapter. emit q->titleChanged(); emit q->urlChanged(); @@ -807,6 +812,7 @@ QQuickWebEngineView::~QQuickWebEngineView() void QQuickWebEngineViewPrivate::ensureContentsAdapter() { + Q_Q(QQuickWebEngineView); if (!adapter) { adapter = new WebContentsAdapter(); adapter->initialize(this); @@ -819,6 +825,10 @@ void QQuickWebEngineViewPrivate::ensureContentsAdapter() // push down the page's user scripts Q_FOREACH (QQuickWebEngineScript *script, m_userScripts) script->d_func()->bind(browserContextAdapter()->userResourceController(), adapter.data()); + // set the zoomFactor if it had been changed on the old adapter. + if (!qFuzzyCompare(adapter->currentZoomFactor(), m_defaultZoomFactor)) + q->setZoomFactor(m_defaultZoomFactor); + } } @@ -910,8 +920,11 @@ void QQuickWebEngineView::stop() void QQuickWebEngineView::setZoomFactor(qreal arg) { Q_D(QQuickWebEngineView); + d->m_defaultZoomFactor = arg; + if (!d->adapter) return; + qreal oldFactor = d->adapter->currentZoomFactor(); d->adapter->setZoomFactor(arg); if (qFuzzyCompare(oldFactor, d->adapter->currentZoomFactor())) @@ -1139,7 +1152,7 @@ qreal QQuickWebEngineView::zoomFactor() const { Q_D(const QQuickWebEngineView); if (!d->adapter) - return 1.0; + return d->m_defaultZoomFactor; return d->adapter->currentZoomFactor(); } diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 892e99cb9..82a9e9612 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -188,7 +188,7 @@ public: void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) Q_DECL_OVERRIDE; - virtual QtWebEngineCore::BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; + virtual QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContextAdapter() Q_DECL_OVERRIDE; QtWebEngineCore::WebContentsAdapter *webContentsAdapter() Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal); @@ -232,6 +232,7 @@ private: QList<QQuickWebEngineScript *> m_userScripts; qreal m_dpiScale; QColor m_backgroundColor; + qreal m_defaultZoomFactor; }; #ifndef QT_NO_ACCESSIBILITY diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 8ba6c8770..54989caaf 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -484,7 +484,7 @@ void QWebEnginePagePrivate::setFullScreenMode(bool fullscreen) } } -BrowserContextAdapter *QWebEnginePagePrivate::browserContextAdapter() +QSharedPointer<BrowserContextAdapter> QWebEnginePagePrivate::browserContextAdapter() { return profile->d_ptr->browserContext(); } diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 58515bfbe..22bfaff95 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -136,7 +136,7 @@ public: void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) Q_DECL_OVERRIDE; - virtual QtWebEngineCore::BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; + virtual QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContextAdapter() Q_DECL_OVERRIDE; QtWebEngineCore::WebContentsAdapter *webContentsAdapter() Q_DECL_OVERRIDE; void updateAction(QWebEnginePage::WebAction) const; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 3a2254427..2dab0aa08 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -140,7 +140,7 @@ using QtWebEngineCore::BrowserContextAdapter; \sa QWebEngineDownloadItem */ -QWebEngineProfilePrivate::QWebEngineProfilePrivate(BrowserContextAdapter* browserContext) +QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter> browserContext) : m_settings(new QWebEngineSettings()) , m_scriptCollection(new QWebEngineScriptCollection(new QWebEngineScriptCollectionPrivate(browserContext->userResourceController()))) , m_browserContextRef(browserContext) @@ -235,7 +235,7 @@ void QWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info) */ QWebEngineProfile::QWebEngineProfile(QObject *parent) : QObject(parent) - , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(true))) + , d_ptr(new QWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter>::create(true))) { d_ptr->q_ptr = this; } @@ -252,7 +252,7 @@ QWebEngineProfile::QWebEngineProfile(QObject *parent) */ QWebEngineProfile::QWebEngineProfile(const QString &storageName, QObject *parent) : QObject(parent) - , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(storageName))) + , d_ptr(new QWebEngineProfilePrivate(QSharedPointer<BrowserContextAdapter>::create(storageName))) { d_ptr->q_ptr = this; } @@ -712,8 +712,7 @@ void QWebEngineProfile::removeUrlScheme(const QByteArray &scheme) void QWebEngineProfile::removeAllUrlSchemeHandlers() { Q_D(QWebEngineProfile); - d->browserContext()->customUrlSchemeHandlers().clear(); - d->browserContext()->updateCustomUrlSchemeHandlers(); + d->browserContext()->clearCustomUrlSchemeHandlers(); } void QWebEngineProfile::destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler *obj) diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h index 9809da42e..4d31c5a81 100644 --- a/src/webenginewidgets/api/qwebengineprofile_p.h +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -57,6 +57,7 @@ #include <QMap> #include <QPointer> #include <QScopedPointer> +#include <QSharedPointer> namespace QtWebEngineCore { class BrowserContextAdapter; @@ -69,10 +70,10 @@ class QWebEngineSettings; class QWebEngineProfilePrivate : public QtWebEngineCore::BrowserContextAdapterClient { public: Q_DECLARE_PUBLIC(QWebEngineProfile) - QWebEngineProfilePrivate(QtWebEngineCore::BrowserContextAdapter* browserContext); + QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext); ~QWebEngineProfilePrivate(); - QtWebEngineCore::BrowserContextAdapter *browserContext() const { return m_browserContextRef.data(); } + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const { return m_browserContextRef; } QWebEngineSettings *settings() const { return m_settings; } void cancelDownload(quint32 downloadId); @@ -85,7 +86,7 @@ private: QWebEngineProfile *q_ptr; QWebEngineSettings *m_settings; QScopedPointer<QWebEngineScriptCollection> m_scriptCollection; - QExplicitlySharedDataPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef; + QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef; QMap<quint32, QPointer<QWebEngineDownloadItem> > m_ongoingDownloads; }; diff --git a/tests/auto/quick/qmltests/data/localStorage.html b/tests/auto/quick/qmltests/data/localStorage.html new file mode 100644 index 000000000..a4e395f48 --- /dev/null +++ b/tests/auto/quick/qmltests/data/localStorage.html @@ -0,0 +1,9 @@ +<html> +<head><title>Original Title</title></head> +<body> +<script type="text/javascript"> +document.title = localStorage.getItem('title'); +localStorage.setItem('title', 'New Title'); +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/tst_settings.qml b/tests/auto/quick/qmltests/data/tst_settings.qml new file mode 100644 index 000000000..aa3a6dc60 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_settings.qml @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 1.2 + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + + TestCase { + name: "WebEngineViewSettings" + + function test_javascriptEnabled() { + webEngineView.settings.javascriptEnabled = true; + + webEngineView.url = Qt.resolvedUrl("javascript.html"); + verify(webEngineView.waitForLoadSucceeded()); + compare(webEngineView.title, "New Title"); + } + + function test_javascriptDisabled() { + webEngineView.settings.javascriptEnabled = false; + + webEngineView.url = Qt.resolvedUrl("javascript.html"); + verify(webEngineView.waitForLoadSucceeded()); + compare(webEngineView.title, "Original Title"); + } + + function test_localStorageDisabled() { + webEngineView.settings.javascriptEnabled = true; + webEngineView.settings.localStorageEnabled = false; + + webEngineView.url = Qt.resolvedUrl("localStorage.html"); + verify(webEngineView.waitForLoadSucceeded()); + compare(webEngineView.title, "Original Title"); + } + + function test_localStorageEnabled() { + webEngineView.settings.localStorageEnabled = true; + webEngineView.settings.javascriptEnabled = true; + + webEngineView.url = Qt.resolvedUrl("localStorage.html"); + verify(webEngineView.waitForLoadSucceeded()); + webEngineView.reload(); + verify(webEngineView.waitForLoadSucceeded()); + compare(webEngineView.title, "New Title"); + } + + function test_settingsAffectCurrentViewOnly() { + var webEngineView2 = Qt.createQmlObject('TestWebEngineView {width: 400; height: 300;}', webEngineView); + + webEngineView.settings.javascriptEnabled = true; + webEngineView2.settings.javascriptEnabled = true; + + var testUrl = Qt.resolvedUrl("javascript.html"); + + webEngineView.url = testUrl; + verify(webEngineView.waitForLoadSucceeded()); + webEngineView2.url = testUrl; + verify(webEngineView2.waitForLoadSucceeded()); + + compare(webEngineView.title, "New Title"); + compare(webEngineView2.title, "New Title"); + + webEngineView.settings.javascriptEnabled = false; + + webEngineView.url = testUrl; + verify(webEngineView.waitForLoadSucceeded()); + webEngineView2.url = testUrl; + verify(webEngineView2.waitForLoadSucceeded()); + + compare(webEngineView.title, "Original Title"); + compare(webEngineView2.title, "New Title"); + + webEngineView2.destroy(); + } + } +} + diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index af6e14c33..b8f0f7df1 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -27,6 +27,7 @@ OTHER_FILES += \ $$PWD/data/geolocation.html \ $$PWD/data/javascript.html \ $$PWD/data/link.html \ + $$PWD/data/localStorage.html \ $$PWD/data/prompt.html \ $$PWD/data/multifileupload.html \ $$PWD/data/redirect.html \ @@ -61,6 +62,7 @@ OTHER_FILES += \ $$PWD/data/tst_unhandledKeyEventPropagation.qml \ $$PWD/data/tst_userScripts.qml \ $$PWD/data/tst_webchannel.qml \ + $$PWD/data/tst_settings.qml \ $$PWD/data/tst_keyboardModifierMapping.qml \ $$PWD/data/icons/favicon.png \ $$PWD/data/icons/grayicons.ico \ diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index f2f5b31f9..f6968acf5 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -60,6 +60,7 @@ private Q_SLOTS: void inputMethod(); void inputMethodHints(); void basicRenderingSanity(); + void setZoomFactor(); void printToPdf(); private: @@ -462,6 +463,25 @@ void tst_QQuickWebEngineView::inputMethodHints() #endif } +void tst_QQuickWebEngineView::setZoomFactor() +{ + QQuickWebEngineView *view = webEngineView(); + + QVERIFY(qFuzzyCompare(view->zoomFactor(), 1.0)); + view->setZoomFactor(2.5); + QVERIFY(qFuzzyCompare(view->zoomFactor(), 2.5)); + + view->setUrl(urlFromTestPath("html/basic_page.html")); + QVERIFY(waitForLoadSucceeded(view)); + QVERIFY(qFuzzyCompare(view->zoomFactor(), 2.5)); + + view->setZoomFactor(0.1); + QVERIFY(qFuzzyCompare(view->zoomFactor(), 2.5)); + + view->setZoomFactor(5.5); + QVERIFY(qFuzzyCompare(view->zoomFactor(), 2.5)); +} + void tst_QQuickWebEngineView::printToPdf() { QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 2740b698c..eb0c5910e 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -237,6 +237,7 @@ private Q_SLOTS: void restoreHistory(); void toPlainTextLoadFinishedRace_data(); void toPlainTextLoadFinishedRace(); + void setZoomFactor(); void printToPdf(); @@ -4983,6 +4984,31 @@ void tst_QWebEnginePage::toPlainTextLoadFinishedRace() QVERIFY(spy.count() == 3); } +void tst_QWebEnginePage::setZoomFactor() +{ + QWebEnginePage *page = new QWebEnginePage; + + QVERIFY(qFuzzyCompare(page->zoomFactor(), 1.0)); + page->setZoomFactor(2.5); + QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + + const QUrl urlToLoad("qrc:/resources/test1.html"); + + QSignalSpy finishedSpy(m_page, SIGNAL(loadFinished(bool))); + m_page->setUrl(urlToLoad); + QTRY_COMPARE(finishedSpy.count(), 1); + QVERIFY(finishedSpy.at(0).first().toBool()); + QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + + page->setZoomFactor(5.5); + QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + + page->setZoomFactor(0.1); + QVERIFY(qFuzzyCompare(page->zoomFactor(), 2.5)); + + delete page; +} + void tst_QWebEnginePage::printToPdf() { QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp index e73ab637b..95d5cf16a 100644 --- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -47,6 +47,8 @@ private Q_SLOTS: void disableCache(); void urlSchemeHandlers(); void urlSchemeHandlerFailRequest(); + void customUserAgent(); + void httpAcceptLanguage(); }; void tst_QWebEngineProfile::defaultProfile() @@ -253,5 +255,60 @@ void tst_QWebEngineProfile::urlSchemeHandlerFailRequest() QCOMPARE(toPlainTextSync(view.page()), QString()); } +void tst_QWebEngineProfile::customUserAgent() +{ + QString defaultUserAgent = QWebEngineProfile::defaultProfile()->httpUserAgent(); + QWebEnginePage page; + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + page.setHtml(QStringLiteral("<html><body>Hello world!</body></html>")); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + + // First test the user-agent is default + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), defaultUserAgent); + + const QString testUserAgent = QStringLiteral("tst_QWebEngineProfile 1.0"); + QWebEngineProfile testProfile; + testProfile.setHttpUserAgent(testUserAgent); + + // Test a new profile with custom user-agent works + QWebEnginePage page2(&testProfile); + QSignalSpy loadFinishedSpy2(&page2, SIGNAL(loadFinished(bool))); + page2.setHtml(QStringLiteral("<html><body>Hello again!</body></html>")); + QTRY_COMPARE(loadFinishedSpy2.count(), 1); + QCOMPARE(evaluateJavaScriptSync(&page2, QStringLiteral("navigator.userAgent")).toString(), testUserAgent); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), defaultUserAgent); + + // Test an existing page and profile with custom user-agent works + QWebEngineProfile::defaultProfile()->setHttpUserAgent(testUserAgent); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), testUserAgent); +} + +void tst_QWebEngineProfile::httpAcceptLanguage() +{ + QWebEnginePage page; + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + page.setHtml(QStringLiteral("<html><body>Hello world!</body></html>")); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + + QStringList defaultLanguages = evaluateJavaScriptSync(&page, QStringLiteral("navigator.languages")).toStringList(); + + const QString testLang = QStringLiteral("xx-YY"); + QWebEngineProfile testProfile; + testProfile.setHttpAcceptLanguage(testLang); + + // Test a completely new profile + QWebEnginePage page2(&testProfile); + QSignalSpy loadFinishedSpy2(&page2, SIGNAL(loadFinished(bool))); + page2.setHtml(QStringLiteral("<html><body>Hello again!</body></html>")); + QTRY_COMPARE(loadFinishedSpy2.count(), 1); + QCOMPARE(evaluateJavaScriptSync(&page2, QStringLiteral("navigator.languages")).toStringList(), QStringList(testLang)); + // Test the old one wasn't affected + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.languages")).toStringList(), defaultLanguages); + + // Test changing an existing page and profile + QWebEngineProfile::defaultProfile()->setHttpAcceptLanguage(testLang); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.languages")).toStringList(), QStringList(testLang)); +} + QTEST_MAIN(tst_QWebEngineProfile) #include "tst_qwebengineprofile.moc" |