diff options
53 files changed, 580 insertions, 513 deletions
diff --git a/dist/changes-5.9.1 b/dist/changes-5.9.1 new file mode 100644 index 000000000..8d361db10 --- /dev/null +++ b/dist/changes-5.9.1 @@ -0,0 +1,61 @@ +Qt 5.9.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0. + +Qt 5.9 introduces many new features and improvements as well as bugfixes +over the 5.8.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* General * +**************************************************************************** + + - Chromium Snapshot: + * Security fixes from Chromium up to version 59.0.3071.104 + Including: CVE-2017-5070, CVE-2017-5071, CVE-2017-5075, CVE-2017-5076, + CVE-2017-5077, CVE-2017-5078, CVE-2017-5079, CVE-2017-5083, + CVE-2017-5088, CVE-2017-5089 + * Fixed building with WebRTC disabled + + - QtWebEngineCore: + * [QTBUG-59690] Fixed issue with drops + * [QTBUG-60588] Fixed error in updating user-agent and accept-language + * [QTBUG-61047] Fixed assert in URLRequestContextGetterQt + * [QTBUG-61165] Fixed building with spellchecker disabled + * [QTBUG-61186] Fixed cancellation of upload folder dialogs + * [QTBUG-61200] Fixed runtime crash when configured with -no-accessibility + + - QtWebEngine: + * [QTBUG-57675] Fixed WebEngineNewViewRequest::requestedUrl when opening + window from JavaScript + + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + + - Linux: + * [QTBUG-60886] Support building with system ICU 59 + * [QTBUG-61128] Support building on Aarch64 hosts + + - Windows: + * [QTBUG-61170] Fixed building with plugins disabled + * Re-enabled building on 32-bit Windows hosts + + - macOS: + * [QTBUG-55165] Fixed WebRTC screen sharing on macOS + * [QTBUG-60706] Find Google Chrome's flash plugin again + * [QTBUG-60707] Fixed spellchecker installation error + * [QTBUG-61413] Fixed erroneous extra rpath diff --git a/examples/webengine/customdialogs/doc/src/customdialogs.qdoc b/examples/webengine/customdialogs/doc/src/customdialogs.qdoc index f5a18b591..2162fe4ca 100644 --- a/examples/webengine/customdialogs/doc/src/customdialogs.qdoc +++ b/examples/webengine/customdialogs/doc/src/customdialogs.qdoc @@ -58,10 +58,11 @@ \section1 Triggering Dialogs - The technical details on how the dialogs are triggered are beyond the scope - of this example. The only thing worth mentioning is that we fire up the - localhost TCP server when the example starts up. The server is needed to - get proxy and HTTP authentication requests. + As mentioned, the \l {webengine/customdialogs/index.html}{index.html} file + is responsible for triggering the dialogs from the side of HTML and + JavaScript. Additionally, the example program starts a localhost TCP server + returning the mocked HTTP responses needed to trigger proxy and HTTP + authentication dialogs. \section1 Custom Dialogs diff --git a/examples/webengine/quicknanobrowser/doc/src/quicknanobrowser.qdoc b/examples/webengine/quicknanobrowser/doc/src/quicknanobrowser.qdoc index 75c2997e8..93b3ed51a 100644 --- a/examples/webengine/quicknanobrowser/doc/src/quicknanobrowser.qdoc +++ b/examples/webengine/quicknanobrowser/doc/src/quicknanobrowser.qdoc @@ -43,7 +43,7 @@ screen mode by using a toolbar button. They can leave fullscreen mode by using a keyboard shortcut. Additional toolbar buttons enable moving backwards and forwards in the browser history, reloading tab content, and opening a settings menu for enabling the following features: - JavaScript, plugins, fullscreen mode, off the record, HTTP disc cache, autoloading images, and + JavaScript, plugins, fullscreen mode, off the record, HTTP disk cache, autoloading images, and ignoring certificate errors. \include examples-run.qdocinc diff --git a/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc b/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc index aa94b17da..66a1252dc 100644 --- a/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc +++ b/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc @@ -36,7 +36,7 @@ \e{Content Manipulation} shows how to use JQuery with \l {Qt WebEngine Widgets} to create a web browser with special effects and content manipulation. - In the application, we call QWebEnginePage::runJavaScript() to + In the application, we call \l {QWebEnginePage::runJavaScript()} to execute jQuery JavaScript code. We implement a QMainWindow with a QWebEngineView as a central widget to build up the browser itself. @@ -51,7 +51,7 @@ \skipto class MainWindow : \printuntil /^\}/ - We also declare a QString that contains the jQuery, a QWebEngineView + We also declare a QString that contains jQuery, a QWebEngineView that displays the web content, and a QLineEdit that acts as the address bar. @@ -74,9 +74,9 @@ The second part of the constructor creates a QWebEngineView and connects slots to the view's signals: - \printuntil SLOT(finishLoading + \printuntil MainWindow::finishLoading - Furthermore, we create a QLineEdit as the browser's address bar. We then set the horizontal + Furthermore, we create a QLineEdit as the browser's address bar. We then set the vertical QSizePolicy to fill the available area in the browser at all times. We add the QLineEdit to a QToolBar together with a set of navigation actions from QWebEngineView::pageAction(): @@ -136,10 +136,6 @@ \printuntil } \printuntil } - We append \c undefined after the jQuery call to prevent a possible recursion loop - and crash caused by the way the elements returned by the each iterator elements - reference each other, which causes problems upon converting them to QVariant. - The \c rotateImages() function rotates the images on the current web page. This JavaScript code relies on CSS transforms. It looks up all \e {img} elements and rotates the images 180 degrees diff --git a/examples/webenginewidgets/contentmanipulation/mainwindow.cpp b/examples/webenginewidgets/contentmanipulation/mainwindow.cpp index 74d647c69..154a37747 100644 --- a/examples/webenginewidgets/contentmanipulation/mainwindow.cpp +++ b/examples/webenginewidgets/contentmanipulation/mainwindow.cpp @@ -52,22 +52,6 @@ #include <QtWebEngineWidgets> #include "mainwindow.h" -template<typename Arg, typename R, typename C> -struct InvokeWrapper { - R *receiver; - void (C::*memberFun)(Arg); - void operator()(Arg result) { - (receiver->*memberFun)(result); - } -}; - -template<typename Arg, typename R, typename C> -InvokeWrapper<Arg, R, C> invoke(R *receiver, void (C::*memberFun)(Arg)) -{ - InvokeWrapper<Arg, R, C> wrapper = {receiver, memberFun}; - return wrapper; -} - MainWindow::MainWindow(const QUrl& url) { setAttribute(Qt::WA_DeleteOnClose, true); @@ -82,14 +66,14 @@ MainWindow::MainWindow(const QUrl& url) view = new QWebEngineView(this); view->load(url); - connect(view, SIGNAL(loadFinished(bool)), SLOT(adjustLocation())); - connect(view, SIGNAL(titleChanged(QString)), SLOT(adjustTitle())); - connect(view, SIGNAL(loadProgress(int)), SLOT(setProgress(int))); - connect(view, SIGNAL(loadFinished(bool)), SLOT(finishLoading(bool))); + connect(view, &QWebEngineView::loadFinished, this, &MainWindow::adjustLocation); + connect(view, &QWebEngineView::titleChanged, this, &MainWindow::adjustTitle); + connect(view, &QWebEngineView::loadProgress, this, &MainWindow::setProgress); + connect(view, &QWebEngineView::loadFinished, this, &MainWindow::finishLoading); locationEdit = new QLineEdit(this); locationEdit->setSizePolicy(QSizePolicy::Expanding, locationEdit->sizePolicy().verticalPolicy()); - connect(locationEdit, SIGNAL(returnPressed()), SLOT(changeLocation())); + connect(locationEdit, &QLineEdit::returnPressed, this, &MainWindow::changeLocation); QToolBar *toolBar = addToolBar(tr("Navigation")); toolBar->addAction(view->pageAction(QWebEnginePage::Back)); @@ -99,38 +83,40 @@ MainWindow::MainWindow(const QUrl& url) toolBar->addWidget(locationEdit); QMenu *viewMenu = menuBar()->addMenu(tr("&View")); - QAction* viewSourceAction = new QAction("Page Source", this); - connect(viewSourceAction, SIGNAL(triggered()), SLOT(viewSource())); + QAction *viewSourceAction = new QAction(tr("Page Source"), this); + connect(viewSourceAction, &QAction::triggered, this, &MainWindow::viewSource); viewMenu->addAction(viewSourceAction); QMenu *effectMenu = menuBar()->addMenu(tr("&Effect")); - effectMenu->addAction("Highlight all links", this, SLOT(highlightAllLinks())); + effectMenu->addAction(tr("Highlight all links"), this, &MainWindow::highlightAllLinks); rotateAction = new QAction(this); rotateAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView)); rotateAction->setCheckable(true); rotateAction->setText(tr("Turn images upside down")); - connect(rotateAction, SIGNAL(toggled(bool)), this, SLOT(rotateImages(bool))); + connect(rotateAction, &QAction::toggled, this, &MainWindow::rotateImages); effectMenu->addAction(rotateAction); QMenu *toolsMenu = menuBar()->addMenu(tr("&Tools")); - toolsMenu->addAction(tr("Remove GIF images"), this, SLOT(removeGifImages())); - toolsMenu->addAction(tr("Remove all inline frames"), this, SLOT(removeInlineFrames())); - toolsMenu->addAction(tr("Remove all object elements"), this, SLOT(removeObjectElements())); - toolsMenu->addAction(tr("Remove all embedded elements"), this, SLOT(removeEmbeddedElements())); + toolsMenu->addAction(tr("Remove GIF images"), this, &MainWindow::removeGifImages); + toolsMenu->addAction(tr("Remove all inline frames"), this, &MainWindow::removeInlineFrames); + toolsMenu->addAction(tr("Remove all object elements"), this, &MainWindow::removeObjectElements); + toolsMenu->addAction(tr("Remove all embedded elements"), this, &MainWindow::removeEmbeddedElements); setCentralWidget(view); } void MainWindow::viewSource() { - QTextEdit* textEdit = new QTextEdit(NULL); + QTextEdit *textEdit = new QTextEdit(nullptr); textEdit->setAttribute(Qt::WA_DeleteOnClose); textEdit->adjustSize(); textEdit->move(this->geometry().center() - textEdit->rect().center()); textEdit->show(); - view->page()->toHtml(invoke(textEdit, &QTextEdit::setPlainText)); + view->page()->toHtml([textEdit](const QString &html){ + textEdit->setPlainText(html); + }); } void MainWindow::adjustLocation() @@ -150,7 +136,7 @@ void MainWindow::adjustTitle() if (progress <= 0 || progress >= 100) setWindowTitle(view->title()); else - setWindowTitle(QString("%1 (%2%)").arg(view->title()).arg(progress)); + setWindowTitle(QStringLiteral("%1 (%2%)").arg(view->title()).arg(progress)); } void MainWindow::setProgress(int p) @@ -170,7 +156,7 @@ void MainWindow::finishLoading(bool) void MainWindow::highlightAllLinks() { - QString code = "qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } ); undefined"; + QString code = QStringLiteral("qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } )"); view->page()->runJavaScript(code); } @@ -179,32 +165,32 @@ void MainWindow::rotateImages(bool invert) QString code; if (invert) - code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('-webkit-transition', '-webkit-transform 2s'); qt.jQuery(this).css('-webkit-transform', 'rotate(180deg)') } ); undefined"; + code = QStringLiteral("qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(180deg)') } )"); else - code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('-webkit-transition', '-webkit-transform 2s'); qt.jQuery(this).css('-webkit-transform', 'rotate(0deg)') } ); undefined"; + code = QStringLiteral("qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(0deg)') } )"); view->page()->runJavaScript(code); } void MainWindow::removeGifImages() { - QString code = "qt.jQuery('[src*=gif]').remove()"; + QString code = QStringLiteral("qt.jQuery('[src*=gif]').remove()"); view->page()->runJavaScript(code); } void MainWindow::removeInlineFrames() { - QString code = "qt.jQuery('iframe').remove()"; + QString code = QStringLiteral("qt.jQuery('iframe').remove()"); view->page()->runJavaScript(code); } void MainWindow::removeObjectElements() { - QString code = "qt.jQuery('object').remove()"; + QString code = QStringLiteral("qt.jQuery('object').remove()"); view->page()->runJavaScript(code); } void MainWindow::removeEmbeddedElements() { - QString code = "qt.jQuery('embed').remove()"; + QString code = QStringLiteral("qt.jQuery('embed').remove()"); view->page()->runJavaScript(code); } diff --git a/examples/webenginewidgets/demobrowser/browserapplication.cpp b/examples/webenginewidgets/demobrowser/browserapplication.cpp index 32429a675..c3f3ef9b9 100644 --- a/examples/webenginewidgets/demobrowser/browserapplication.cpp +++ b/examples/webenginewidgets/demobrowser/browserapplication.cpp @@ -314,7 +314,9 @@ void BrowserApplication::loadSettings() settings.endGroup(); settings.beginGroup(QLatin1String("cookies")); - QWebEngineProfile::PersistentCookiesPolicy persistentCookiesPolicy = QWebEngineProfile::PersistentCookiesPolicy(settings.value(QLatin1String("persistentCookiesPolicy")).toInt()); + QWebEngineProfile::PersistentCookiesPolicy persistentCookiesPolicy = + QWebEngineProfile::PersistentCookiesPolicy(settings.value(QLatin1String("persistentCookiesPolicy"), + QWebEngineProfile::AllowPersistentCookies).toInt()); defaultProfile->setPersistentCookiesPolicy(persistentCookiesPolicy); QString pdataPath = settings.value(QLatin1String("persistentDataPath")).toString(); defaultProfile->setPersistentStoragePath(pdataPath); diff --git a/examples/webenginewidgets/demobrowser/browsermainwindow.cpp b/examples/webenginewidgets/demobrowser/browsermainwindow.cpp index 327d7a9d3..14d49f7f3 100644 --- a/examples/webenginewidgets/demobrowser/browsermainwindow.cpp +++ b/examples/webenginewidgets/demobrowser/browsermainwindow.cpp @@ -109,9 +109,7 @@ BrowserMainWindow::BrowserMainWindow(QWidget *parent, Qt::WindowFlags flags) , m_historyForward(0) , m_stop(0) , m_reload(0) -#ifndef QT_NO_PRINTER , m_currentPrinter(nullptr) -#endif { setToolButtonStyle(Qt::ToolButtonFollowStyle); setAttribute(Qt::WA_DeleteOnClose, true); @@ -312,9 +310,7 @@ void BrowserMainWindow::setupMenu() #if defined(QWEBENGINEPAGE_PRINT) fileMenu->addAction(tr("P&rint Preview..."), this, SLOT(slotFilePrintPreview())); #endif -#ifndef QT_NO_PRINTER fileMenu->addAction(tr("&Print..."), this, SLOT(slotFilePrint()), QKeySequence::Print); -#endif fileMenu->addAction(tr("&Print to PDF..."), this, SLOT(slotFilePrintToPDF())); fileMenu->addSeparator(); @@ -702,23 +698,19 @@ void BrowserMainWindow::slotFileOpen() void BrowserMainWindow::slotFilePrintPreview() { -#ifndef QT_NO_PRINTPREVIEWDIALOG if (!currentTab()) return; QPrintPreviewDialog *dialog = new QPrintPreviewDialog(this); connect(dialog, SIGNAL(paintRequested(QPrinter*)), currentTab(), SLOT(print(QPrinter*))); dialog->exec(); -#endif } void BrowserMainWindow::slotFilePrint() { -#ifndef QT_NO_PRINTER if (!currentTab()) return; printRequested(currentTab()->page()); -#endif } void BrowserMainWindow::slotHandlePdfPrinted(const QByteArray& result) @@ -751,7 +743,6 @@ void BrowserMainWindow::slotFilePrintToPDF() currentTab()->page()->printToPdf(invoke(this, &BrowserMainWindow::slotHandlePdfPrinted), dialog->pageLayout()); } -#ifndef QT_NO_PRINTER void BrowserMainWindow::slotHandlePagePrinted(bool result) { Q_UNUSED(result); @@ -763,7 +754,6 @@ void BrowserMainWindow::slotHandlePagePrinted(bool result) void BrowserMainWindow::printRequested(QWebEnginePage *page) { -#ifndef QT_NO_PRINTDIALOG if (m_currentPrinter) return; m_currentPrinter = new QPrinter(); @@ -774,9 +764,7 @@ void BrowserMainWindow::printRequested(QWebEnginePage *page) return; } page->print(m_currentPrinter, invoke(this, &BrowserMainWindow::slotHandlePagePrinted)); -#endif } -#endif void BrowserMainWindow::slotPrivateBrowsing() { diff --git a/examples/webenginewidgets/demobrowser/browsermainwindow.h b/examples/webenginewidgets/demobrowser/browsermainwindow.h index 91e1c1d2f..5bbbb2924 100644 --- a/examples/webenginewidgets/demobrowser/browsermainwindow.h +++ b/examples/webenginewidgets/demobrowser/browsermainwindow.h @@ -56,9 +56,7 @@ #include <QtCore/QUrl> QT_BEGIN_NAMESPACE -#ifndef QT_NO_PRINTER class QPrinter; -#endif class QWebEnginePage; QT_END_NAMESPACE @@ -142,10 +140,8 @@ private slots: void slotSwapFocus(); void slotHandlePdfPrinted(const QByteArray&); -#ifndef QT_NO_PRINTER void slotHandlePagePrinted(bool result); void printRequested(QWebEnginePage *page); -#endif void geometryChangeRequested(const QRect &geometry); void updateToolbarActionText(bool visible); void updateBookmarksToolbarActionText(bool visible); @@ -180,9 +176,7 @@ private: QAction *m_restoreLastSession; QAction *m_addBookmark; -#ifndef QT_NO_PRINTER QPrinter *m_currentPrinter; -#endif QIcon m_reloadIcon; QIcon m_stopIcon; diff --git a/examples/webenginewidgets/demobrowser/printtopdfdialog.cpp b/examples/webenginewidgets/demobrowser/printtopdfdialog.cpp index 0f3b1765e..50a8bb91a 100644 --- a/examples/webenginewidgets/demobrowser/printtopdfdialog.cpp +++ b/examples/webenginewidgets/demobrowser/printtopdfdialog.cpp @@ -52,10 +52,8 @@ #include "ui_printtopdfdialog.h" #include <QtCore/QDir> -#ifndef QT_NO_PRINTER #include <QtPrintSupport/QPageSetupDialog> #include <QtPrintSupport/QPrinter> -#endif // QT_NO_PRINTER #include <QtWidgets/QFileDialog> PrintToPdfDialog::PrintToPdfDialog(const QString &filePath, QWidget *parent) : @@ -66,11 +64,8 @@ PrintToPdfDialog::PrintToPdfDialog(const QString &filePath, QWidget *parent) : ui->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); connect(ui->chooseFilePathButton, &QToolButton::clicked, this, &PrintToPdfDialog::onChooseFilePathButtonClicked); -#ifndef QT_NO_PRINTER connect(ui->choosePageLayoutButton, &QToolButton::clicked, this, &PrintToPdfDialog::onChoosePageLayoutButtonClicked); -#else ui->choosePageLayoutButton->hide(); -#endif // QT_NO_PRINTER updatePageLayoutLabel(); setFilePath(filePath); } @@ -82,7 +77,6 @@ PrintToPdfDialog::~PrintToPdfDialog() void PrintToPdfDialog::onChoosePageLayoutButtonClicked() { -#ifndef QT_NO_PRINTER QPrinter printer; printer.setPageLayout(currentPageLayout); @@ -92,7 +86,6 @@ void PrintToPdfDialog::onChoosePageLayoutButtonClicked() currentPageLayout.setPageSize(printer.pageLayout().pageSize()); currentPageLayout.setOrientation(printer.pageLayout().orientation()); updatePageLayoutLabel(); -#endif // QT_NO_PRINTER } void PrintToPdfDialog::onChooseFilePathButtonClicked() diff --git a/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc b/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc index 0239c1065..a20dc04c5 100644 --- a/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc +++ b/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc @@ -139,7 +139,7 @@ \printto defaultTextFile - The menu items are connected to the mapping member slots. The + The menu items are connected to the corresponding member slots. The \uicontrol Save item is activated or deactivated depending on whether the user has edited the content. diff --git a/mkspecs/features/configure.prf b/mkspecs/features/configure.prf index a07171b3e..6de9efe93 100644 --- a/mkspecs/features/configure.prf +++ b/mkspecs/features/configure.prf @@ -146,10 +146,6 @@ defineTest(runConfigure) { cache(WEBENGINE_CONFIG, add, $$list($$WEBENGINE_CONFIG)) export(WEBENGINE_CONFIG) } - # Set a global WEBENGINE_ARCH for the target architecture we can also read from option(host_build) - WEBENGINE_ARCH = $$QT_ARCH - cache(WEBENGINE_ARCH) - export(WEBENGINE_ARCH) } unix:!darwin { diff --git a/mkspecs/features/functions.prf b/mkspecs/features/functions.prf index 8dd21f410..56894e58a 100644 --- a/mkspecs/features/functions.prf +++ b/mkspecs/features/functions.prf @@ -16,7 +16,7 @@ defineTest(isQtMinimum) { defineTest(isPlatformSupported) { QT_FOR_CONFIG += gui-private linux { - !gcc:!clang { + if(!gcc:!clang)|intel_icc { skipBuild("Qt WebEngine on Linux requires clang or GCC.") return(false) } @@ -29,6 +29,10 @@ defineTest(isPlatformSupported) { isBuildingOnWin32() { skipBuild("Qt WebEngine on Windows must be built on a 64-bit machine.") } + !msvc|intel_icl { + skipBuild("Qt WebEngine on Windows requires MSVC.") + return(false) + } !isMinWinSDKVersion(10, 10586): { skipBuild("Qt WebEngine on Windows requires a Windows SDK version 10.0.10586 or newer.") return(false) @@ -38,6 +42,10 @@ defineTest(isPlatformSupported) { skipBuild("Using XCode version $$QMAKE_XCODE_VERSION, but at least version 5.1 is required to build Qt WebEngine.") return(false) } + !clang|intel_icc { + skipBuild("Qt WebEngine on macOS requires Clang.") + return(false) + } # We require OS X 10.0 (darwin version 14.0.0) or newer darwin_major_version = $$section(QMAKE_HOST.version, ., 0, 0) lessThan(darwin_major_version, 14) { diff --git a/mkspecs/features/gn_generator.prf b/mkspecs/features/gn_generator.prf index 1f730acd0..b2b749154 100644 --- a/mkspecs/features/gn_generator.prf +++ b/mkspecs/features/gn_generator.prf @@ -186,8 +186,7 @@ for (flag, QMAKE_LFLAGS): GN_CONTENTS += " \"$$filter_flag_values($$flag)\"," for (flag, GN_FLAGS): GN_CONTENTS += " \"$$flag\"," !isEmpty(QMAKE_RPATHDIR) { for (rpath, QMAKE_RPATHDIR) { - macos: GN_CONTENTS += " \"-Wl,-rpath,$${rpath}\"," - else:unix: GN_CONTENTS += " \"-Wl,-rpath=$${rpath}\"," + unix:!macos: GN_CONTENTS += " \"-Wl,-rpath=$${rpath}\"," } } !isEmpty(QMAKE_RPATHLINKDIR): GN_CONTENTS += " \"-Wl,-rpath-link=$${QMAKE_RPATHLINKDIR}\"," diff --git a/src/3rdparty b/src/3rdparty -Subproject 4a23e0462a610f421d22fba38b0f9ba72120ae1 +Subproject 0e828760a46a39f26c7d9fd86654c363f4218be diff --git a/src/buildtools/configure_host.pro b/src/buildtools/configure_host.pro index fd27643ec..f1b3d47b0 100644 --- a/src/buildtools/configure_host.pro +++ b/src/buildtools/configure_host.pro @@ -4,8 +4,9 @@ TEMPLATE = aux # Pick up the host toolchain option(host_build) -GN_HOST_CPU = $$gnArch($$QMAKE_HOST.arch) -GN_TARGET_CPU = $$gnArch($$WEBENGINE_ARCH) +GN_HOST_CPU = $$gnArch($$QT_ARCH) +!isEmpty(QT_TARGET_ARCH): GN_TARGET_CPU = $$gnArch($$QT_TARGET_ARCH) +else: GN_TARGET_CPU = $$GN_HOST_CPU GN_OS = $$gnOS() clang: GN_CLANG = true @@ -15,11 +16,11 @@ use_gold_linker: GN_USE_GOLD=true else: GN_USE_GOLD=false GN_V8_HOST_CPU = $$GN_HOST_CPU -contains(GN_TARGET_CPU, "arm")|contains(GN_TARGET_CPU, "mips")|contains(GN_TARGET_CPU, "x86") { +contains(GN_TARGET_CPU, "arm")|contains(GN_TARGET_CPU, "mipsel")|contains(GN_TARGET_CPU, "x86") { # The v8 snapshot need a host that matches bitwidth, so we build makesnapshot to 32-bit variants of host. contains(GN_V8_HOST_CPU, x64): GN_V8_HOST_CPU = "x86" else: contains(GN_V8_HOST_CPU, arm64): GN_V8_HOST_CPU = "arm" - else: contains(GN_V8_HOST_CPU, mips64): GN_V8_HOST_CPU = "mips" + else: contains(GN_V8_HOST_CPU, mips64el): GN_V8_HOST_CPU = "mipsel" } # We always use the gcc_toolchain, because clang_toolchain is just diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro index 22c165e2a..d3d47e03a 100644 --- a/src/core/api/core_api.pro +++ b/src/core/api/core_api.pro @@ -53,11 +53,3 @@ SOURCES = \ unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static { SOURCES += qtbug-60565.cpp } - -msvc { - # Create a list of object files that can be used as response file for the linker. - # This is done to simulate -whole-archive on MSVC. - QMAKE_POST_LINK = \ - "if exist $(DESTDIR_TARGET).objects del $(DESTDIR_TARGET).objects$$escape_expand(\\n\\t)" \ - "for %%a in ($(OBJECTS)) do echo $$shell_quote($$shell_path($$OUT_PWD))\\%%a >> $(DESTDIR_TARGET).objects" -} diff --git a/src/core/api/qtbug-60565.cpp b/src/core/api/qtbug-60565.cpp index 21b545cca..be601b7e4 100644 --- a/src/core/api/qtbug-60565.cpp +++ b/src/core/api/qtbug-60565.cpp @@ -47,6 +47,7 @@ #endif #define SHIM_ALIAS_SYMBOL(fn) __attribute__((weak, alias(#fn))) +#define SHIM_HIDDEN __attribute__ ((visibility ("hidden"))) extern "C" { @@ -87,19 +88,19 @@ static void* __shimCppNewArray(size_t size); static void __shimCppDelete(void *address); static void __shimCppDeleteArray(void *address); -static void* ShimCppNew(size_t size) { +SHIM_HIDDEN void* ShimCppNew(size_t size) { return __shimCppNew(size); } -static void* ShimCppNewArray(size_t size) { +SHIM_HIDDEN void* ShimCppNewArray(size_t size) { return __shimCppNewArray(size); } -static void ShimCppDelete(void* address) { +SHIM_HIDDEN void ShimCppDelete(void* address) { __shimCppDelete(address); } -static void ShimCppDeleteArray(void* address) { +SHIM_HIDDEN void ShimCppDeleteArray(void* address) { __shimCppDeleteArray(address); } } // extern "C" diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 133006d70..ffee001ff 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -63,8 +63,9 @@ #include "components/prefs/pref_registry_simple.h" #include "components/user_prefs/user_prefs.h" #if BUILDFLAG(ENABLE_SPELLCHECK) -#include "chrome/common/pref_names.h" #include "chrome/browser/spellchecker/spellcheck_service.h" +#include "chrome/common/pref_names.h" +#include "components/spellcheck/browser/pref_names.h" #endif namespace QtWebEngineCore { @@ -80,12 +81,11 @@ BrowserContextQt::BrowserContextQt(BrowserContextAdapter *adapter) #if BUILDFLAG(ENABLE_SPELLCHECK) // Initial spellcheck settings - registry->RegisterListPref(prefs::kSpellCheckDictionaries, new base::ListValue()); registry->RegisterStringPref(prefs::kAcceptLanguages, std::string()); - registry->RegisterStringPref(prefs::kSpellCheckDictionary, std::string()); - registry->RegisterBooleanPref(prefs::kSpellCheckUseSpellingService, false); - registry->RegisterBooleanPref(prefs::kEnableContinuousSpellcheck, false); - registry->RegisterBooleanPref(prefs::kEnableAutoSpellCorrect, false); + registry->RegisterListPref(spellcheck::prefs::kSpellCheckDictionaries, new base::ListValue()); + registry->RegisterStringPref(spellcheck::prefs::kSpellCheckDictionary, std::string()); + registry->RegisterBooleanPref(spellcheck::prefs::kEnableSpellcheck, false); + registry->RegisterBooleanPref(spellcheck::prefs::kSpellCheckUseSpellingService, false); #endif //ENABLE_SPELLCHECK m_prefService = factory.Create(std::move(registry.get())); user_prefs::UserPrefs::Set(this, m_prefService.get()); @@ -216,7 +216,7 @@ void BrowserContextQt::failedToLoadDictionary(const std::string &language) void BrowserContextQt::setSpellCheckLanguages(const QStringList &languages) { StringListPrefMember dictionaries_pref; - dictionaries_pref.Init(prefs::kSpellCheckDictionaries, m_prefService.get()); + dictionaries_pref.Init(spellcheck::prefs::kSpellCheckDictionaries, m_prefService.get()); std::vector<std::string> dictionaries; dictionaries.reserve(languages.size()); for (const auto &language : languages) @@ -227,7 +227,7 @@ void BrowserContextQt::setSpellCheckLanguages(const QStringList &languages) QStringList BrowserContextQt::spellCheckLanguages() const { QStringList spellcheck_dictionaries; - for (const auto &value : *m_prefService->GetList(prefs::kSpellCheckDictionaries)) { + for (const auto &value : *m_prefService->GetList(spellcheck::prefs::kSpellCheckDictionaries)) { std::string dictionary; if (value->GetAsString(&dictionary)) spellcheck_dictionaries.append(QString::fromStdString(dictionary)); @@ -238,12 +238,12 @@ QStringList BrowserContextQt::spellCheckLanguages() const void BrowserContextQt::setSpellCheckEnabled(bool enabled) { - m_prefService->SetBoolean(prefs::kEnableContinuousSpellcheck, enabled); + m_prefService->SetBoolean(spellcheck::prefs::kEnableSpellcheck, enabled); } bool BrowserContextQt::isSpellCheckEnabled() const { - return m_prefService->GetBoolean(prefs::kEnableContinuousSpellcheck); + return m_prefService->GetBoolean(spellcheck::prefs::kEnableSpellcheck); } #endif //ENABLE_SPELLCHECK } // namespace QtWebEngineCore diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index 24951cd07..60cfa6857 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -98,17 +98,18 @@ contains(QT_ARCH, "mips"):!host_build { host_build { gn_args += custom_toolchain=\"$$QTWEBENGINE_OUT_ROOT/src/toolchain:host\" + GN_HOST_CPU = $$gnArch($$QT_ARCH) + gn_args += host_cpu=\"$$GN_HOST_CPU\" # Don't bother trying to use system libraries in this case gn_args += use_glib=false gn_args += use_system_libffi=false } else { gn_args += custom_toolchain=\"$$QTWEBENGINE_OUT_ROOT/src/toolchain:target\" + gn_args += host_toolchain=\"$$QTWEBENGINE_OUT_ROOT/src/toolchain:host\" cross_compile { - gn_args += host_toolchain=\"$$QTWEBENGINE_OUT_ROOT/src/toolchain:host\" gn_args += v8_snapshot_toolchain=\"$$QTWEBENGINE_OUT_ROOT/src/toolchain:v8_snapshot\" - GN_HOST_CPU = $$gnArch($$QMAKE_HOST.arch) GN_TARGET_CPU = $$gnArch($$QT_ARCH) - gn_args += host_cpu=\"$$GN_HOST_CPU\" target_cpu=\"$$GN_TARGET_CPU\" + gn_args += target_cpu=\"$$GN_TARGET_CPU\" } !contains(QT_CONFIG, no-pkg-config) { # Strip '>2 /dev/null' from $$pkgConfigExecutable() diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index 49c725475..f5dd4a9d3 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -36,10 +36,8 @@ defineTest(usingMSVC32BitCrossCompiler) { msvc:contains(QT_ARCH, "i386"):!usingMSVC32BitCrossCompiler() { # The 32 bit MSVC linker runs out of memory if we do not remove all debug information. - gn_args += symbol_level=0 -} else { - # Chromium builds with debug info in release by default but Qt doesn't - CONFIG(release, debug|release):!force_debug_info: gn_args += symbol_level=1 + force_debug_info: gn_args -= symbol_level=1 + gn_args *= symbol_level=0 } msvc { @@ -55,10 +53,11 @@ msvc { SDK_PATH = $$(WINDOWSSDKDIR) VS_PATH= $$(VSINSTALLDIR) - gn_args += visual_studio_path=$$shell_quote($$VS_PATH) - gn_args += windows_sdk_path=$$shell_quote($$SDK_PATH) + gn_args += visual_studio_path=\"$$clean_path($$VS_PATH)\" + gn_args += windows_sdk_path=\"$$clean_path($$SDK_PATH)\" - contains(QT_ARCH, "i386"): gn_args += target_cpu=\"x86\" + GN_TARGET_CPU = $$gnArch($$QT_ARCH) + gn_args += target_cpu=\"$$GN_TARGET_CPU\" } else { fatal("Qt WebEngine for Windows can only be built with the Microsoft Visual Studio C++ compiler") diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 38f66d641..8284029a0 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -139,10 +139,15 @@ content::ContentRendererClient *ContentMainDelegateQt::CreateContentRendererClie { #if defined(OS_LINUX) base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess(); - - if (parsedCommandLine->HasSwitch(switches::kLang)) { - const std::string &locale = parsedCommandLine->GetSwitchValueASCII(switches::kLang); - ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); + std::string process_type = parsedCommandLine->GetSwitchValueASCII(switches::kProcessType); + bool no_sandbox = parsedCommandLine->HasSwitch(switches::kNoSandbox); + + // Reload locale if the renderer process is sandboxed + if (process_type == switches::kRendererProcess && !no_sandbox) { + if (parsedCommandLine->HasSwitch(switches::kLang)) { + const std::string &locale = parsedCommandLine->GetSwitchValueASCII(switches::kLang); + ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); + } } #endif diff --git a/src/core/core.pro b/src/core/core.pro index 6cc8080e0..9709e62c3 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -17,23 +17,6 @@ core_generator.depends = core_headers # core_gn_generator.pro is a dummy .pro file that is used by qmake # to generate our main BUILD.gn file -core_icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat -core_icu.path = $$[QT_INSTALL_DATA]/resources -core_icu.CONFIG += no_check_exist - -core_locales.files = $$OUT_PWD/$$getConfigDir()/qtwebengine_locales/*.pak -core_locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales -core_locales.CONFIG += no_check_exist - -core_resources.files = \ - $$OUT_PWD/$$getConfigDir()/qtwebengine_resources.pak \ - $$OUT_PWD/$$getConfigDir()/qtwebengine_resources_100p.pak \ - $$OUT_PWD/$$getConfigDir()/qtwebengine_resources_200p.pak \ - $$OUT_PWD/$$getConfigDir()/qtwebengine_devtools_resources.pak -core_resources.path = $$[QT_INSTALL_DATA]/resources -core_resources.CONFIG += no_check_exist -INSTALLS += core_resources core_locales core_icu - gn_run.file = gn_run.pro gn_run.depends = core_generator diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 44e8ac613..3785ddc46 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -47,10 +47,8 @@ CONFIG *= no_smart_library_merge osx { LIBS_PRIVATE += -Wl,-force_load,$${api_library_path}$${QMAKE_DIR_SEP}lib$${api_library_name}.a } else:msvc { - # Simulate -whole-archive by passing the list of object files that belong to the public - # API library as response file to the linker. QMAKE_LFLAGS += /OPT:REF - QMAKE_LFLAGS += @$${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib.objects + QMAKE_LFLAGS += /WHOLEARCHIVE:$${api_library_path}$${QMAKE_DIR_SEP}$${api_library_name}.lib } else { LIBS_PRIVATE += -Wl,-whole-archive -l$$api_library_name -Wl,-no-whole-archive } diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp index b3c42aa08..8bdbaadd2 100644 --- a/src/core/media_capture_devices_dispatcher.cpp +++ b/src/core/media_capture_devices_dispatcher.cpp @@ -62,8 +62,14 @@ #include "content/public/common/media_stream_request.h" #include "media/audio/audio_device_description.h" #include "media/audio/audio_manager_base.h" +#include "media/media_features.h" #include "ui/base/l10n/l10n_util.h" +#if BUILDFLAG(ENABLE_WEBRTC) +#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" +#endif + #include <QtCore/qcoreapplication.h> namespace QtWebEngineCore { @@ -330,10 +336,38 @@ void MediaCaptureDevicesDispatcher::handleScreenCaptureAccessRequest(content::We { content::MediaStreamDevices devices; std::unique_ptr<content::MediaStreamUI> ui; +#if BUILDFLAG(ENABLE_WEBRTC) if (userAccepted) { - content::DesktopMediaID screenId = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0); + // Source id patterns are different across platforms. + // On Linux, the hardcoded value "0" is used. + // On Windows, the screens are enumerated consecutively in increasing order from 0. + // On macOS the source ids are randomish numbers assigned by the OS. + webrtc::DesktopCapturer::SourceId id = 0; + + // In order to provide a correct screen id, we query for the available screen ids, and + // select the first one as the main display id. + // The code is based on the file + // src/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc. + webrtc::DesktopCaptureOptions options = + webrtc::DesktopCaptureOptions::CreateDefault(); + options.set_disable_effects(false); + std::unique_ptr<webrtc::DesktopCapturer> screen_capturer( + webrtc::DesktopCapturer::CreateScreenCapturer(options)); + + if (screen_capturer) { + webrtc::DesktopCapturer::SourceList screens; + if (screen_capturer->GetSourceList(&screens)) { + if (screens.size() > 0) { + id = screens[0].id; + } + } + } + + content::DesktopMediaID screenId = content::DesktopMediaID( + content::DesktopMediaID::TYPE_SCREEN, id); ui = getDevicesForDesktopCapture(&devices, screenId, false/*capture_audio*/, false/*display_notification*/, getContentsUrl(webContents)); } +#endif std::map<content::WebContents*, RequestsQueue>::iterator it = m_pendingRequests.find(webContents); if (it == m_pendingRequests.end()) { diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni index de1fa1836..c9f766a36 100644 --- a/src/core/qtwebengine.gni +++ b/src/core/qtwebengine.gni @@ -1,3 +1,4 @@ +import("//media/media_options.gni") import("//third_party/widevine/cdm/widevine.gni") chromium_version = exec_script("//build/util/version.py", [ "-f", rebase_path("//chrome/VERSION"), @@ -18,10 +19,12 @@ deps = [ "//components/visitedlink/renderer", "//components/web_cache/browser", "//components/web_cache/renderer", + "//components/spellcheck:build_features", "//content/public/app:browser", "//content/public/browser", "//content/public/common", "//content/public/renderer", + "//media:media_features", "//net:net_browser_services", "//net:net_with_v8", "//skia", @@ -36,6 +39,10 @@ if (enable_widevine) { deps += [ "//components/cdm/renderer"] } +if (enable_webrtc) { + deps += [ "//third_party/webrtc/base:base" ] +} + if (is_linux && !is_desktop_linux) { deps += [ "//ui/events/ozone:events_ozone_evdev"] } diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 3d51d4108..4e98a1016 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -942,10 +942,17 @@ QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) case Qt::ImFont: // TODO: Implement this return QVariant(); - case Qt::ImCursorRectangle: - if (!text_input_manager_ || !text_input_manager_->GetActiveWidget()) - return QVariant(); - return toQt(text_input_manager_->GetSelectionRegion()->caret_rect); + case Qt::ImCursorRectangle: { + if (text_input_manager_) { + if (auto *region = text_input_manager_->GetSelectionRegion()) { + gfx::Rect caretRect = gfx::RectBetweenSelectionBounds(region->anchor, region->focus); + if (caretRect.width() == 0) + caretRect.set_width(1); // IME API on Windows expects a width > 0 + return toQt(caretRect); + } + } + return QVariant(); + } case Qt::ImCursorPosition: return m_cursorPosition; case Qt::ImAnchorPosition: @@ -1253,7 +1260,6 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) // to the same focused object, and cancelling the composition on the next event loop tick. if (!m_receivedEmptyImeText && m_imeInProgress && !hasSelection) { m_receivedEmptyImeText = true; - m_imeInProgress = false; QInputMethodEvent *eventCopy = new QInputMethodEvent(*ev); QGuiApplication::postEvent(qApp->focusObject(), eventCopy); } else { diff --git a/src/core/resource_bundle_qt.cpp b/src/core/resource_bundle_qt.cpp index 52355e996..c37854ea6 100644 --- a/src/core/resource_bundle_qt.cpp +++ b/src/core/resource_bundle_qt.cpp @@ -75,7 +75,8 @@ bool ResourceBundle::LocaleDataPakExists(const std::string& locale) #if defined(OS_LINUX) base::CommandLine *parsed_command_line = base::CommandLine::ForCurrentProcess(); std::string process_type = parsed_command_line->GetSwitchValueASCII(switches::kProcessType); - if (process_type == switches::kRendererProcess) { + bool no_sandbox = parsed_command_line->HasSwitch(switches::kNoSandbox); + if (process_type == switches::kRendererProcess && !no_sandbox) { // The Renderer Process is sandboxed thus only one locale is available in it. // The particular one is passed by the --lang command line option. if (!parsed_command_line->HasSwitch(switches::kLang) || parsed_command_line->GetSwitchValueASCII(switches::kLang) != locale) diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 9fc8add01..fe1758655 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -340,8 +340,7 @@ void URLRequestContextGetterQt::generateCookieStore() cookieMonster->SetCookieableSchemes(cookieableSchemes); m_cookieDelegate->setCookieMonster(cookieMonster); - if (!m_updateAllStorage) { - Q_ASSERT(m_updateHttpCache); + if (!m_updateAllStorage && m_updateHttpCache) { // HttpCache needs to be regenerated when we generate a new channel id service generateHttpCache(); } @@ -469,6 +468,9 @@ void URLRequestContextGetterQt::generateHttpCache() QMutexLocker lock(&m_mutex); m_updateHttpCache = false; + if (m_updateCookieStore) + generateCookieStore(); + net::HttpCache::DefaultBackend* main_backend = 0; switch (m_httpCacheType) { case BrowserContextAdapter::MemoryHttpCache: diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 270096553..399c036a4 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -402,6 +402,7 @@ void WebContentsAdapter::initialize(WebContentsAdapterClient *adapterClient) // We keep a reference to browserContextAdapter to keep it alive as long as we use it. // This is needed in case the QML WebEngineProfile is garbage collected before the WebEnginePage. d->browserContextAdapter = adapterClient->browserContextAdapter(); + Q_ASSERT(d->browserContextAdapter); // Create our own if a WebContents wasn't provided at construction. if (!d->webContents) @@ -1228,7 +1229,7 @@ static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeDat return; if (mimeData->hasHtml()) dropData->html = toNullableString16(mimeData->html()); - else if (mimeData->hasText()) + if (mimeData->hasText()) dropData->text = toNullableString16(mimeData->text()); } diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index ee7dbe1ce..8d75f24b7 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -339,7 +339,7 @@ public: virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) = 0; virtual void focusContainer() = 0; virtual void unhandledKeyEvent(QKeyEvent *event) = 0; - virtual void adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry) = 0; + virtual void adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry, const QUrl &targetUrl) = 0; virtual bool isBeingAdopted() = 0; virtual void close() = 0; virtual void windowCloseRejected() = 0; @@ -359,9 +359,7 @@ public: virtual void passOnFocus(bool reverse) = 0; // returns the last QObject (QWidget/QQuickItem) based object in the accessibility // hierarchy before going into the BrowserAccessibility tree -#ifndef QT_NO_ACCESSIBILITY virtual QObject *accessibilityParentObject() = 0; -#endif // QT_NO_ACCESSIBILITY virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) = 0; virtual void authenticationRequired(QSharedPointer<AuthenticationDialogController>) = 0; virtual void runGeolocationPermissionRequest(const QUrl &securityOrigin) = 0; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 5bcb83c6b..a6e1fb438 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -306,6 +306,11 @@ void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::Favic m_faviconManager->update(faviconCandidates); } +void WebContentsDelegateQt::WebContentsCreated(content::WebContents* /*source_contents*/, int /*opener_render_process_id*/, int /*opener_render_frame_id*/, const std::string& /*frame_name*/, const GURL& target_url, content::WebContents* new_contents) +{ + this->m_initialTargetUrl = toQt(target_url); +} + content::ColorChooser *WebContentsDelegateQt::OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<content::ColorSuggestion> &suggestion) { Q_UNUSED(suggestion); @@ -445,7 +450,7 @@ QWeakPointer<WebContentsAdapter> WebContentsDelegateQt::createWindow(content::We { QSharedPointer<WebContentsAdapter> newAdapter = QSharedPointer<WebContentsAdapter>::create(new_contents); - m_viewClient->adoptNewWindow(newAdapter, static_cast<WebContentsAdapterClient::WindowOpenDisposition>(disposition), user_gesture, toQt(initial_pos)); + m_viewClient->adoptNewWindow(newAdapter, static_cast<WebContentsAdapterClient::WindowOpenDisposition>(disposition), user_gesture, toQt(initial_pos), m_initialTargetUrl); // If the client didn't reference the adapter, it will be deleted now, and the weak pointer zeroed. return newAdapter; diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 5ae442bbc..84799c2cd 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -104,6 +104,7 @@ public: void LoadProgressChanged(content::WebContents* source, double progress) override; void HandleKeyboardEvent(content::WebContents *source, const content::NativeWebKeyboardEvent &event) override; content::ColorChooser *OpenColorChooser(content::WebContents *source, SkColor color, const std::vector<content::ColorSuggestion> &suggestion) override; + void WebContentsCreated(content::WebContents* source_contents, int opener_render_process_id, int opener_render_frame_id, const std::string& frame_name, const GURL& target_url, content::WebContents* new_contents) override; content::JavaScriptDialogManager *GetJavaScriptDialogManager(content::WebContents *source) override; void EnterFullscreenModeForTab(content::WebContents* web_contents, const GURL& origin) override; void ExitFullscreenModeForTab(content::WebContents*) override; @@ -156,6 +157,7 @@ private: QScopedPointer<FaviconManager> m_faviconManager; SavePageInfo m_savePageInfo; QSharedPointer<FilePickerController> m_filePickerController; + QUrl m_initialTargetUrl; }; } // namespace QtWebEngineCore diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index bf3ea955c..1fceb4366 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -591,7 +591,7 @@ void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event) q->window()->sendEvent(q->parentItem(), event); } -void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &) +void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &, const QUrl &targetUrl) { Q_Q(QQuickWebEngineView); QQuickWebEngineNewViewRequest request; @@ -599,8 +599,7 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(QSharedPointer<WebContentsAdapte // to start loading it and possibly return it to its parent page window.open(). request.m_adapter = newWebContents; request.m_isUserInitiated = userGesture; - if (newWebContents) - request.m_requestedUrl = newWebContents->requestedUrl(); + request.m_requestedUrl = targetUrl; switch (disposition) { case WebContentsAdapterClient::NewForegroundTabDisposition: @@ -716,13 +715,11 @@ void QQuickWebEngineViewPrivate::runMouseLockPermissionRequest(const QUrl &secur adapter->grantMouseLockPermission(false); } -#ifndef QT_NO_ACCESSIBILITY QObject *QQuickWebEngineViewPrivate::accessibilityParentObject() { Q_Q(QQuickWebEngineView); return q; } -#endif // QT_NO_ACCESSIBILITY QSharedPointer<BrowserContextAdapter> QQuickWebEngineViewPrivate::browserContextAdapter() { @@ -1102,9 +1099,10 @@ void QQuickWebEngineViewPrivate::didFindText(quint64 requestId, int matchCount) void QQuickWebEngineViewPrivate::didPrintPage(quint64 requestId, const QByteArray &result) { + Q_Q(QQuickWebEngineView); QJSValue callback = m_callbacks.take(requestId); QJSValueList args; - args.append(QJSValue(result.data())); + args.append(qmlEngine(q)->toScriptValue(result)); callback.call(args); } diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 2ecd70d78..19ecf5e1f 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -107,7 +107,7 @@ public: virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE; virtual void focusContainer() Q_DECL_OVERRIDE; virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE; - virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &) Q_DECL_OVERRIDE; + virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &, const QUrl &targetUrl) Q_DECL_OVERRIDE; virtual bool isBeingAdopted() Q_DECL_OVERRIDE; virtual void close() Q_DECL_OVERRIDE; virtual void windowCloseRejected() Q_DECL_OVERRIDE; @@ -129,9 +129,7 @@ public: virtual void authenticationRequired(QSharedPointer<QtWebEngineCore::AuthenticationDialogController>) Q_DECL_OVERRIDE; virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) Q_DECL_OVERRIDE; virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; -#ifndef QT_NO_ACCESSIBILITY virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; -#endif // QT_NO_ACCESSIBILITY virtual QtWebEngineCore::WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &errorController) Q_DECL_OVERRIDE; virtual void runGeolocationPermissionRequest(QUrl const&) Q_DECL_OVERRIDE; diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc index 2eeda6e8a..ec678672c 100644 --- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc @@ -69,7 +69,7 @@ \section2 Windows - On Windows, Visual Studio 2015 and Windows 10 SDK are required. + On Windows, Visual Studio 2015 or 2017 and Windows 10 SDK are required. \section2 Linux 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 86f3aaa64..a0ed00918 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -241,14 +241,8 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) { - if (event->type() == QEvent::ShortcutOverride) { - QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); - if (m_client->handleShortcutOverrideEvent(keyEvent)) - return true; - if (editorActionForKeyEvent(keyEvent) != QQuickWebEngineView::NoWebAction) - event->accept(); - return true; - } + if (event->type() == QEvent::ShortcutOverride) + return m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event)); if (event->type() == QEvent::NativeGesture) return m_client->forwardEvent(event); diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index ea0117b95..d0305f81a 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -81,11 +81,9 @@ #include <QMenu> #include <QMessageBox> #include <QMimeData> -#if defined(QT_PRINTSUPPORT_LIB) -#ifndef QT_NO_PRINTER +#ifdef ENABLE_PRINTING #include <QPrinter> -#endif //QT_NO_PRINTER -#endif //QT_PRINTSUPPORT_LIB +#endif #include <QStandardPaths> #include <QStyle> #include <QTimer> @@ -403,10 +401,11 @@ void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) QGuiApplication::sendEvent(view->parentWidget(), event); } -void QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) +void QWebEnginePagePrivate::adoptNewWindow(QSharedPointer<WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry, const QUrl &targetUrl) { Q_Q(QWebEnginePage); Q_UNUSED(userGesture); + Q_UNUSED(targetUrl); QWebEnginePage *newPage = q->createWindow(toWindowType(disposition)); if (!newPage) @@ -585,12 +584,10 @@ void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOr Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock); } -#ifndef QT_NO_ACCESSIBILITY QObject *QWebEnginePagePrivate::accessibilityParentObject() { return view; } -#endif // QT_NO_ACCESSIBILITY void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const { @@ -1969,7 +1966,7 @@ QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringLis break; // Chromium extension, not exposed as part of the public API for now. case FilePickerController::UploadFolder: - str = QFileDialog::getExistingDirectory(view(), tr("Select folder to upload")) + QLatin1Char('/'); + str = QFileDialog::getExistingDirectory(view(), tr("Select folder to upload")); if (!str.isNull()) ret << str; break; @@ -2126,8 +2123,6 @@ void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &res #endif // if defined(ENABLE_PDF) } -#if defined(QT_PRINTSUPPORT_LIB) -#ifndef QT_NO_PRINTER /*! \fn void QWebEnginePage::print(QPrinter *printer, FunctorOrLambda resultCallback) Renders the current content of the page into a temporary PDF document, then prints it using \a printer. @@ -2164,8 +2159,6 @@ void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback<bool> &re d->m_callbacks.invokeDirectly(resultCallback, false); #endif // if defined(ENABLE_PDF) } -#endif // if defined(QT_NO_PRINTER) -#endif // if defined(QT_PRINTSUPPORT_LIB) /*! \since 5.7 diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 37a59e88c..74ebd0a35 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -55,11 +55,7 @@ QT_BEGIN_NAMESPACE class QMenu; -#if defined(QT_PRINTSUPPORT_LIB) -#ifndef QT_NO_PRINTER class QPrinter; -#endif // QT_NO_PRINTER -#endif // QT_PRINTSUPPORT_LIB class QWebChannel; class QWebEngineContextMenuData; @@ -310,15 +306,11 @@ public: void printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF())); #endif -#if defined(QT_PRINTSUPPORT_LIB) -#ifndef QT_NO_PRINTER #ifdef Q_QDOC void print(QPrinter *printer, FunctorOrLambda resultCallback); #else void print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback); #endif // QDOC -#endif // QT_NO_PRINTER -#endif // QT_PRINTSUPPORT_LIB const QWebEngineContextMenuData &contextMenuData() const; diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index c7b805c45..ec84f05e1 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -100,7 +100,7 @@ public: virtual void loadFinished(bool success, const QUrl &url, bool isErrorPage = false, int errorCode = 0, const QString &errorDescription = QString()) Q_DECL_OVERRIDE; virtual void focusContainer() Q_DECL_OVERRIDE; virtual void unhandledKeyEvent(QKeyEvent *event) Q_DECL_OVERRIDE; - virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) Q_DECL_OVERRIDE; + virtual void adoptNewWindow(QSharedPointer<QtWebEngineCore::WebContentsAdapter> newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry, const QUrl &targetUrl) Q_DECL_OVERRIDE; void adoptNewWindowImpl(QWebEnginePage *newPage, const QSharedPointer<QtWebEngineCore::WebContentsAdapter> &newWebContents, const QRect &initialGeometry); @@ -126,9 +126,7 @@ public: virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) Q_DECL_OVERRIDE; virtual void runGeolocationPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; -#ifndef QT_NO_ACCESSIBILITY virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; -#endif // QT_NO_ACCESSIBILITY virtual QtWebEngineCore::WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; virtual void allowCertificateError(const QSharedPointer<CertificateErrorController> &controller) Q_DECL_OVERRIDE; virtual void showValidationMessage(const QRect &anchor, const QString &mainText, const QString &subText) Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index 4c8c4be33..6e24b4b51 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -124,9 +124,9 @@ QWebEngineSettings *QWebEngineSettings::globalSettings() #endif /*! - Returns the default settings for the web engine page. - - \sa globalSettings() + Returns the settings for a web engine page that belongs to the default + profile. All web pages not specifically created with another profile belong + to the default profile. */ QWebEngineSettings *QWebEngineSettings::defaultSettings() { diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc index bc841849e..26f3964da 100644 --- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc @@ -24,12 +24,9 @@ /*! \fn static QWebEngineSettings *QWebEngineSettings::globalSettings() - Returns the global settings object. + \obsolete - Any setting changed on the default object is automatically applied to all - QWebEnginePage instances where the particular setting is not overridden already. - - \sa defaultSettings() + Use defaultSettings() instead. */ /*! @@ -40,16 +37,15 @@ \inmodule QtWebEngineWidgets - Each QWebEnginePage object has its own QWebEngineSettings object, which configures the - settings for that page. If a setting is not configured, then it is looked - up in the global settings object, which can be accessed using - globalSettings(). - QWebEngineSettings allows configuration of browser properties, such as font sizes and families, the location of a custom style sheet, and generic attributes, such as JavaScript support. Individual attributes are set using the setAttribute() function. The \l{QWebEngineSettings::WebAttribute}{WebAttribute} enum further describes each attribute. + Each QWebEnginePage object has its own QWebEngineSettings object, which configures the + settings for that page. If a setting is not configured for a web engine + page, it is looked up in the settings of the profile the page belongs to. + \sa QWebEnginePage::settings(), QWebEngineView::settings() */ @@ -184,10 +180,8 @@ /*! \fn void QWebEngineSettings::resetFontSize(FontSize type) - Resets the font size for \a type to the size specified in the global - settings object. - - This function has no effect on the global QWebEngineSettings instance. + Resets the font size for \a type to the size specified in the profile that + the page belongs to. */ /*! @@ -222,10 +216,8 @@ /*! \fn void QWebEngineSettings::resetFontFamily(FontFamily which) - Resets the actual font family specified by \a which to the one set - in the global QWebEngineSettings instance. - - This function has no effect on the global QWebEngineSettings instance. + Resets the actual font family specified by \a which to the one specified + in the profile that the page belongs to. */ /*! @@ -245,9 +237,5 @@ \fn void QWebEngineSettings::resetAttribute(WebAttribute attribute) Resets the setting of \a attribute to the value specified in the - global QWebEngineSettings instance. - - This function has no effect on the global QWebEngineSettings instance. - - \sa globalSettings() + profile that the page belongs to. */ diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc index 3b27ca146..e54c5d507 100644 --- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc @@ -141,6 +141,12 @@ \warning This function works only for HTML. For other MIME types (such as XHTML or SVG), setContent() should be used instead. + \note Content larger than 2 MB cannot be displayed, because setHtml() + converts the provided HTML to percent-encoding and places \c data: in front + of it to create the URL that it navigates to. Thereby, the provided code + becomes a URL that exceeds the 2 MB limit set by Chromium. If the content is + too large, the loadFinished() signal is triggered with \c success=false. + \sa load(), setContent(), QWebEnginePage::toHtml(), QWebEnginePage::setContent() */ 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 c608ba2aa..d02191b23 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -59,15 +59,6 @@ namespace QtWebEngineCore { -static bool handleShortcutOverrideEvent(RenderWidgetHostViewQtDelegateClient *client, QKeyEvent *ke) -{ - if (client->handleShortcutOverrideEvent(ke)) - return true; - if (editorActionForKeyEvent(ke) != QWebEnginePage::NoWebAction) - ke->accept(); - return true; -} - class RenderWidgetHostViewQuickItem : public QQuickItem { public: RenderWidgetHostViewQuickItem(RenderWidgetHostViewQtDelegateClient *client) : m_client(client) @@ -79,10 +70,8 @@ public: protected: bool event(QEvent *event) override { - if (event->type() == QEvent::ShortcutOverride) { - handleShortcutOverrideEvent(m_client, static_cast<QKeyEvent *>(event)); - return true; - } + if (event->type() == QEvent::ShortcutOverride) + return m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event)); return QQuickItem::event(event); } void focusInEvent(QFocusEvent *event) override @@ -454,10 +443,8 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) // We forward focus events later, once they have made it to the m_rootItem. return QQuickWidget::event(event); case QEvent::ShortcutOverride: - if (event->type() == QEvent::ShortcutOverride) { - handleShortcutOverrideEvent(m_client, static_cast<QKeyEvent *>(event)); + if (m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event))) return true; - } break; case QEvent::DragEnter: case QEvent::DragLeave: diff --git a/tests/auto/quick/qmltests/data/tst_download.qml b/tests/auto/quick/qmltests/data/tst_download.qml index e4e93b993..019ebd9dc 100644 --- a/tests/auto/quick/qmltests/data/tst_download.qml +++ b/tests/auto/quick/qmltests/data/tst_download.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -28,7 +28,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.1 +import QtWebEngine 1.5 TestWebEngineView { id: webEngineView @@ -40,6 +40,7 @@ TestWebEngineView { property int receivedBytes: 0 property bool cancelDownload: false property var downloadState: [] + property var downloadInterruptReason: null SignalSpy { id: downLoadRequestedSpy @@ -55,7 +56,9 @@ TestWebEngineView { Connections { id: downloadItemConnections + ignoreUnknownSignals: true onStateChanged: downloadState.push(target.state) + onInterruptReasonChanged: downloadInterruptReason = target.interruptReason } WebEngineProfile { @@ -88,6 +91,7 @@ TestWebEngineView { cancelDownload = false downloadItemConnections.target = null downloadState = [] + downloadInterruptReason = null } function test_downloadRequest() { @@ -96,6 +100,7 @@ TestWebEngineView { downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) compare(downloadState[0], WebEngineDownloadItem.DownloadRequested) + verify(!downloadInterruptReason) } function test_totalFileLength() { @@ -104,6 +109,7 @@ TestWebEngineView { downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) compare(totalBytes, 325) + verify(!downloadInterruptReason) } function test_downloadSucceeded() { @@ -111,10 +117,12 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("download.zip") downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) - compare(downloadState[1], WebEngineDownloadItem.DownloadInProgress) + compare(downloadState[0], WebEngineDownloadItem.DownloadRequested) + tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress) downloadFinishedSpy.wait() compare(totalBytes, receivedBytes) tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted) + verify(!downloadInterruptReason) } function test_downloadCancelled() { @@ -124,7 +132,8 @@ TestWebEngineView { downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) compare(downloadFinishedSpy.count, 1) - compare(downloadState[1], WebEngineDownloadItem.DownloadCancelled) + tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadCancelled) + tryCompare(webEngineView, "downloadInterruptReason", WebEngineDownloadItem.UserCanceled) } } } diff --git a/tests/auto/quick/qmltests/data/tst_findText.qml b/tests/auto/quick/qmltests/data/tst_findText.qml index 78359bfc2..8526012c9 100644 --- a/tests/auto/quick/qmltests/data/tst_findText.qml +++ b/tests/auto/quick/qmltests/data/tst_findText.qml @@ -61,6 +61,32 @@ TestWebEngineView { return bodyInnerHTML; } + function getListItemText(index) { + var listItemText; + runJavaScript("document.getElementById('list').getElementsByTagName('li')[" + index + "].innerText;", function(result) { + listItemText = result; + }); + tryVerify(function() { return listItemText != undefined; }); + return listItemText; + } + + function appendListItem(text) { + var script = + "(function () {" + + " var list = document.getElementById('list');" + + " var item = document.createElement('li');" + + " item.appendChild(document.createTextNode('" + text + "'));" + + " list.appendChild(item);" + + " return list.getElementsByTagName('li').length - 1;" + + "})();"; + var itemIndex; + + runJavaScript(script, function(result) { itemIndex = result; }); + tryVerify(function() { return itemIndex != undefined; }); + // Make sure the DOM is up-to-date. + tryVerify(function() { return getListItemText(itemIndex).length == text.length; }); + } + function test_findText() { var findFlags = WebEngineView.FindCaseSensitively webEngineView.url = Qt.resolvedUrl("test1.html") @@ -157,5 +183,37 @@ TestWebEngineView { tryCompare(webEngineView, "matchCount", 1) verify(!findFailed) } + + function test_findTextInterruptedByLoad() { + var findFlags = 0; + + var listItemText = ''; + for (var i = 0; i < 100000; ++i) + listItemText += "bla "; + listItemText = listItemText.trim(); + + webEngineView.loadHtml( + "<html><body>" + + "<ol id='list' />" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + + // Generating a huge list is a workaround to avoid timeout while loading the test page. + for (var i = 0; i < 10; ++i) + appendListItem(listItemText); + appendListItem("hello"); + + webEngineView.clear(); + webEngineView.findText("hello", findFlags, webEngineView.findTextCallback); + + // This should not crash. + webEngineView.url = "https://www.qt.io"; + if (!webEngineView.waitForLoadSucceeded(12000)) + skip("Couldn't load page from network, skipping test."); + + // Can't be sure whether the findText succeeded before the new load. + // Thus don't check the find result just whether the callback was called. + tryVerify(function() { return webEngineView.matchCount != -1; }); + } } } diff --git a/tests/auto/quick/qmltests/data/tst_loadProgress.qml b/tests/auto/quick/qmltests/data/tst_loadProgress.qml index 32cd91418..bb85ed8e3 100644 --- a/tests/auto/quick/qmltests/data/tst_loadProgress.qml +++ b/tests/auto/quick/qmltests/data/tst_loadProgress.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -41,15 +41,31 @@ TestWebEngineView { loadProgressArray.push(webEngineView.loadProgress) } + SignalSpy { + id: spyProgress + target: webEngineView + signalName: "loadProgressChanged" + } + TestCase { name: "WebEngineViewLoadProgress" function test_loadProgress() { compare(webEngineView.loadProgress, 0) + compare(spyProgress.count, 0) loadProgressArray = [] webEngineView.url = Qt.resolvedUrl("test1.html") + // Wait for the first loadProgressChanged signal, which have to be non-negative + spyProgress.wait() + verify(loadProgressArray[0] >= 0) + verify(webEngineView.loadProgress >= 0) + + // Wait for the last loadProgressChanged signal, which have to be 100% verify(webEngineView.waitForLoadSucceeded()) + spyProgress.wait() + compare(loadProgressArray[loadProgressArray.length - 1], 100) + compare(webEngineView.loadProgress, 100) // Test whether the chromium emits progress numbers in ascending order var loadProgressMin = 0 @@ -58,9 +74,6 @@ TestWebEngineView { verify(loadProgressMin <= loadProgress) loadProgressMin = loadProgress } - - // The progress must be 100% at the end - compare(loadProgressArray[loadProgressArray.length - 1], 100) } } } diff --git a/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml b/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml deleted file mode 100644 index f05bb1e3d..000000000 --- a/tests/auto/quick/qmltests/data/tst_loadProgressSignal.qml +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.2 - -TestWebEngineView { - id: webEngineView - width: 400 - height: 300 - - SignalSpy { - id: spyProgress - target: webEngineView - signalName: "loadProgressChanged" - } - - TestCase { - name: "WebEngineViewLoadProgressSignal" - - function test_loadProgressSignal() { - compare(spyProgress.count, 0) - compare(webEngineView.loadProgress, 0) - webEngineView.url = Qt.resolvedUrl("test1.html") - spyProgress.wait() - verify(webEngineView.loadProgress > -1 && webEngineView.loadProgress < 101) - if (webEngineView.loadProgress > 0 && webEngineView.loadProgress < 100) { - verify(webEngineView.waitForLoadSucceeded()) - spyProgress.wait() - compare(webEngineView.loadProgress, 100) - } - } - } -} diff --git a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml index 7a04d5f5b..4becbb620 100644 --- a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml +++ b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml @@ -28,7 +28,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.2 +import QtWebEngine 1.5 TestWebEngineView { id: webEngineView @@ -47,7 +47,8 @@ TestWebEngineView { onNewViewRequested: { newViewRequest = { "destination": request.destination, - "userInitiated": request.userInitiated + "userInitiated": request.userInitiated, + "requestedUrl": request.requestedUrl }; dialog = Qt.createQmlObject( @@ -81,6 +82,8 @@ TestWebEngineView { } function test_jsWindowOpen() { + var url = 'data:text/html,%3Chtml%3E%3Cbody%3ETest+Page%3C%2Fbody%3E%3C%2Fhtml%3E'; + // Open an empty page in a new tab webEngineView.loadHtml( "<html><head><script>" + @@ -95,28 +98,30 @@ TestWebEngineView { verify(dialog.webEngineView.waitForLoadSucceeded()); compare(dialog.webEngineView.url, ""); + compare(newViewRequest.requestedUrl, 'about:blank'); newViewRequestedSpy.clear(); dialog.destroy(); - // Open an empty page in a new dialog + // Open a page in a new dialog webEngineView.loadHtml( "<html><head><script>" + - " function popup() { window.open('', '_blank', 'width=200,height=100'); }" + + " function popup() { window.open('" + url + "', '_blank', 'width=200,height=100'); }" + "</script></head>" + "<body onload='popup()'></body></html>"); verify(webEngineView.waitForLoadSucceeded()); tryCompare(newViewRequestedSpy, "count", 1); compare(newViewRequest.destination, WebEngineView.NewViewInDialog); + compare(newViewRequest.requestedUrl, url); verify(!newViewRequest.userInitiated); verify(dialog.webEngineView.waitForLoadSucceeded()); newViewRequestedSpy.clear(); dialog.destroy(); - // Open an empty page in a new dialog by user + // Open a page in a new dialog by user webEngineView.loadHtml( "<html><head><script>" + - " function popup() { window.open('', '_blank', 'width=200,height=100'); }" + + " function popup() { window.open('" + url + "', '_blank', 'width=200,height=100'); }" + "</script></head>" + "<body onload=\"document.getElementById('popupButton').focus();\">" + " <button id='popupButton' onclick='popup()'>Pop Up!</button>" + @@ -124,6 +129,7 @@ TestWebEngineView { verify(webEngineView.waitForLoadSucceeded()); verifyElementHasFocus("popupButton"); keyPress(Qt.Key_Enter); + compare(newViewRequest.requestedUrl, url); tryCompare(newViewRequestedSpy, "count", 1); compare(newViewRequest.destination, WebEngineView.NewViewInDialog); diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 3973ede14..d2c9245bd 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -58,7 +58,6 @@ OTHER_FILES += \ $$PWD/data/tst_loadFail.qml \ $$PWD/data/tst_loadHtml.qml \ $$PWD/data/tst_loadProgress.qml \ - $$PWD/data/tst_loadProgressSignal.qml \ $$PWD/data/tst_loadRecursionCrash.qml \ $$PWD/data/tst_loadUrl.qml \ $$PWD/data/tst_navigationHistory.qml \ diff --git a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp index dffd995c9..d9bbce173 100644 --- a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp +++ b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp @@ -37,8 +37,9 @@ public: protected : void loadPage(int nr) { + loadFinishedSpy->clear(); page->load(QUrl("qrc:/resources/page" + QString::number(nr) + ".html")); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 1); } public Q_SLOTS: @@ -75,7 +76,7 @@ private Q_SLOTS: private: QWebEnginePage* page; QWebEngineHistory* hist; - QScopedPointer<SignalBarrier> loadFinishedBarrier; + QScopedPointer<QSignalSpy> loadFinishedSpy; int histsize; }; @@ -94,7 +95,7 @@ void tst_QWebEngineHistory::initTestCase() void tst_QWebEngineHistory::init() { page = new QWebEnginePage(this); - loadFinishedBarrier.reset(new SignalBarrier(page, SIGNAL(loadFinished(bool)))); + loadFinishedSpy.reset(new QSignalSpy(page, SIGNAL(loadFinished(bool)))); for (int i = 1;i < 6;i++) { loadPage(i); @@ -105,7 +106,7 @@ void tst_QWebEngineHistory::init() void tst_QWebEngineHistory::cleanup() { - loadFinishedBarrier.reset(); + loadFinishedSpy.reset(); delete page; } @@ -114,7 +115,7 @@ void tst_QWebEngineHistory::cleanup() */ void tst_QWebEngineHistory::title() { - QCOMPARE(hist->currentItem().title(), QString("page5")); + QTRY_COMPARE(hist->currentItem().title(), QString("page5")); } void tst_QWebEngineHistory::lastVisited() @@ -128,7 +129,7 @@ void tst_QWebEngineHistory::lastVisited() */ void tst_QWebEngineHistory::count() { - QCOMPARE(hist->count(), histsize); + QTRY_COMPARE(hist->count(), histsize); } /** @@ -136,17 +137,17 @@ void tst_QWebEngineHistory::count() */ void tst_QWebEngineHistory::back() { - SignalBarrier titleChangedBarrier(page, SIGNAL(titleChanged(const QString&))); + QSignalSpy titleChangedSpy(page, SIGNAL(titleChanged(const QString&))); for (int i = histsize;i > 1;i--) { - QCOMPARE(toPlainTextSync(page), QString("page") + QString::number(i)); + QTRY_COMPARE(toPlainTextSync(page), QString("page") + QString::number(i)); hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); - QVERIFY(titleChangedBarrier.ensureSignalEmitted()); + QTRY_COMPARE(loadFinishedSpy->count(), histsize-i+1); + QTRY_COMPARE(titleChangedSpy.count(), histsize-i+1); } //try one more time (too many). crash test hist->back(); - QCOMPARE(toPlainTextSync(page), QString("page1")); + QTRY_COMPARE(toPlainTextSync(page), QString("page1")); } /** @@ -155,21 +156,23 @@ void tst_QWebEngineHistory::back() void tst_QWebEngineHistory::forward() { //rewind history :-) + int histBackCount = 0; while (hist->canGoBack()) { hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + histBackCount++; + QTRY_COMPARE(loadFinishedSpy->count(), histBackCount+1); } - SignalBarrier titleChangedBarrier(page, SIGNAL(titleChanged(const QString&))); + QSignalSpy titleChangedSpy(page, SIGNAL(titleChanged(const QString&))); for (int i = 1;i < histsize;i++) { - QCOMPARE(toPlainTextSync(page), QString("page") + QString::number(i)); + QTRY_COMPARE(toPlainTextSync(page), QString("page") + QString::number(i)); hist->forward(); - loadFinishedBarrier->ensureSignalEmitted(); - QVERIFY(titleChangedBarrier.ensureSignalEmitted()); + QTRY_COMPARE(loadFinishedSpy->count(), i+histBackCount); + QTRY_COMPARE(titleChangedSpy.count(), i); } //try one more time (too many). crash test hist->forward(); - QCOMPARE(toPlainTextSync(page), QString("page") + QString::number(histsize)); + QTRY_COMPARE(toPlainTextSync(page), QString("page") + QString::number(histsize)); } /** @@ -178,7 +181,7 @@ void tst_QWebEngineHistory::forward() void tst_QWebEngineHistory::itemAt() { for (int i = 1;i < histsize;i++) { - QCOMPARE(hist->itemAt(i - 1).title(), QString("page") + QString::number(i)); + QTRY_COMPARE(hist->itemAt(i - 1).title(), QString("page") + QString::number(i)); QVERIFY(hist->itemAt(i - 1).isValid()); } //check out of range values @@ -192,14 +195,19 @@ void tst_QWebEngineHistory::itemAt() void tst_QWebEngineHistory::goToItem() { QWebEngineHistoryItem current = hist->currentItem(); + hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 2); + hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 3); + QVERIFY(hist->currentItem().title() != current.title()); + hist->goToItem(current); - loadFinishedBarrier->ensureSignalEmitted(); - QCOMPARE(hist->currentItem().title(), current.title()); + QTRY_COMPARE(loadFinishedSpy->count(), 3); + + QTRY_COMPARE(hist->currentItem().title(), current.title()); } /** @@ -209,25 +217,27 @@ void tst_QWebEngineHistory::items() { QList<QWebEngineHistoryItem> items = hist->items(); //check count - QCOMPARE(histsize, items.count()); + QTRY_COMPARE(histsize, items.count()); //check order for (int i = 1;i <= histsize;i++) { - QCOMPARE(items.at(i - 1).title(), QString("page") + QString::number(i)); + QTRY_COMPARE(items.at(i - 1).title(), QString("page") + QString::number(i)); } } void tst_QWebEngineHistory::backForwardItems() { hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 2); + hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); - QCOMPARE(hist->items().size(), 5); - QCOMPARE(hist->backItems(100).size(), 2); - QCOMPARE(hist->backItems(1).size(), 1); - QCOMPARE(hist->forwardItems(100).size(), 2); - QCOMPARE(hist->forwardItems(1).size(), 1); + QTRY_COMPARE(loadFinishedSpy->count(), 3); + + QTRY_COMPARE(hist->items().size(), 5); + QTRY_COMPARE(hist->backItems(100).size(), 2); + QTRY_COMPARE(hist->backItems(1).size(), 1); + QTRY_COMPARE(hist->forwardItems(100).size(), 2); + QTRY_COMPARE(hist->forwardItems(1).size(), 1); } /** @@ -242,20 +252,20 @@ void tst_QWebEngineHistory::serialize_1() save << *hist; QVERIFY(save.status() == QDataStream::Ok); - QCOMPARE(hist->count(), histsize); + QTRY_COMPARE(hist->count(), histsize); //check size of history //load next page to find differences loadPage(6); - QCOMPARE(hist->count(), histsize + 1); + QTRY_COMPARE(hist->count(), histsize + 1); load >> *hist; QVERIFY(load.status() == QDataStream::Ok); - QCOMPARE(hist->count(), histsize); + QTRY_COMPARE(hist->count(), histsize); //check order of historyItems QList<QWebEngineHistoryItem> items = hist->items(); for (int i = 1;i <= histsize;i++) { - QCOMPARE(items.at(i - 1).title(), QString("page") + QString::number(i)); + QTRY_COMPARE(items.at(i - 1).title(), QString("page") + QString::number(i)); } } @@ -271,16 +281,16 @@ void tst_QWebEngineHistory::serialize_2() // Force a "same document" navigation. page->load(page->url().toString() + QLatin1String("#dummyAnchor")); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 1); int initialCurrentIndex = hist->currentItemIndex(); hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 2); hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 3); hist->back(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 4); //check if current index was changed (make sure that it is not last item) QVERIFY(hist->currentItemIndex() != initialCurrentIndex); //save current index @@ -291,18 +301,18 @@ void tst_QWebEngineHistory::serialize_2() load >> *hist; QVERIFY(load.status() == QDataStream::Ok); // Restoring the history will trigger a load. - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 5); //check current index - QCOMPARE(hist->currentItemIndex(), oldCurrentIndex); + QTRY_COMPARE(hist->currentItemIndex(), oldCurrentIndex); hist->forward(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 6); hist->forward(); - loadFinishedBarrier->ensureSignalEmitted(); + QTRY_COMPARE(loadFinishedSpy->count(), 7); hist->forward(); - loadFinishedBarrier->ensureSignalEmitted(); - QCOMPARE(hist->currentItemIndex(), initialCurrentIndex); + QTRY_COMPARE(loadFinishedSpy->count(), 8); + QTRY_COMPARE(hist->currentItemIndex(), initialCurrentIndex); } /** @@ -334,10 +344,10 @@ void tst_QWebEngineHistory::serialize_3() QWebEngineHistoryItem b = hist->currentItem(); //check properties AFTER serialization - QCOMPARE(b.title(), title); - QCOMPARE(b.lastVisited(), lastVisited); - QCOMPARE(b.originalUrl(), originalUrl); - QCOMPARE(b.url(), url); + QTRY_COMPARE(b.title(), title); + QTRY_COMPARE(b.lastVisited(), lastVisited); + QTRY_COMPARE(b.originalUrl(), originalUrl); + QTRY_COMPARE(b.url(), url); //Check if all data was read QVERIFY(load.atEnd()); @@ -398,27 +408,16 @@ void tst_QWebEngineHistory::saveAndRestore_crash_3() void tst_QWebEngineHistory::saveAndRestore_crash_4() { -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else QByteArray buffer; saveHistory(hist, &buffer); QScopedPointer<QWebEnginePage> page2(new QWebEnginePage(this)); - // The initial crash was in PageCache. - page2->settings()->setMaximumPagesInCache(3); // Load the history in a new page, waiting for the load to finish. - QEventLoop waitForLoadFinished; - QObject::connect(page2.data(), SIGNAL(loadFinished(bool)), &waitForLoadFinished, SLOT(quit()), Qt::QueuedConnection); + QSignalSpy loadFinishedSpy2(page2.data(), SIGNAL(loadFinished(bool))); QDataStream load(&buffer, QIODevice::ReadOnly); load >> *page2->history(); - waitForLoadFinished.exec(); - - page2.reset(); - // Give some time for the PageCache cleanup 0-timer to fire. - QTest::qWait(50); -#endif + QTRY_COMPARE(loadFinishedSpy2.count(), 1); } void tst_QWebEngineHistory::popPushState_data() @@ -469,10 +468,10 @@ void tst_QWebEngineHistory::historyItemFromDeletedPage() foreach (QWebEngineHistoryItem item, items) { QVERIFY(!item.isValid()); - QCOMPARE(item.originalUrl(), QUrl()); - QCOMPARE(item.url(), QUrl()); - QCOMPARE(item.title(), QString()); - QCOMPARE(item.lastVisited(), QDateTime()); + QTRY_COMPARE(item.originalUrl(), QUrl()); + QTRY_COMPARE(item.url(), QUrl()); + QTRY_COMPARE(item.title(), QString()); + QTRY_COMPARE(item.lastVisited(), QDateTime()); } } diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST index 7121f7561..b3f393af4 100644 --- a/tests/auto/widgets/qwebengineview/BLACKLIST +++ b/tests/auto/widgets/qwebengineview/BLACKLIST @@ -3,3 +3,6 @@ windows [imeComposition] osx + +[inputFieldOverridesShortcuts] +osx diff --git a/tests/auto/widgets/qwebengineview/resources/input_types.html b/tests/auto/widgets/qwebengineview/resources/input_types.html index 2e893afae..5ba1a6069 100644 --- a/tests/auto/widgets/qwebengineview/resources/input_types.html +++ b/tests/auto/widgets/qwebengineview/resources/input_types.html @@ -1,9 +1,9 @@ <html><body> -<input type='text' maxlength='20' style='position: absolute; left: 10px; top: 0px; height: 50px; width: 100px;'/><br> -<input type='password' style='position: absolute; left: 10px; top: 50px; height: 50px; width: 100px;'/><br> -<input type='tel' style='position: absolute; left: 10px; top: 100px; height: 50px; width: 100px;'/><br> -<input type='number' style='position: absolute; left: 10px; top: 150px; height: 50px; width: 100px;'/><br> -<input type='email' style='position: absolute; left: 10px; top: 200px; height: 50px; width: 100px;'/><br> -<input type='url' style='position: absolute; left: 10px; top: 250px; height: 50px; width: 100px;'/><br> -<textarea style='position: absolute; left: 10px; top: 310px; height: 50px; width: 100px;' rows="2" cols="20">blah blah blah blah</textarea><br> +<input type='text' id='textInput' maxlength='20' style='position: absolute; left: 10px; top: 0px; height: 50px; width: 100px;'/><br> +<input type='password' id='passwordInput' style='position: absolute; left: 10px; top: 50px; height: 50px; width: 100px;'/><br> +<input type='tel' id='telInput' style='position: absolute; left: 10px; top: 100px; height: 50px; width: 100px;'/><br> +<input type='number' id='numberInput' style='position: absolute; left: 10px; top: 150px; height: 50px; width: 100px;'/><br> +<input type='email' id='emailInput' style='position: absolute; left: 10px; top: 200px; height: 50px; width: 100px;'/><br> +<input type='url' id='urlInput' style='position: absolute; left: 10px; top: 250px; height: 50px; width: 100px;'/><br> +<textarea id='textArea' style='position: absolute; left: 10px; top: 310px; height: 50px; width: 100px;' rows="2" cols="20">blah blah blah blah</textarea><br> </body></html> diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 37c7ae881..8509e9a2d 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -55,6 +55,43 @@ do { \ QCOMPARE((__expr), __expected); \ } while (0) +static QPoint elementCenter(QWebEnginePage *page, const QString &id) +{ + const QString jsCode( + "(function(){" + " var elem = document.getElementById('" + id + "');" + " var rect = elem.getBoundingClientRect();" + " return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" + "})()"); + QVariantList rectList = evaluateJavaScriptSync(page, jsCode).toList(); + + if (rectList.count() != 2) { + qWarning("elementCenter failed."); + return QPoint(); + } + + return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); +} + +static QRect elementGeometry(QWebEnginePage *page, const QString &id) +{ + const QString jsCode( + "(function() {" + " var elem = document.getElementById('" + id + "');" + " var rect = elem.getBoundingClientRect();" + " return [rect.left, rect.top, rect.right, rect.bottom];" + "})()"); + QVariantList coords = evaluateJavaScriptSync(page, jsCode).toList(); + + if (coords.count() != 4) { + qWarning("elementGeometry faield."); + return QRect(); + } + + return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt()); +} + + class tst_QWebEngineView : public QObject { Q_OBJECT @@ -263,113 +300,111 @@ void tst_QWebEngineView::crashTests() void tst_QWebEngineView::microFocusCoordinates() { -#if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) - QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); -#else - QWebEnginePage* page = new QWebEnginePage; - QWebEngineView* webView = new QWebEngineView; - webView->setPage( page ); - - page->setHtml("<html><body>" \ - "<input type='text' id='input1' style='font--family: serif' value='' maxlength='20'/><br>" \ - "<canvas id='canvas1' width='500' height='500'></canvas>" \ - "<input type='password'/><br>" \ - "<canvas id='canvas2' width='500' height='500'></canvas>" \ - "</body></html>"); - -#if defined(QWEBENGINEFRAME) - page->mainFrame()->setFocus(); -#endif + QWebEngineView webView; + webView.show(); + QTest::qWaitForWindowExposed(&webView); + + QSignalSpy scrollSpy(webView.page(), SIGNAL(scrollPositionChanged(QPointF))); + QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool))); + webView.page()->setHtml("<html><body>" + "<input type='text' id='input1' value='' maxlength='20'/><br>" + "<canvas id='canvas1' width='500' height='500'></canvas>" + "<input type='password'/><br>" + "<canvas id='canvas2' width='500' height='500'></canvas>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); - QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); - QVERIFY(initialMicroFocus.isValid()); + evaluateJavaScriptSync(webView.page(), "document.getElementById('input1').focus()"); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); - page->scroll(0,50); + QTRY_VERIFY(webView.focusProxy()->inputMethodQuery(Qt::ImMicroFocus).isValid()); + QVariant initialMicroFocus = webView.focusProxy()->inputMethodQuery(Qt::ImMicroFocus); - QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); - QVERIFY(currentMicroFocus.isValid()); + evaluateJavaScriptSync(webView.page(), "window.scrollBy(0, 50)"); + QVERIFY(scrollSpy.wait()); + + QTRY_VERIFY(webView.focusProxy()->inputMethodQuery(Qt::ImMicroFocus).isValid()); + QVariant currentMicroFocus = webView.focusProxy()->inputMethodQuery(Qt::ImMicroFocus); QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect()); -#endif } void tst_QWebEngineView::focusInputTypes() { -#if !defined(QWEBENGINEELEMENT) - QSKIP("QWEBENGINEELEMENT"); -#else QWebEngineView webView; webView.show(); QTest::qWaitForWindowExposed(&webView); - QUrl url("qrc:///resources/input_types.html"); - QWebEngineFrame* const mainFrame = webView.page()->mainFrame(); - webView.load(url); - mainFrame->setFocus(); - - QSignalSpy spyFinished(webView, &QWebEngineView::loadFinished); - QVERIFY(spyFinished.wait()); + QSignalSpy loadFinishedSpy(&webView, SIGNAL(loadFinished(bool))); + webView.load(QUrl("qrc:///resources/input_types.html")); + QVERIFY(loadFinishedSpy.wait()); - // 'text' type - QWebEngineElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - QVERIFY(webView.inputMethodHints() == Qt::ImhNone); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + // 'text' field + QPoint textInputCenter = elementCenter(webView.page(), "textInput"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'password' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QPoint passwordInputCenter = elementCenter(webView.page(), "passwordInput"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'tel' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDialableCharactersOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QPoint telInputCenter = elementCenter(webView.page(), "telInput"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, telInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("telInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDialableCharactersOnly); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'number' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDigitsOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QPoint numberInputCenter = elementCenter(webView.page(), "numberInput"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, numberInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("numberInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhFormattedNumbersOnly); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'email' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhEmailCharactersOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QPoint emailInputCenter = elementCenter(webView.page(), "emailInput"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, emailInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("emailInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhEmailCharactersOnly); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'url' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhUrlCharactersOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QPoint urlInputCenter = elementCenter(webView.page(), "urlInput"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, urlInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("urlInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase)); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'password' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'text' type - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - QVERIFY(webView.inputMethodHints() == Qt::ImhNone); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'password' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); // 'text area' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - QVERIFY(webView.inputMethodHints() == Qt::ImhNone); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); -#endif + QPoint textAreaCenter = elementCenter(webView.page(), "textArea"); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textAreaCenter); + QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textArea")); + VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhMultiLine | Qt::ImhPreferLowercase)); + QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); } class KeyEventRecordingWidget : public QWidget { @@ -1309,7 +1344,6 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() { bool actionTriggered = false; QAction *action = new QAction; - action->setShortcut(Qt::Key_X); connect(action, &QAction::triggered, [&actionTriggered] () { actionTriggered = true; }); QWebEngineView view; @@ -1317,7 +1351,7 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); view.setHtml(QString("<html><body onload=\"input1=document.getElementById('input1')\">" - "<input id=\"dummy\" type=\"text\">" + "<button id=\"btn1\" type=\"button\">push it real good</button>" "<input id=\"input1\" type=\"text\" value=\"x\">" "</body></html>")); QVERIFY(loadFinishedSpy.wait()); @@ -1330,7 +1364,15 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() "input1.value").toString(); }; + // The input form is not focused. The action is triggered on pressing Shift+Delete. + action->setShortcut(Qt::SHIFT + Qt::Key_Delete); + QTest::keyClick(view.windowHandle(), Qt::Key_Delete, Qt::ShiftModifier); + QTRY_VERIFY(actionTriggered); + QCOMPARE(inputFieldValue(), QString("x")); + // The input form is not focused. The action is triggered on pressing X. + action->setShortcut(Qt::Key_X); + actionTriggered = false; QTest::keyClick(view.windowHandle(), Qt::Key_X); QTRY_VERIFY(actionTriggered); QCOMPARE(inputFieldValue(), QString("x")); @@ -1349,16 +1391,12 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() QTRY_VERIFY(actionTriggered); QCOMPARE(inputFieldValue(), QString("yx")); - // Remove focus from the input field. A QKeySequence::Copy action still must not be triggered. - evaluateJavaScriptSync(view.page(), "input1.blur();"); + // Remove focus from the input field. A QKeySequence::Copy action must be triggerable. + evaluateJavaScriptSync(view.page(), "document.getElementById('btn1').focus();"); action->setShortcut(QKeySequence::Copy); actionTriggered = false; QTest::keyClick(view.windowHandle(), Qt::Key_C, Qt::ControlModifier); - // Add some text in the input field to ensure that the key event went through. - evaluateJavaScriptSync(view.page(), "input1.focus();"); - QTest::keyClick(view.windowHandle(), Qt::Key_U); - QTRY_COMPARE(inputFieldValue(), QString("yux")); - QVERIFY(!actionTriggered); + QTRY_VERIFY(actionTriggered); } class TestInputContext : public QPlatformInputContext @@ -1393,42 +1431,6 @@ public: bool m_visible; }; -static QPoint elementCenter(QWebEnginePage *page, const QString &id) -{ - const QString jsCode( - "(function(){" - " var elem = document.getElementById('" + id + "');" - " var rect = elem.getBoundingClientRect();" - " return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" - "})()"); - QVariantList rectList = evaluateJavaScriptSync(page, jsCode).toList(); - - if (rectList.count() != 2) { - qWarning("elementCenter failed."); - return QPoint(); - } - - return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); -} - -static QRect elementGeometry(QWebEnginePage *page, const QString &id) -{ - const QString jsCode( - "(function() {" - " var elem = document.getElementById('" + id + "');" - " var rect = elem.getBoundingClientRect();" - " return [rect.left, rect.top, rect.right, rect.bottom];" - "})()"); - QVariantList coords = evaluateJavaScriptSync(page, jsCode).toList(); - - if (coords.count() != 4) { - qWarning("elementGeometry faield."); - return QRect(); - } - - return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt()); -} - void tst_QWebEngineView::softwareInputPanel() { TestInputContext testContext; @@ -1798,12 +1800,36 @@ void tst_QWebEngineView::emptyInputMethodEvent() QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); QCOMPARE(selectionChangedSpy.count(), 1); - // Send empty QInputMethodEvent + // 1. Empty input method event does not clear text QInputMethodEvent emptyEvent; QApplication::sendEvent(view.focusProxy(), &emptyEvent); QString inputValue = evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(); - QCOMPARE(inputValue, QString("QtWebEngine")); + QCOMPARE(inputValue, QStringLiteral("QtWebEngine")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QStringLiteral("QtWebEngine")); + + // Reset: clear input field + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1').value = ''"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + QTRY_VERIFY(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString().isEmpty()); + + // 2. Cancel IME composition with empty input method event + // Start IME composition + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent eventComposition("a", attributes); + QApplication::sendEvent(view.focusProxy(), &eventComposition); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("a")); + QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString().isEmpty()); + + // Cancel IME composition + QApplication::sendEvent(view.focusProxy(), &emptyEvent); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString().isEmpty()); + + // Try key press after cancelled IME composition + QTest::keyClick(view.focusProxy(), Qt::Key_B); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QStringLiteral("b")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QStringLiteral("b")); } void tst_QWebEngineView::imeComposition() |