diff options
32 files changed, 197 insertions, 102 deletions
diff --git a/examples/webenginewidgets/demobrowser/Info_mac.plist b/examples/webenginewidgets/demobrowser/Info_mac.plist index ccd4b3f28..25443f7be 100644 --- a/examples/webenginewidgets/demobrowser/Info_mac.plist +++ b/examples/webenginewidgets/demobrowser/Info_mac.plist @@ -41,5 +41,7 @@ </array> <key>NOTE</key> <string>DemoBrowser by The Qt Company Ltd.</string> + <key>NSSupportsAutomaticGraphicsSwitching</key> + <string>YES</string> </dict> </plist> diff --git a/examples/webenginewidgets/demobrowser/webview.cpp b/examples/webenginewidgets/demobrowser/webview.cpp index ab2a4f3c6..498df74fc 100644 --- a/examples/webenginewidgets/demobrowser/webview.cpp +++ b/examples/webenginewidgets/demobrowser/webview.cpp @@ -363,6 +363,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) QMenu *menu; if (page()->contextMenuData().linkUrl().isValid()) { menu = new QMenu(this); + menu->setAttribute(Qt::WA_DeleteOnClose, true); menu->addAction(page()->action(QWebEnginePage::OpenLinkInThisWindow)); menu->addAction(page()->action(QWebEnginePage::OpenLinkInNewWindow)); menu->addAction(page()->action(QWebEnginePage::OpenLinkInNewTab)); @@ -375,7 +376,6 @@ 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/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp index 657993fc6..e4e7f5efa 100644 --- a/examples/webenginewidgets/simplebrowser/webview.cpp +++ b/examples/webenginewidgets/simplebrowser/webview.cpp @@ -151,7 +151,6 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) 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/qtwebengine.pro b/qtwebengine.pro index 3fd5c12e6..b6e735876 100644 --- a/qtwebengine.pro +++ b/qtwebengine.pro @@ -1,4 +1,3 @@ -load(qt_build_config) load(qt_parts) isPlatformSupported() { diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp index a3806fc63..877b376b0 100644 --- a/src/core/api/qwebengineurlrequestinfo.cpp +++ b/src/core/api/qwebengineurlrequestinfo.cpp @@ -96,7 +96,7 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q interceptor on the profile enables intercepting, blocking, and modifying URL requests before they reach the networking stack of Chromium. - \sa QWebEngineUrlRequestInterceptor::interceptRequest, QWebEngineUrlRequestInfo + \sa interceptRequest(), QWebEngineUrlRequestInfo */ /*! @@ -115,7 +115,7 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::OtherNavigation, Q \a info contains the information about the URL request and will track internally whether its members have been altered. - \sa QWebEngineProfile::setRequestInterceptor + \sa QWebEngineProfile::setRequestInterceptor() */ @@ -183,7 +183,7 @@ QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPriva /*! Returns the resource type of the request. - \sa QWebEngineUrlRequestInfo::ResourceType + \sa ResourceType */ QWebEngineUrlRequestInfo::ResourceType QWebEngineUrlRequestInfo::resourceType() const @@ -208,7 +208,7 @@ QWebEngineUrlRequestInfo::ResourceType QWebEngineUrlRequestInfo::resourceType() /*! Returns the navigation type of the request. - \sa QWebEngineUrlRequestInfo::NavigationType + \sa NavigationType */ QWebEngineUrlRequestInfo::NavigationType QWebEngineUrlRequestInfo::navigationType() const diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp index 74b097ef6..158ff7f67 100644 --- a/src/core/file_picker_controller.cpp +++ b/src/core/file_picker_controller.cpp @@ -49,18 +49,18 @@ namespace QtWebEngineCore { -FilePickerController::FilePickerController(FileChooserMode mode, content::WebContents *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) +FilePickerController::FilePickerController(FileChooserMode mode, content::RenderFrameHost *frameHost, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject *parent) : QObject(parent) , m_defaultFileName(defaultFileName) , m_acceptedMimeTypes(acceptedMimeTypes) - , m_contents(contents) + , m_frameHost(frameHost) , m_mode(mode) { } void FilePickerController::accepted(const QStringList &files) { - FilePickerController::filesSelectedInChooser(files, m_contents); + FilePickerController::filesSelectedInChooser(files, m_frameHost); } void FilePickerController::accepted(const QVariant &files) @@ -76,12 +76,12 @@ void FilePickerController::accepted(const QVariant &files) qWarning("An unhandled type '%s' was provided in FilePickerController::accepted(QVariant)", files.typeName()); } - FilePickerController::filesSelectedInChooser(stringList, m_contents); + FilePickerController::filesSelectedInChooser(stringList, m_frameHost); } void FilePickerController::rejected() { - FilePickerController::filesSelectedInChooser(QStringList(), m_contents); + FilePickerController::filesSelectedInChooser(QStringList(), m_frameHost); } static QStringList listRecursively(const QDir &dir) @@ -103,15 +103,14 @@ ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, content::FileChooserParam ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, content::FileChooserParams::UploadFolder) ASSERT_ENUMS_MATCH(FilePickerController::Save, content::FileChooserParams::Save) -void FilePickerController::filesSelectedInChooser(const QStringList &filesList, content::WebContents *contents) +void FilePickerController::filesSelectedInChooser(const QStringList &filesList, content::RenderFrameHost *frameHost) { - content::RenderViewHost *rvh = contents->GetRenderViewHost(); - Q_ASSERT(rvh); + Q_ASSERT(frameHost); QStringList files(filesList); if (this->m_mode == UploadFolder && !filesList.isEmpty() && QFileInfo(filesList.first()).isDir()) // Enumerate the directory files = listRecursively(QDir(filesList.first())); - rvh->GetMainFrame()->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(this->m_mode)); + frameHost->FilesSelectedInChooser(toVector<content::FileChooserFileInfo>(files), static_cast<content::FileChooserParams::Mode>(this->m_mode)); } QStringList FilePickerController::acceptedMimeTypes() const diff --git a/src/core/file_picker_controller.h b/src/core/file_picker_controller.h index 14e8de42d..66f28c3fc 100644 --- a/src/core/file_picker_controller.h +++ b/src/core/file_picker_controller.h @@ -45,7 +45,7 @@ #include <QStringList> namespace content { - class WebContents; + class RenderFrameHost; } namespace QtWebEngineCore { @@ -60,7 +60,7 @@ public: Save }; - FilePickerController(FileChooserMode mode, content::WebContents *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); + FilePickerController(FileChooserMode mode, content::RenderFrameHost *contents, const QString &defaultFileName, const QStringList &acceptedMimeTypes, QObject * = 0); QStringList acceptedMimeTypes() const; QString defaultFileName() const; FileChooserMode mode() const; @@ -71,10 +71,10 @@ public Q_SLOTS: void rejected(); private: - void filesSelectedInChooser(const QStringList &filesList, content::WebContents *contents); + void filesSelectedInChooser(const QStringList &filesList, content::RenderFrameHost *contents); QString m_defaultFileName; QStringList m_acceptedMimeTypes; - content::WebContents *m_contents; + content::RenderFrameHost *m_frameHost; FileChooserMode m_mode; }; diff --git a/src/core/javascript_dialog_manager_qt.cpp b/src/core/javascript_dialog_manager_qt.cpp index 2844dba5d..5fac12dd3 100644 --- a/src/core/javascript_dialog_manager_qt.cpp +++ b/src/core/javascript_dialog_manager_qt.cpp @@ -71,7 +71,7 @@ void JavaScriptDialogManagerQt::RunJavaScriptDialog(content::WebContents *webCon void JavaScriptDialogManagerQt::RunBeforeUnloadDialog(content::WebContents *webContents, bool isReload, const content::JavaScriptDialogManager::DialogClosedCallback &callback) { Q_UNUSED(isReload); - runDialogForContents(webContents, WebContentsAdapterClient::UnloadDialog, QString()/*toQt(messageText).toHtmlEscaped()*/, QString() , QUrl(), callback); + runDialogForContents(webContents, WebContentsAdapterClient::UnloadDialog, QString(), QString(), QUrl(), callback); } bool JavaScriptDialogManagerQt::HandleJavaScriptDialog(content::WebContents *contents, bool accept, const base::string16 *promptOverride) diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 870b19eef..f1c69fca3 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -238,6 +238,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget , m_needsDelegatedFrameAck(false) , m_loadVisuallyCommittedState(NotCommitted) , m_adapterClient(0) + , m_currentInputType(ui::TEXT_INPUT_TYPE_NONE) , m_imeInProgress(false) , m_receivedEmptyImeText(false) , m_initPending(false) diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index cabf44ac6..635b7c2d0 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -268,6 +268,7 @@ void URLRequestContextGetterQt::updateCookieStore() if (m_contextInitialized && !m_updateAllStorage && !m_updateCookieStore) { m_updateCookieStore = true; + m_updateHttpCache = true; content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateCookieStore, this)); } @@ -337,6 +338,12 @@ void URLRequestContextGetterQt::generateCookieStore() const std::vector<std::string> cookieableSchemes(kCookieableSchemes, kCookieableSchemes + arraysize(kCookieableSchemes)); cookieMonster->SetCookieableSchemes(cookieableSchemes); m_cookieDelegate->setCookieMonster(cookieMonster); + + if (!m_updateAllStorage) { + Q_ASSERT(m_updateHttpCache); + // HttpCache needs to be regenerated when we generate a new channel id service + generateHttpCache(); + } } void URLRequestContextGetterQt::updateUserAgent() diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 384724736..7b0712143 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -87,8 +87,8 @@ #include <QPageLayout> #include <QStringList> #include <QStyleHints> -#include <QTimer> #include <QVariant> +#include <QtCore/qelapsedtimer.h> #include <QtCore/qmimedata.h> #include <QtGui/qaccessible.h> #include <QtGui/qdrag.h> @@ -349,8 +349,6 @@ WebContentsAdapterPrivate::WebContentsAdapterPrivate() , nextRequestId(CallbackDirectory::ReservedCallbackIdsEnd) , lastFindRequestId(0) , currentDropAction(blink::WebDragOperationNone) - , inDragUpdateLoop(false) - , updateDragCursorMessagePollingTimer(new QTimer) { } @@ -393,7 +391,6 @@ WebContentsAdapter::WebContentsAdapter(content::WebContents *webContents) { Q_D(WebContentsAdapter); d->webContents.reset(webContents); - initUpdateDragCursorMessagePollingTimer(); } WebContentsAdapter::~WebContentsAdapter() @@ -1295,50 +1292,42 @@ Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const Q d->lastDragScreenPos = toGfx(screenPos); rvh->DragTargetDragOver(d->lastDragClientPos, d->lastDragScreenPos, toWeb(e->possibleActions()), toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); - - base::MessageLoop *currentMessageLoop = base::MessageLoop::current(); - DCHECK(currentMessageLoop); - if (!currentMessageLoop->NestableTasksAllowed()) { - // We're already inside a MessageLoop::RunTask call, and scheduled tasks will not be - // executed. That means, updateDragAction will never be called, and the RunLoop below will - // remain blocked forever. - qWarning("WebContentsAdapter::updateDragPosition called from MessageLoop::RunTask."); - return Qt::IgnoreAction; - } - - // Wait until we get notified via RenderViewHostDelegateView::UpdateDragCursor. This calls - // WebContentsAdapter::updateDragAction that will eventually quit the nested loop. - base::RunLoop loop; - d->inDragUpdateLoop = true; - d->dragUpdateLoopQuitClosure = loop.QuitClosure(); - - d->updateDragCursorMessagePollingTimer->start(); - loop.Run(); - d->updateDragCursorMessagePollingTimer->stop(); - + waitForUpdateDragActionCalled(); return toQt(d->currentDropAction); } -void WebContentsAdapter::updateDragAction(int action) +void WebContentsAdapter::waitForUpdateDragActionCalled() { Q_D(WebContentsAdapter); - d->currentDropAction = static_cast<blink::WebDragOperation>(action); - finishDragUpdate(); + const qint64 timeout = 3000; + QElapsedTimer t; + t.start(); + base::MessagePump::Delegate *delegate = base::MessageLoop::current(); + DCHECK(delegate); + d->updateDragActionCalled = false; + for (;;) { + while (delegate->DoWork() && !d->updateDragActionCalled) {} + if (d->updateDragActionCalled) + break; + if (t.hasExpired(timeout)) { + qWarning("WebContentsAdapter::updateDragAction was not called within %d ms.", + static_cast<int>(timeout)); + return; + } + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); + } } -void WebContentsAdapter::finishDragUpdate() +void WebContentsAdapter::updateDragAction(int action) { Q_D(WebContentsAdapter); - if (d->inDragUpdateLoop) { - d->dragUpdateLoopQuitClosure.Run(); - d->inDragUpdateLoop = false; - } + d->updateDragActionCalled = true; + d->currentDropAction = static_cast<blink::WebDragOperation>(action); } void WebContentsAdapter::endDragging(const QPoint &clientPos, const QPoint &screenPos) { Q_D(WebContentsAdapter); - finishDragUpdate(); content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); rvh->FilterDropData(d->currentDropData.get()); d->lastDragClientPos = toGfx(clientPos); @@ -1350,32 +1339,11 @@ void WebContentsAdapter::endDragging(const QPoint &clientPos, const QPoint &scre void WebContentsAdapter::leaveDrag() { Q_D(WebContentsAdapter); - finishDragUpdate(); content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); rvh->DragTargetDragLeave(); d->currentDropData.reset(); } -void WebContentsAdapter::initUpdateDragCursorMessagePollingTimer() -{ - Q_D(WebContentsAdapter); - // Poll for drag cursor updated message 60 times per second. In practice, the timer is fired - // at most twice, after which it is stopped. - d->updateDragCursorMessagePollingTimer->setInterval(16); - d->updateDragCursorMessagePollingTimer->setSingleShot(false); - - QObject::connect(d->updateDragCursorMessagePollingTimer.data(), &QTimer::timeout, [](){ - base::MessagePump::Delegate *delegate = base::MessageLoop::current(); - DCHECK(delegate); - - // Execute Chromium tasks if there are any present. Specifically we are interested to handle - // the RenderViewHostImpl::OnUpdateDragCursor message, that gets sent from the render - // process. - while (delegate->DoWork()) {} - }); -} - - void WebContentsAdapter::replaceMisspelling(const QString &word) { #if defined(ENABLE_SPELLCHECK) diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 0accd3be5..10c65a6cb 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -169,10 +169,8 @@ public: void enterDrag(QDragEnterEvent *e, const QPoint &screenPos); Qt::DropAction updateDragPosition(QDragMoveEvent *e, const QPoint &screenPos); void updateDragAction(int action); - void finishDragUpdate(); void endDragging(const QPoint &clientPos, const QPoint &screenPos); void leaveDrag(); - void initUpdateDragCursorMessagePollingTimer(); void printToPDF(const QPageLayout&, const QString&); quint64 printToPDFCallbackResult(const QPageLayout &, const bool colorMode = true); @@ -188,8 +186,9 @@ public: private: Q_DISABLE_COPY(WebContentsAdapter) Q_DECLARE_PRIVATE(WebContentsAdapter) - QScopedPointer<WebContentsAdapterPrivate> d_ptr; + void waitForUpdateDragActionCalled(); + QScopedPointer<WebContentsAdapterPrivate> d_ptr; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 9503b4401..f24070523 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -61,7 +61,6 @@ #include <QScopedPointer> #include <QSharedPointer> -QT_FORWARD_DECLARE_CLASS(QTimer) QT_FORWARD_DECLARE_CLASS(QWebChannel) class WebEngineContext; @@ -96,11 +95,9 @@ public: int lastFindRequestId; std::unique_ptr<content::DropData> currentDropData; blink::WebDragOperation currentDropAction; - bool inDragUpdateLoop; + bool updateDragActionCalled; gfx::Point lastDragClientPos; gfx::Point lastDragScreenPos; - base::Closure dragUpdateLoopQuitClosure; - QScopedPointer<QTimer> updateDragCursorMessagePollingTimer; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index c7ad844a8..fb32ea813 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -327,7 +327,7 @@ void WebContentsDelegateQt::RunFileChooser(content::RenderFrameHost *frameHost, acceptedMimeTypes.append(toQt(*it)); m_filePickerController.reset(new FilePickerController(static_cast<FilePickerController::FileChooserMode>(params.mode), - web_contents(), toQt(params.default_file_name.value()), acceptedMimeTypes)); + frameHost, toQt(params.default_file_name.value()), acceptedMimeTypes)); // Defer the call to not block base::MessageLoop::RunTask with modal dialogs. QTimer::singleShot(0, [this] () { diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp index 2142b5f0d..61e26c4a3 100644 --- a/src/tools/qwebengine_convert_dict/main.cpp +++ b/src/tools/qwebengine_convert_dict/main.cpp @@ -120,9 +120,34 @@ int main(int argc, char *argv[]) return 1; } - PathService::Override(base::DIR_QT_LIBRARY_DATA, - toFilePath(QLibraryInfo::location(QLibraryInfo::DataPath) % - QLatin1String("/resources"))); + bool icuDataDirFound = false; + QString icuDataDir = QLibraryInfo::location(QLibraryInfo::DataPath) + % QLatin1String("/resources"); + + // Try to look up the path to the ICU data directory via an environment variable + // (e.g. for the case when the tool is ran during build phase, and regular installed + // ICU data file is not available). + QString icuPossibleEnvDataDir = QString::fromLatin1(qgetenv("QT_WEBENGINE_ICU_DATA_DIR")); + if (!icuPossibleEnvDataDir.isEmpty() && QFileInfo::exists(icuPossibleEnvDataDir)) { + icuDataDir = icuPossibleEnvDataDir; + icuDataDirFound = true; + } + // Try to find the ICU data directory in the installed Qt location. + else if (QFileInfo::exists(icuDataDir)) { + icuDataDirFound = true; + } + + if (icuDataDirFound) { + PathService::Override(base::DIR_QT_LIBRARY_DATA, toFilePath(icuDataDir)); + } else { + QTextStream out(stdout); + out << "Couldn't find ICU data directory. Please check that the following path exists: " + << icuDataDir + << "\nAlternatively provide the directory path via the QT_WEBENGINE_ICU_DAT_DIR " + "environment variable.\n" << endl; + return 1; + } + base::AtExitManager exit_manager; base::i18n::InitializeICU(); diff --git a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro index 4f0de84e3..2bdfee304 100644 --- a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro +++ b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro @@ -47,4 +47,11 @@ INCLUDEPATH += $$CHROMIUM_SRC_DIR SOURCES += \ main.cpp +# Support converting dictionaries in a prefix build, by supplying +# the path to the ICU data file located in the Qt build path, rather +# than the install path (which is not present at build time). +icu_data_dir.name = QT_WEBENGINE_ICU_DATA_DIR +icu_data_dir.value = $$OUT_PWD/../../../src/core/$$getConfigDir() +QT_TOOL_ENV = icu_data_dir load(qt_tool) +QT_TOOL_ENV = diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 162dbe1d7..f22ec86a4 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -336,7 +336,7 @@ QQuickWebEngineProfile::~QQuickWebEngineProfile() The storage name that is used to create separate subdirectories for each profile that uses the disk for storing persistent data and cache. - \sa QQuickWebEngineProfile::persistentStoragePath, QQuickWebEngineProfile::cachePath + \sa persistentStoragePath, cachePath */ QString QQuickWebEngineProfile::storageName() const diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 2db25584c..1cc0969ef 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -881,6 +881,8 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) QQuickWebEngineView::~QQuickWebEngineView() { Q_D(QQuickWebEngineView); + if (d->adapter) + d->adapter->stopFinding(); if (d->faviconProvider) d->faviconProvider->detach(this); } diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc index 615e3eed0..851507659 100644 --- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc @@ -131,6 +131,13 @@ \li Text fields might be painted with a different style on Mountain Lion (\macos 10.8). \endlist + \section1 macOS Airplay Support on MacBooks with Dual GPUs + + To make Qt WebEngine work correctly when streaming to an AppleTV from a MacBook that supports + GPU switching, it is important to add the \c NSSupportsAutomaticGraphicsSwitching option to the + application Info.plist file, with the value set to \c YES. Otherwise rendering issues might + occur when creating new web engine view instances after Airplay is switched on or off. + \section1 Default QSurfaceFormat OpenGL Profile Support If a new default QSurfaceFormat with a modified OpenGL profile has to be set, it should be set diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index f79b0ca22..4e4fc406f 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -323,7 +323,8 @@ void RenderWidgetHostViewQtDelegateQuick::touchEvent(QTouchEvent *event) void RenderWidgetHostViewQtDelegateQuick::hoverMoveEvent(QHoverEvent *event) { QQuickItem *parent = parentItem(); - if (!m_isPopup && parent && !parent->property("activeFocusOnPress").toBool() && !parent->hasActiveFocus()) { + if ((!m_isPopup && parent && !parent->property("activeFocusOnPress").toBool() + && !parent->hasActiveFocus()) || event->posF() == event->oldPosF()) { event->ignore(); return; } diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index a37484023..4a47a49eb 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -330,7 +330,10 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d item->setParentItem(m_view); dialog->setParent(m_view); QQmlProperty textProp(dialog, QStringLiteral("text")); - textProp.write(dialogController->message()); + if (dialogController->type() == WebContentsAdapterClient::UnloadDialog) + textProp.write(tr("Changes that you made may not be saved.")); + else + textProp.write(dialogController->message()); QQmlProperty titleProp(dialog, QStringLiteral("title")); titleProp.write(title); diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp index 582f0308c..1950221c7 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.cpp +++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp @@ -218,7 +218,7 @@ quint32 QWebEngineDownloadItem::id() const This signal is emitted whenever the download's \a state changes. - \sa state(), QWebEngineDownloadItem::DownloadState + \sa state(), DownloadState */ /*! @@ -327,7 +327,7 @@ quint32 QWebEngineDownloadItem::id() const /*! Returns the download item's current state. - \sa QWebEngineDownloadItem::DownloadState + \sa DownloadState */ QWebEngineDownloadItem::DownloadState QWebEngineDownloadItem::state() const diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 2af3db414..8908af3c4 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -821,6 +821,8 @@ QWebEnginePage::QWebEnginePage(QWebEngineProfile *profile, QObject* parent) QWebEnginePage::~QWebEnginePage() { Q_D(QWebEnginePage); + if (d->adapter) + d->adapter->stopFinding(); QWebEngineViewPrivate::bind(d->view, 0); } @@ -842,7 +844,7 @@ QWebEngineSettings *QWebEnginePage::settings() const * that is exposed in the JavaScript context of this page as \c qt.webChannelTransport. * * \since 5.5 - * \sa setWebChannel + * \sa setWebChannel() */ QWebChannel *QWebEnginePage::webChannel() const { @@ -1455,7 +1457,7 @@ void QWebEnginePagePrivate::javascriptDialog(QSharedPointer<JavaScriptDialogCont controller->textProvided(promptResult); break; case UnloadDialog: - accepted = (QMessageBox::information(view, QCoreApplication::translate("QWebEnginePage", "Are you sure you want to leave this page?"), controller->message(), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes); + accepted = (QMessageBox::question(view, QCoreApplication::translate("QWebEnginePage", "Are you sure you want to leave this page?"), QCoreApplication::translate("QWebEnginePage", "Changes that you made may not be saved."), QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok); break; case InternalAuthorizationDialog: accepted = (QMessageBox::question(view, controller->title(), controller->message(), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes); @@ -1632,6 +1634,8 @@ QMenu *QWebEnginePage::createStandardContextMenu() if (d->isFullScreenMode()) menu->addAction(QWebEnginePage::action(ExitFullScreen)); + menu->setAttribute(Qt::WA_DeleteOnClose, true); + return menu; } diff --git a/src/webenginewidgets/api/qwebenginescript.cpp b/src/webenginewidgets/api/qwebenginescript.cpp index 04a9d979a..d5247cde1 100644 --- a/src/webenginewidgets/api/qwebenginescript.cpp +++ b/src/webenginewidgets/api/qwebenginescript.cpp @@ -196,7 +196,7 @@ ASSERT_ENUMS_MATCH(QWebEngineScript::DocumentCreation, UserScript::DocumentEleme * Returns the point in the loading process at which the script will be executed. * The default value is QWebEngineScript::Deferred. * - * \sa setInjectionPoint + * \sa setInjectionPoint() */ QWebEngineScript::InjectionPoint QWebEngineScript::injectionPoint() const { @@ -205,7 +205,7 @@ QWebEngineScript::InjectionPoint QWebEngineScript::injectionPoint() const /*! * Sets the point at which to execute the script to be \a p. * - * \sa QWebEngineScript::InjectionPoint + * \sa InjectionPoint */ void QWebEngineScript::setInjectionPoint(QWebEngineScript::InjectionPoint p) { diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 58d805fcb..56948bb18 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -333,7 +333,6 @@ bool QWebEngineView::event(QEvent *ev) void QWebEngineView::contextMenuEvent(QContextMenuEvent *event) { QMenu *menu = page()->createStandardContextMenu(); - connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(event->globalPos()); } diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index 58abc9fa1..7616ebcee 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -538,7 +538,7 @@ This signal is emitted whenever the page requests the web browser window to be closed, for example through the JavaScript \c{window.close()} call. - \sa QWebEnginePage::RequestClose + \sa RequestClose */ /*! @@ -729,7 +729,7 @@ /*! \fn void QWebEnginePage::featurePermissionRequested(const QUrl &securityOrigin, Feature feature) - This is signal is emitted when the web site identified by \a securityOrigin requests to make use of + This signal is emitted when the web site identified by \a securityOrigin requests to make use of the resource or device identified by \a feature. \sa featurePermissionRequestCanceled(), setFeaturePermission() @@ -738,7 +738,7 @@ /*! \fn void QWebEnginePage::featurePermissionRequestCanceled(const QUrl &securityOrigin, Feature feature) - This is signal is emitted when the web site identified by \a securityOrigin cancels a previously issued + This signal is emitted when the web site identified by \a securityOrigin cancels a previously issued request to make use of \a feature. \sa featurePermissionRequested(), setFeaturePermission() diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 69ecbe160..e7ad5b107 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -64,6 +64,8 @@ public: RenderWidgetHostViewQuickItem(RenderWidgetHostViewQtDelegateClient *client) : m_client(client) { setFlag(ItemHasContents, true); + // Mark that this item should receive focus when the parent QQuickWidget receives focus. + setFocus(true); } protected: void focusInEvent(QFocusEvent *event) override @@ -180,10 +182,14 @@ void RenderWidgetHostViewQtDelegateWidget::initAsPopup(const QRect& screenRect) setAttribute(Qt::WA_ShowWithoutActivating); setFocusPolicy(Qt::NoFocus); +#ifdef Q_OS_MACOS // macOS doesn't like Qt::ToolTip when QWebEngineView is inside a modal dialog, specifically by // not forwarding click events to the popup. So we use Qt::Tool which behaves the same way, but // works on macOS too. setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); +#else + setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); +#endif setGeometry(screenRect); show(); diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 4d4268324..60c11addc 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -32,8 +32,8 @@ OTHER_FILES += \ $$PWD/data/prompt.html \ $$PWD/data/multifileupload.html \ $$PWD/data/redirect.html \ + $$PWD/data/script-with-metadata.js \ $$PWD/data/singlefileupload.html \ - $$PWD/data/small-favicon.png \ $$PWD/data/test1.html \ $$PWD/data/test2.html \ $$PWD/data/test3.html \ @@ -41,6 +41,7 @@ OTHER_FILES += \ $$PWD/data/keyboardModifierMapping.html \ $$PWD/data/keyboardEvents.html \ $$PWD/data/titleupdate.js \ + $$PWD/data/tst_activeFocusOnPress.qml \ $$PWD/data/tst_desktopBehaviorLoadHtml.qml \ $$PWD/data/tst_download.qml \ $$PWD/data/tst_favicon.qml \ @@ -72,6 +73,7 @@ OTHER_FILES += \ $$PWD/data/tst_settings.qml \ $$PWD/data/tst_keyboardModifierMapping.qml \ $$PWD/data/tst_keyboardEvents.qml \ + $$PWD/data/webchannel-test.html \ $$PWD/data/icons/favicon.png \ $$PWD/data/icons/gray128.png \ $$PWD/data/icons/gray16.png \ diff --git a/tests/auto/quick/qquickwebengineview/BLACKLIST b/tests/auto/quick/qquickwebengineview/BLACKLIST index 2cde59454..6cfd71635 100644 --- a/tests/auto/quick/qquickwebengineview/BLACKLIST +++ b/tests/auto/quick/qquickwebengineview/BLACKLIST @@ -3,3 +3,6 @@ windows [inputEventForwardingDisabledWhenActiveFocusOnPressDisabled] * + +[changeLocale] +windows diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST index 0a909d0f6..d249ac141 100644 --- a/tests/auto/widgets/qwebengineview/BLACKLIST +++ b/tests/auto/widgets/qwebengineview/BLACKLIST @@ -1,2 +1,5 @@ [doNotSendMouseKeyboardEventsWhenDisabled] windows +[changeLocale] +windows +linux diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 8057b5beb..e51171437 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -87,6 +87,7 @@ private Q_SLOTS: void stopSettingFocusWhenDisabled_data(); void focusOnNavigation_data(); void focusOnNavigation(); + void focusInternalRenderWidgetHostViewQuickItem(); void changeLocale(); void inputMethodsTextFormat_data(); @@ -858,11 +859,60 @@ void tst_QWebEngineView::focusOnNavigation() webView->setFocus(); QTRY_COMPARE(webView->hasFocus(), true); + // Clean up. #undef loadAndTriggerFocusAndCompare #undef triggerJavascriptFocus } +void tst_QWebEngineView::focusInternalRenderWidgetHostViewQuickItem() +{ + // Create a container widget, that will hold a line edit that has initial focus, and a web + // engine view. + QScopedPointer<QWidget> containerWidget(new QWidget); + QLineEdit *label = new QLineEdit; + label->setText(QString::fromLatin1("Text")); + label->setFocus(); + + // Create the web view, and set its focusOnNavigation property to false, so it doesn't + // get initial focus. + QWebEngineView *webView = new QWebEngineView; + QWebEngineSettings *settings = webView->page()->settings(); + settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); + webView->resize(300, 300); + + QHBoxLayout *layout = new QHBoxLayout; + layout->addWidget(label); + layout->addWidget(webView); + + containerWidget->setLayout(layout); + containerWidget->show(); + QTest::qWaitForWindowExposed(containerWidget.data()); + + // Load the content, and check that focus is not set. + QSignalSpy loadSpy(webView, SIGNAL(loadFinished(bool))); + webView->setHtml("<html><head><title>Title</title></head><body>Hello" + "<input id=\"input\" type=\"text\"></body></html>"); + QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(webView->hasFocus(), false); + + // Manually trigger focus. + webView->setFocus(); + + // Check that focus is set in QWebEngineView and all internal classes. + QTRY_COMPARE(webView->hasFocus(), true); + + QQuickWidget *renderWidgetHostViewQtDelegateWidget = + qobject_cast<QQuickWidget *>(webView->focusProxy()); + QVERIFY(renderWidgetHostViewQtDelegateWidget); + QTRY_COMPARE(renderWidgetHostViewQtDelegateWidget->hasFocus(), true); + + QQuickItem *renderWidgetHostViewQuickItem = + renderWidgetHostViewQtDelegateWidget->rootObject(); + QVERIFY(renderWidgetHostViewQuickItem); + QTRY_COMPARE(renderWidgetHostViewQuickItem->hasFocus(), true); +} + void tst_QWebEngineView::changeLocale() { QStringList errorLines; diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index 5e294b96b..b4965129c 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -13,6 +13,18 @@ defineTest(isQtMinimum) { } } +defineTest(isMinMSVCVersion) { + actual = $$split(MSVC_VER, .) + actual_major = $$member(actual, 0) + actual_minor = $$member(actual, 1) + requested_major = $$1 + requested_minor = $$2 + lessThan(actual_major, $$requested_major): return(false) + greaterThan(actual_major, $$requested_major): return(true) + lessThan(actual_minor, $$requested_minor): return(false) + return(true) +} + defineTest(isPlatformSupported) { QT_FOR_CONFIG += gui-private linux { @@ -27,7 +39,7 @@ defineTest(isPlatformSupported) { return(false) } msvc { - !equals(MSVC_VER, "14.0") { + !isMinMSVCVersion(14, 0) { skipBuild("Qt WebEngine on Windows requires MSVC 2015 Update 2 or later.") return(false) } |