diff options
Diffstat (limited to 'src/webenginewidgets')
21 files changed, 400 insertions, 192 deletions
diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp index 5d68ed0ec..63e11175b 100644 --- a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp +++ b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp @@ -148,10 +148,11 @@ QString QWebEngineContextMenuData::linkText() const /*! Returns the URL of a link if the context is a link. + It is not guaranteed to be a valid URL. */ QUrl QWebEngineContextMenuData::linkUrl() const { - return d ? d->linkUrl() : QUrl(); + return d ? d->unfilteredLinkUrl() : QUrl(); } /*! diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.cpp b/src/webenginewidgets/api/qwebenginedownloaditem.cpp index c1d9a3698..dc1a48360 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.cpp +++ b/src/webenginewidgets/api/qwebenginedownloaditem.cpp @@ -38,10 +38,12 @@ ****************************************************************************/ #include "qwebenginedownloaditem.h" - #include "qwebenginedownloaditem_p.h" + +#include "browser_context_adapter.h" #include "qwebengineprofile_p.h" + QT_BEGIN_NAMESPACE using QtWebEngineCore::BrowserContextAdapterClient; @@ -116,6 +118,7 @@ QWebEngineDownloadItemPrivate::QWebEngineDownloadItemPrivate(QWebEngineProfilePr , type(QWebEngineDownloadItem::Attachment) , interruptReason(QWebEngineDownloadItem::NoReason) , downloadUrl(url) + , downloadPaused(false) , totalBytes(-1) , receivedBytes(0) { @@ -145,10 +148,16 @@ void QWebEngineDownloadItemPrivate::update(const BrowserContextAdapterClient::Do Q_EMIT q->downloadProgress(receivedBytes, totalBytes); } - downloadFinished = downloadState != QWebEngineDownloadItem::DownloadInProgress; + if (info.done != downloadFinished) { + downloadFinished = info.done; + if (downloadFinished) + Q_EMIT q->finished(); + } - if (downloadFinished) - Q_EMIT q->finished(); + if (downloadPaused != info.paused) { + downloadPaused = info.paused; + Q_EMIT q->isPausedChanged(downloadPaused); + } } /*! @@ -184,13 +193,51 @@ void QWebEngineDownloadItem::cancel() || state == QWebEngineDownloadItem::DownloadCancelled) return; - d->downloadState = QWebEngineDownloadItem::DownloadCancelled; - Q_EMIT stateChanged(d->downloadState); - // We directly cancel the download request if the user cancels // before it even started, so no need to notify the profile here. - if (state == QWebEngineDownloadItem::DownloadInProgress) - d->profile->cancelDownload(d->downloadId); + if (state == QWebEngineDownloadItem::DownloadInProgress) { + if (auto browserContext = d->profile->browserContext()) + browserContext->cancelDownload(d->downloadId); + } else { + d->downloadState = QWebEngineDownloadItem::DownloadCancelled; + Q_EMIT stateChanged(d->downloadState); + } +} + +/*! + \since 5.10 + Pauses the current download. Has no effect if the state is not \c DownloadInProgress. + + \sa resume() +*/ + +void QWebEngineDownloadItem::pause() +{ + Q_D(QWebEngineDownloadItem); + + QWebEngineDownloadItem::DownloadState state = d->downloadState; + + if (state != QWebEngineDownloadItem::DownloadInProgress) + return; + + d->profile->browserContext()->pauseDownload(d->downloadId); +} + +/*! + \since 5.10 + Resumes the current download if it was paused or interrupted. + + \sa pause(), isPaused(), state() +*/ +void QWebEngineDownloadItem::resume() +{ + Q_D(QWebEngineDownloadItem); + + QWebEngineDownloadItem::DownloadState state = d->downloadState; + + if (d->downloadFinished || (state != QWebEngineDownloadItem::DownloadInProgress && state != QWebEngineDownloadItem::DownloadInterrupted)) + return; + d->profile->browserContext()->resumeDownload(d->downloadId); } /*! @@ -206,12 +253,21 @@ quint32 QWebEngineDownloadItem::id() const /*! \fn QWebEngineDownloadItem::finished() - This signal is emitted whenever the download finishes. + This signal is emitted when the download finishes. \sa state(), isFinished() */ /*! + \fn QWebEngineDownloadItem::isPausedChanged(bool isPaused) + \since 5.10 + + This signal is emitted whenever \a isPaused changes. + + \sa pause(), isPaused() +*/ + +/*! \fn QWebEngineDownloadItem::stateChanged(DownloadState state) This signal is emitted whenever the download's \a state changes. @@ -407,7 +463,7 @@ void QWebEngineDownloadItem::setPath(QString path) } /*! - Returns whether this download is finished (not in progress). + Returns whether this download is finished (completed, cancelled, or non-resumable interrupted state). \sa finished(), state(), */ @@ -419,6 +475,18 @@ bool QWebEngineDownloadItem::isFinished() const } /*! + Returns whether this download is paused. + + \sa pause() +*/ + +bool QWebEngineDownloadItem::isPaused() const +{ + Q_D(const QWebEngineDownloadItem); + return d->downloadPaused; +} + +/*! Returns the format the web page will be saved in if this is a download request for a web page. \since 5.7 diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h index a4b6c08aa..2aca2bb2a 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.h +++ b/src/webenginewidgets/api/qwebenginedownloaditem.h @@ -120,6 +120,7 @@ public: QString path() const; void setPath(QString path); bool isFinished() const; + bool isPaused() const; SavePageFormat savePageFormat() const; void setSavePageFormat(SavePageFormat format); DownloadType type() const; @@ -129,11 +130,14 @@ public: public Q_SLOTS: void accept(); void cancel(); + void pause(); + void resume(); Q_SIGNALS: void finished(); void stateChanged(QWebEngineDownloadItem::DownloadState state); void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void isPausedChanged(bool isPaused); private: Q_DISABLE_COPY(QWebEngineDownloadItem) diff --git a/src/webenginewidgets/api/qwebenginedownloaditem_p.h b/src/webenginewidgets/api/qwebenginedownloaditem_p.h index 038332da3..da765e5c5 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem_p.h +++ b/src/webenginewidgets/api/qwebenginedownloaditem_p.h @@ -77,6 +77,7 @@ public: QString downloadPath; const QUrl downloadUrl; QString mimeType; + bool downloadPaused; qint64 totalBytes; qint64 receivedBytes; diff --git a/src/webenginewidgets/api/qwebenginehistory.h b/src/webenginewidgets/api/qwebenginehistory.h index 21ebbf41d..33d91d523 100644 --- a/src/webenginewidgets/api/qwebenginehistory.h +++ b/src/webenginewidgets/api/qwebenginehistory.h @@ -79,9 +79,7 @@ private: friend class QWebEngineHistoryPrivate; }; -#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineHistoryItem) -#endif class QWebEngineHistoryPrivate; class QWEBENGINEWIDGETS_EXPORT QWebEngineHistory { diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index ae6276fdc..438e3ea24 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -60,6 +60,7 @@ #include "render_widget_host_view_qt_delegate_widget.h" #include "web_contents_adapter.h" #include "web_engine_settings.h" +#include "qwebenginescript.h" #ifdef QT_UI_DELEGATES #include "ui/messagebubblewidget_p.h" @@ -100,13 +101,8 @@ static const int MaxTooltipLength = 1024; static bool printPdfDataOnPrinter(const QByteArray& data, QPrinter& printer) { if (!data.size()) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) qWarning("Failure to print on printer %ls: Print result data is empty.", qUtf16Printable(printer.printerName())); -#else - qWarning("Failure to print on printer %s: Print result data is empty.", - qPrintable(printer.printerName())); -#endif return false; } @@ -142,13 +138,8 @@ static bool printPdfDataOnPrinter(const QByteArray& data, QPrinter& printer) QPainter painter; if (!painter.begin(&printer)) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) qWarning("Failure to print on printer %ls: Could not open printer for painting.", qUtf16Printable(printer.printerName())); -#else - qWarning("Failure to print on printer %s: Could not open printer for painting.", - qPrintable(printer.printerName())); -#endif return false; } @@ -354,7 +345,6 @@ void QWebEnginePagePrivate::loadFinished(bool success, const QUrl &url, bool isE if (isErrorPage) { Q_ASSERT(settings->testAttribute(QWebEngineSettings::ErrorPageEnabled)); - Q_ASSERT(success); Q_EMIT q->loadFinished(false); return; } @@ -378,25 +368,14 @@ void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool succ void QWebEnginePagePrivate::focusContainer() { - if (view) + if (view) { + view->activateWindow(); view->setFocus(); + } } void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) { -#ifdef Q_OS_OSX - Q_Q(QWebEnginePage); - if (event->type() == QEvent::KeyPress) { - QWebEnginePage::WebAction action = editorActionForKeyEvent(event); - if (action != QWebEnginePage::NoWebAction) { - // Try triggering a registered short-cut - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event)) - return; - q->triggerAction(action); - return; - } - } -#endif if (view && view->parentWidget()) QGuiApplication::sendEvent(view->parentWidget(), event); } @@ -560,16 +539,20 @@ void QWebEnginePagePrivate::showColorDialog(QSharedPointer<ColorChooserControlle void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags requestFlags) { Q_Q(QWebEnginePage); - QWebEnginePage::Feature requestedFeature; - if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - requestedFeature = QWebEnginePage::MediaAudioVideoCapture; + QWebEnginePage::Feature feature; + if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && + requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) + feature = QWebEnginePage::MediaAudioVideoCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) - requestedFeature = QWebEnginePage::MediaAudioCapture; + feature = QWebEnginePage::MediaAudioCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - requestedFeature = QWebEnginePage::MediaVideoCapture; - else - return; - Q_EMIT q->featurePermissionRequested(securityOrigin, requestedFeature); + feature = QWebEnginePage::MediaVideoCapture; + else if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopAudioCapture) && + requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + feature = QWebEnginePage::DesktopAudioVideoCapture; + else // if (requestFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture)) + feature = QWebEnginePage::DesktopVideoCapture; + Q_EMIT q->featurePermissionRequested(securityOrigin, feature); } void QWebEnginePagePrivate::runGeolocationPermissionRequest(const QUrl &securityOrigin) @@ -1142,6 +1125,42 @@ QAction *QWebEnginePage::action(WebAction action) const case ViewSource: text = tr("&View Page Source"); break; + case ToggleBold: + text = tr("&Bold"); + break; + case ToggleItalic: + text = tr("&Italic"); + break; + case ToggleUnderline: + text = tr("&Underline"); + break; + case ToggleStrikethrough: + text = tr("&Strikethrough"); + break; + case AlignLeft: + text = tr("Align &Left"); + break; + case AlignCenter: + text = tr("Align &Center"); + break; + case AlignRight: + text = tr("Align &Right"); + break; + case AlignJustified: + text = tr("Align &Justified"); + break; + case Indent: + text = tr("&Indent"); + break; + case Outdent: + text = tr("&Outdent"); + break; + case InsertOrderedList: + text = tr("Insert &Ordered List"); + break; + case InsertUnorderedList: + text = tr("Insert &Unordered List"); + break; case NoWebAction: case WebActionCount: Q_UNREACHABLE(); @@ -1231,14 +1250,14 @@ void QWebEnginePage::triggerAction(WebAction action, bool) } break; case CopyLinkToClipboard: - if (menuData.linkUrl().isValid()) { - QString urlString = menuData.linkUrl().toString(QUrl::FullyEncoded); + if (!menuData.unfilteredLinkUrl().isEmpty()) { + QString urlString = menuData.unfilteredLinkUrl().toString(QUrl::FullyEncoded); QString title = menuData.linkText().toHtmlEscaped(); QMimeData *data = new QMimeData(); data->setText(urlString); QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>"); data->setHtml(html); - data->setUrls(QList<QUrl>() << menuData.linkUrl()); + data->setUrls(QList<QUrl>() << menuData.unfilteredLinkUrl()); qApp->clipboard()->setMimeData(data); } break; @@ -1347,6 +1366,42 @@ void QWebEnginePage::triggerAction(WebAction action, bool) // the viewSource() call after the QMenu's destruction. QTimer::singleShot(0, this, [d](){ d->adapter->viewSource(); }); break; + case ToggleBold: + runJavaScript(QStringLiteral("document.execCommand('bold');"), QWebEngineScript::ApplicationWorld); + break; + case ToggleItalic: + runJavaScript(QStringLiteral("document.execCommand('italic');"), QWebEngineScript::ApplicationWorld); + break; + case ToggleUnderline: + runJavaScript(QStringLiteral("document.execCommand('underline');"), QWebEngineScript::ApplicationWorld); + break; + case ToggleStrikethrough: + runJavaScript(QStringLiteral("document.execCommand('strikethrough');"), QWebEngineScript::ApplicationWorld); + break; + case AlignLeft: + runJavaScript(QStringLiteral("document.execCommand('justifyLeft');"), QWebEngineScript::ApplicationWorld); + break; + case AlignCenter: + runJavaScript(QStringLiteral("document.execCommand('justifyCenter');"), QWebEngineScript::ApplicationWorld); + break; + case AlignRight: + runJavaScript(QStringLiteral("document.execCommand('justifyRight');"), QWebEngineScript::ApplicationWorld); + break; + case AlignJustified: + runJavaScript(QStringLiteral("document.execCommand('justifyFull');"), QWebEngineScript::ApplicationWorld); + break; + case Indent: + runJavaScript(QStringLiteral("document.execCommand('indent');"), QWebEngineScript::ApplicationWorld); + break; + case Outdent: + runJavaScript(QStringLiteral("document.execCommand('outdent');"), QWebEngineScript::ApplicationWorld); + break; + case InsertOrderedList: + runJavaScript(QStringLiteral("document.execCommand('insertOrderedList');"), QWebEngineScript::ApplicationWorld); + break; + case InsertUnorderedList: + runJavaScript(QStringLiteral("document.execCommand('insertUnorderedList');"), QWebEngineScript::ApplicationWorld); + break; case NoWebAction: break; case WebActionCount: @@ -1401,35 +1456,36 @@ void QWebEnginePagePrivate::wasHidden() adapter->wasHidden(); } -bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData &data) +void QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData &data) { if (!view) - return false; + return; contextData.reset(); - QContextMenuEvent event(QContextMenuEvent::Mouse, data.position(), view->mapToGlobal(data.position())); switch (view->contextMenuPolicy()) { - case Qt::PreventContextMenu: - return false; case Qt::DefaultContextMenu: + { contextData = data; + QContextMenuEvent event(QContextMenuEvent::Mouse, data.position(), view->mapToGlobal(data.position())); view->contextMenuEvent(&event); - break; + return; + } case Qt::CustomContextMenu: contextData = data; Q_EMIT view->customContextMenuRequested(data.position()); - break; + return; case Qt::ActionsContextMenu: if (view->actions().count()) { + QContextMenuEvent event(QContextMenuEvent::Mouse, data.position(), view->mapToGlobal(data.position())); QMenu::exec(view->actions(), event.globalPos(), 0, view); - break; } - // fallthrough + return; + case Qt::PreventContextMenu: case Qt::NoContextMenu: - event.ignore(); - return false; + return; } - return true; + + Q_UNREACHABLE(); } void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) @@ -1621,7 +1677,7 @@ QMenu *QWebEnginePage::createStandardContextMenu() menu->addAction(QWebEnginePage::action(Unselect)); } - if (!contextMenuData.linkText().isEmpty() && contextMenuData.linkUrl().isValid()) { + if (!contextMenuData.linkText().isEmpty() && !contextMenuData.unfilteredLinkUrl().isEmpty()) { menu->addAction(QWebEnginePage::action(CopyLinkToClipboard)); } if (contextMenuData.mediaUrl().isValid()) { @@ -1668,37 +1724,58 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine Q_D(QWebEnginePage); if (policy == PermissionUnknown) return; - WebContentsAdapterClient::MediaRequestFlags flags = WebContentsAdapterClient::MediaNone; - switch (feature) { - case MediaAudioVideoCapture: - case MediaAudioCapture: - case MediaVideoCapture: - if (policy != PermissionUnknown) { - if (policy == PermissionDeniedByUser) - flags = WebContentsAdapterClient::MediaNone; - else { - if (feature == MediaAudioCapture) - flags = WebContentsAdapterClient::MediaAudioCapture; - else if (feature == MediaVideoCapture) - flags = WebContentsAdapterClient::MediaVideoCapture; - else - flags = WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaVideoCapture | WebContentsAdapterClient::MediaAudioCapture); - } - d->adapter->grantMediaAccessPermission(securityOrigin, flags); - } - d->adapter->grantMediaAccessPermission(securityOrigin, flags); - break; - case QWebEnginePage::Geolocation: - d->adapter->runGeolocationRequestCallback(securityOrigin, (policy == PermissionGrantedByUser) ? true : false); - break; - case MouseLock: - if (policy == PermissionGrantedByUser) + + const WebContentsAdapterClient::MediaRequestFlags audioVideoCaptureFlags( + WebContentsAdapterClient::MediaVideoCapture | + WebContentsAdapterClient::MediaAudioCapture); + const WebContentsAdapterClient::MediaRequestFlags desktopAudioVideoCaptureFlags( + WebContentsAdapterClient::MediaDesktopVideoCapture | + WebContentsAdapterClient::MediaDesktopAudioCapture); + + if (policy == PermissionGrantedByUser) { + switch (feature) { + case MediaAudioVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, audioVideoCaptureFlags); + break; + case MediaAudioCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaAudioCapture); + break; + case MediaVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaVideoCapture); + break; + case DesktopAudioVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, desktopAudioVideoCaptureFlags); + break; + case DesktopVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaDesktopVideoCapture); + break; + case Geolocation: + d->adapter->runGeolocationRequestCallback(securityOrigin, true); + break; + case MouseLock: d->adapter->grantMouseLockPermission(true); - else + break; + case Notifications: + break; + } + } else { // if (policy == PermissionDeniedByUser) + switch (feature) { + case MediaAudioVideoCapture: + case MediaAudioCapture: + case MediaVideoCapture: + case DesktopAudioVideoCapture: + case DesktopVideoCapture: + d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone); + break; + case Geolocation: + d->adapter->runGeolocationRequestCallback(securityOrigin, false); + break; + case MouseLock: d->adapter->grantMouseLockPermission(false); - break; - case Notifications: - break; + break; + case Notifications: + break; + } } } @@ -1725,6 +1802,25 @@ WebEngineSettings *QWebEnginePagePrivate::webEngineSettings() const return settings->d_func(); } +/*! + \since 5.10 + Downloads the resource from the location given by \a url to a local file. + + If \a filename is given, it is used as the suggested file name. + If it is relative, the file is saved in the standard download location with + the given name. + If it is a null or empty QString, the default file name is used. + + This will emit QWebEngineProfile::downloadRequested() after the download + has started. +*/ + +void QWebEnginePage::download(const QUrl& url, const QString& filename) +{ + Q_D(QWebEnginePage); + d->adapter->download(url, filename); +} + void QWebEnginePage::load(const QUrl& url) { Q_D(QWebEnginePage); @@ -2015,11 +2111,7 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &page Q_D(const QWebEnginePage); #if defined(ENABLE_PRINTING) if (d->currentPrinter) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); -#else - qWarning("Cannot print to PDF while at the same time printing on printer %s", qPrintable(d->currentPrinter->printerName())); -#endif return; } #endif // ENABLE_PRINTING @@ -2048,11 +2140,7 @@ void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &res #if defined(ENABLE_PDF) #if defined(ENABLE_PRINTING) if (d->currentPrinter) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); -#else - qWarning("Cannot print to PDF while at the same time printing on printer %s", qPrintable(d->currentPrinter->printerName())); -#endif d->m_callbacks.invokeEmpty(resultCallback); return; } @@ -2084,11 +2172,7 @@ void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback<bool> &re #if defined(ENABLE_PDF) #if defined(ENABLE_PRINTING) if (d->currentPrinter) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) qWarning("Cannot print page on printer %ls: Already printing on %ls.", qUtf16Printable(printer->printerName()), qUtf16Printable(d->currentPrinter->printerName())); -#else - qWarning("Cannot print page on printer %s: Already printing on %s.", qPrintable(printer->printerName()), qPrintable(d->currentPrinter->printerName())); -#endif d->m_callbacks.invokeDirectly(resultCallback, false); return; } diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 5619639c7..295527e74 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -128,6 +128,22 @@ public: SavePage, OpenLinkInNewBackgroundTab, ViewSource, + + ToggleBold, + ToggleItalic, + ToggleUnderline, + ToggleStrikethrough, + + AlignLeft, + AlignCenter, + AlignRight, + AlignJustified, + Indent, + Outdent, + + InsertOrderedList, + InsertUnorderedList, + WebActionCount }; Q_ENUM(WebAction) @@ -172,7 +188,9 @@ public: MediaAudioCapture = 2, MediaVideoCapture, MediaAudioVideoCapture, - MouseLock + MouseLock, + DesktopVideoCapture, + DesktopAudioVideoCapture }; Q_ENUM(Feature) @@ -234,6 +252,7 @@ public: void load(const QUrl &url); void load(const QWebEngineHttpRequest &request); + void download(const QUrl &url, const QString &filename = QString()); void setHtml(const QString &html, const QUrl &baseUrl = QUrl()); void setContent(const QByteArray &data, const QString &mimeType = QString(), const QUrl &baseUrl = QUrl()); diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index ec84f05e1..12bad1351 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -107,7 +107,7 @@ public: virtual bool isBeingAdopted() Q_DECL_OVERRIDE; virtual void close() Q_DECL_OVERRIDE; virtual void windowCloseRejected() Q_DECL_OVERRIDE; - virtual bool contextMenuRequested(const QtWebEngineCore::WebEngineContextMenuData &data) Q_DECL_OVERRIDE; + virtual void contextMenuRequested(const QtWebEngineCore::WebEngineContextMenuData &data) Q_DECL_OVERRIDE; virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) Q_DECL_OVERRIDE; virtual void requestFullScreenMode(const QUrl &origin, bool fullscreen) Q_DECL_OVERRIDE; virtual bool isFullScreenMode() const Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index b39512d60..2897d9798 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -143,7 +143,7 @@ using QtWebEngineCore::BrowserContextAdapter; will be deleted immediately after the signal emission. This signal cannot be used with a queued connection. - \sa QWebEngineDownloadItem + \sa QWebEngineDownloadItem, QWebEnginePage::download() */ QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext) @@ -151,7 +151,7 @@ QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCor , m_scriptCollection(new QWebEngineScriptCollection(new QWebEngineScriptCollectionPrivate(browserContext->userResourceController()))) , m_browserContext(new QWebEngineBrowserContext(browserContext, this)) { - m_settings->d_ptr->initDefaults(browserContext->isOffTheRecord()); + m_settings->d_ptr->initDefaults(); } QWebEngineProfilePrivate::~QWebEngineProfilePrivate() @@ -174,12 +174,6 @@ QSharedPointer<QtWebEngineCore::BrowserContextAdapter> QWebEngineProfilePrivate: return m_browserContext ? m_browserContext->browserContextRef : nullptr; } -void QWebEngineProfilePrivate::cancelDownload(quint32 downloadId) -{ - if (m_browserContext) - m_browserContext->browserContextRef->cancelDownload(downloadId); -} - void QWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) { m_ongoingDownloads.remove(downloadId); @@ -581,34 +575,8 @@ QWebEngineProfile *QWebEngineProfile::defaultProfile() For example, the language \c en-US will load the \c en-US.bdic dictionary file. - Qt WebEngine checks for the \c qtwebengine_dictionaries subdirectory - first in the local directory and if it is not found, in the Qt - installation directory. - - On macOS, depending on how Qt WebEngine is configured at build time, there are two possibilities - how spellchecking data is found: - - \list - \li Hunspell dictionaries (default) - .bdic dictionaries are used, just like on other - platforms - \li Native dictionaries - the macOS spellchecking APIs are used (which means the results - will depend on the installed OS dictionaries) - \endlist - - Thus, in the macOS Hunspell case, Qt WebEngine will look in the \e qtwebengine_dictionaries - subdirectory located inside the application bundle \c Resources directory, and also in the - \c Resources directory located inside the Qt framework bundle. - - To summarize, in case of Hunspell usage, the following paths are considered: - - \list - \li QCoreApplication::applicationDirPath()/qtwebengine_dictionaries - or QCoreApplication::applicationDirPath()/../Contents/Resources/qtwebengine_dictionaries - (on macOS) - \li [QLibraryInfo::DataPath]/qtwebengine_dictionaries - or path/to/QtWebEngineCore.framework/Resources/qtwebengine_dictionaries (Qt framework - bundle on macOS) - \endlist + See the \l {Spellchecker}{Spellchecker feature documentation} for how + dictionary files are searched. For more information about how to compile \c .bdic dictionaries, see the \l{WebEngine Widgets Spellchecker Example}{Spellchecker Example}. @@ -681,7 +649,8 @@ static bool checkInternalScheme(const QByteArray &scheme) static QSet<QByteArray> internalSchemes; if (internalSchemes.isEmpty()) { internalSchemes << QByteArrayLiteral("qrc") << QByteArrayLiteral("data") << QByteArrayLiteral("blob") - << QByteArrayLiteral("http") << QByteArrayLiteral("ftp") << QByteArrayLiteral("javascript"); + << QByteArrayLiteral("http") << QByteArrayLiteral("https") << QByteArrayLiteral("ftp") + << QByteArrayLiteral("javascript"); } return internalSchemes.contains(scheme); } diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h index 8e7b0aab8..8d9e5011f 100644 --- a/src/webenginewidgets/api/qwebengineprofile_p.h +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -79,7 +79,6 @@ public: QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext() const; QWebEngineSettings *settings() const { return m_settings; } - void cancelDownload(quint32 downloadId); void downloadDestroyed(quint32 downloadId); void downloadRequested(DownloadItemInfo &info) Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/api/qwebenginescript.h b/src/webenginewidgets/api/qwebenginescript.h index 34c13e4b7..e3f65ec59 100644 --- a/src/webenginewidgets/api/qwebenginescript.h +++ b/src/webenginewidgets/api/qwebenginescript.h @@ -102,9 +102,7 @@ private: QSharedDataPointer<QtWebEngineCore::UserScript> d; }; -#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineScript) -#endif #ifndef QT_NO_DEBUG_STREAM QWEBENGINEWIDGETS_EXPORT QDebug operator<<(QDebug, const QWebEngineScript &); diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index 65c77a54d..1def61cb6 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -97,6 +97,10 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web return WebEngineSettings::AllowRunningInsecureContent; case QWebEngineSettings::AllowGeolocationOnInsecureOrigins: return WebEngineSettings::AllowGeolocationOnInsecureOrigins; + case QWebEngineSettings::AllowWindowActivationFromJavaScript: + return WebEngineSettings::AllowWindowActivationFromJavaScript; + case QWebEngineSettings::ShowScrollBars: + return WebEngineSettings::ShowScrollBars; default: return WebEngineSettings::UnsupportedInCoreSettings; diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index 73995a457..470609227 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -89,7 +89,9 @@ public: FocusOnNavigationEnabled, PrintElementBackgrounds, AllowRunningInsecureContent, - AllowGeolocationOnInsecureOrigins + AllowGeolocationOnInsecureOrigins, + AllowWindowActivationFromJavaScript, + ShowScrollBars }; enum FontSize { diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index c03d9fde6..7ea451fc5 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -316,9 +316,15 @@ void QWebEngineView::setZoomFactor(qreal factor) */ bool QWebEngineView::event(QEvent *ev) { - // We swallow spontaneous contextMenu events and synthethize those back later on when we get the - // HandleContextMenu callback from chromium if (ev->type() == QEvent::ContextMenu) { + if (contextMenuPolicy() == Qt::NoContextMenu) { + // We forward the contextMenu event to the parent widget + ev->ignore(); + return false; + } + + // We swallow spontaneous contextMenu events and synthethize those back later on when we get the + // HandleContextMenu callback from chromium ev->accept(); return true; } diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index b7c876ddd..23b280b6d 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -89,8 +89,8 @@ \c MainWorld. The \l {QWebEngineSettings::FocusOnNavigationEnabled} {FocusOnNavigationEnabled} setting can be - used to stop the view associated with the page from automatically receiving focus when a - navigation operation occurs (like loading or reloading a page or navigating through history). + used to make the view associated with the page automatically receive focus when a navigation + operation occurs (like loading or reloading a page or navigating through history). */ /*! @@ -158,6 +158,46 @@ the web page on disk. (Added in Qt 5.7) \value ViewSource Show the source of the current page in a new tab. (Added in Qt 5.8) + \value ToggleBold + Toggles boldness for the selection or at the cursor position. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value ToggleItalic + Toggles italics for the selection or at the cursor position. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value ToggleUnderline + Toggles underlining of the selection or at the cursor position. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value ToggleStrikethrough + Toggles striking through the selection or at the cursor position. + Requires \c contenteditable="true". (Added in Qt 5.10) + + \value AlignLeft + Aligns the lines containing the selection or the cursor to the left. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value AlignCenter + Aligns the lines containing the selection or the cursor at the center. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value AlignRight + Aligns the lines containing the selection or the cursor to the right. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value AlignJustified + Stretches the lines containing the selection or the cursor so that each + line has equal width. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value Indent + Indents the lines containing the selection or the cursor. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value Outdent + Outdents the lines containing the selection or the cursor. + Requires \c contenteditable="true". (Added in Qt 5.10) + + \value InsertOrderedList + Inserts an ordered list at the current cursor position, deleting the current selection. + Requires \c contenteditable="true". (Added in Qt 5.10) + \value InsertUnorderedList + Inserts an unordered list at the current cursor position, + deleting the current selection. + Requires \c contenteditable="true". (Added in Qt 5.10) \omitvalue WebActionCount */ @@ -246,6 +286,11 @@ \value MouseLock Mouse locking, which locks the mouse pointer to the web view and is typically used in games. + \value DesktopVideoCapture + Video output capture, that is, the capture of the user's display, + for screen sharing purposes for example. (Added in Qt 5.10) + \value DesktopAudioVideoCapture + Both audio and video output capture. (Added in Qt 5.10) \sa featurePermissionRequested(), featurePermissionRequestCanceled(), setFeaturePermission(), PermissionPolicy @@ -505,6 +550,9 @@ This signal is emitted whenever the selection changes, either interactively or programmatically. For example, by calling triggerAction() with a selection action. + \note When using the mouse to select text by left-clicking and dragging, the signal will be + emitted for each new character selected, and not upon releasing the left mouse button. + \sa selectedText() */ diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc index d26babd5a..3fe87082a 100644 --- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc @@ -148,7 +148,7 @@ Gives focus to the view associated with the page, whenever a navigation operation occurs (load, stop, reload, reload and bypass cache, forward, backward, set content, and so on). - Enabled by default. (Added in Qt 5.8) + Disabled by default. (Added in Qt 5.8) \value PrintElementBackgrounds Turns on printing of CSS backgrounds when printing a web page. Enabled by default. (Added in Qt 5.8) @@ -162,6 +162,13 @@ Geolocation features. This provides an override to allow non secure origins to access Geolocation again. Disabled by default. (Added in Qt 5.9) + \value AllowWindowActivationFromJavaScript + Allows activating windows by using the window.focus() JavaScript + method. Disabled by default. + (Added in Qt 5.10) + \value ShowScrollBars + Shows scroll bars. + Enabled by default. (Added in Qt 5.10) */ diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc index 9de0609b7..18d139c00 100644 --- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc @@ -77,7 +77,7 @@ new windows, such as pop-up windows, you can subclass QWebEngineView and reimplement the createWindow() function. - \sa {WebEngine Demo Browser Example}, {WebEngine Content Manipulation Example}, {WebEngine Markdown Editor Example} + \sa {WebEngine Widgets Simple Browser Example}, {WebEngine Content Manipulation Example}, {WebEngine Markdown Editor Example} */ @@ -365,6 +365,9 @@ This signal is emitted whenever the selection changes. + \note When using the mouse to select text by left-clicking and dragging, the signal will be + emitted for each new character selected, and not upon releasing the left mouse button. + \sa selectedText() */ 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 d56f644d3..8dd5c158b 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -51,10 +51,6 @@ #include <QWindow> #include <private/qquickwindow_p.h> -#if (QT_VERSION < QT_VERSION_CHECK(5, 8, 0)) -#include <QSGSimpleRectNode> -#include <QSGSimpleTextureNode> -#endif #include <private/qwidget_p.h> namespace QtWebEngineCore { @@ -71,7 +67,8 @@ protected: bool event(QEvent *event) override { if (event->type() == QEvent::ShortcutOverride) - return m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event)); + return m_client->forwardEvent(event); + return QQuickItem::event(event); } void focusInEvent(QFocusEvent *event) override @@ -112,11 +109,10 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende , m_client(client) , m_rootItem(new RenderWidgetHostViewQuickItem(client)) , m_isPopup(false) + , m_isPasswordInput(false) { setFocusPolicy(Qt::StrongFocus); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) - QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); @@ -142,15 +138,30 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende // Make sure the OpenGL profile of the QQuickWidget matches the shared context profile. if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) { - format.setMajorVersion(sharedFormat.majorVersion()); - format.setMinorVersion(sharedFormat.minorVersion()); - format.setProfile(sharedFormat.profile()); + int major; + int minor; + QSurfaceFormat::OpenGLContextProfile profile; + +#ifdef Q_OS_MACOS + // Due to QTBUG-63180, requesting the sharedFormat.majorVersion() on macOS will lead to + // a failed creation of QQuickWidget shared context. Thus make sure to request the + // major version specified in the defaultFormat instead. + major = defaultFormat.majorVersion(); + minor = defaultFormat.minorVersion(); + profile = defaultFormat.profile(); +#else + major = sharedFormat.majorVersion(); + minor = sharedFormat.minorVersion(); + profile = sharedFormat.profile(); +#endif + format.setMajorVersion(major); + format.setMinorVersion(minor); + format.setProfile(profile); } } setFormat(format); #endif -#endif setMouseTracking(true); setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_OpaquePaintEvent); @@ -297,30 +308,17 @@ QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer() QSGInternalImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode() { QSGRenderContext *renderContext = QQuickWindowPrivate::get(quickWindow())->context; -#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) return renderContext->sceneGraphContext()->createInternalImageNode(); -#else - return renderContext->sceneGraphContext()->createImageNode(); -#endif } QSGTextureNode *RenderWidgetHostViewQtDelegateWidget::createTextureNode() { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) return quickWindow()->createImageNode(); -#else - return new QSGSimpleTextureNode(); -#endif } QSGRectangleNode *RenderWidgetHostViewQtDelegateWidget::createRectangleNode() { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) return quickWindow()->createRectangleNode(); -#else - QSGRenderContext *renderContext = QQuickWindowPrivate::get(quickWindow())->context; - return renderContext->sceneGraphContext()->createRectangleNode(); -#endif } void RenderWidgetHostViewQtDelegateWidget::update() @@ -344,12 +342,14 @@ void RenderWidgetHostViewQtDelegateWidget::move(const QPoint &screenPos) QQuickWidget::move(screenPos); } -void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVisible) +void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVisible, bool passwordInput) { - if (qApp->inputMethod()->isVisible() == editorVisible) + if (qApp->inputMethod()->isVisible() == editorVisible && m_isPasswordInput == passwordInput) return; - QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, editorVisible); + QQuickWidget::setAttribute(Qt::WA_InputMethodEnabled, editorVisible && !passwordInput); + m_isPasswordInput = passwordInput; + qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); qApp->inputMethod()->setVisible(editorVisible); } @@ -449,10 +449,6 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) case QEvent::FocusOut: // We forward focus events later, once they have made it to the m_rootItem. return QQuickWidget::event(event); - case QEvent::ShortcutOverride: - if (m_client->handleShortcutOverrideEvent(static_cast<QKeyEvent *>(event))) - return true; - break; case QEvent::DragEnter: case QEvent::DragLeave: case QEvent::DragMove: diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index fb33c55c7..f3e9da2cc 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -74,7 +74,7 @@ public: virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; - virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; + virtual void inputMethodStateChanged(bool editorVisible, bool passwordInput) Q_DECL_OVERRIDE; virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE; virtual void setClearColor(const QColor &color) Q_DECL_OVERRIDE; @@ -94,6 +94,7 @@ private: RenderWidgetHostViewQtDelegateClient *m_client; QScopedPointer<QQuickItem> m_rootItem; bool m_isPopup; + bool m_isPasswordInput; QColor m_clearColor; QPoint m_lastGlobalPos; QList<QMetaObject::Connection> m_windowConnections; diff --git a/src/webenginewidgets/ui/messagebubblewidget.cpp b/src/webenginewidgets/ui/messagebubblewidget.cpp index 4a53a421f..70dada0c4 100644 --- a/src/webenginewidgets/ui/messagebubblewidget.cpp +++ b/src/webenginewidgets/ui/messagebubblewidget.cpp @@ -41,6 +41,7 @@ #include "api/qwebengineview.h" +#include <qglobal.h> #include <QBitmap> #include <QHBoxLayout> #include <QIcon> diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index ad79c1ef9..540c4d538 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -1,3 +1,5 @@ +QT_FOR_CONFIG += webengine-private + TARGET = QtWebEngineWidgets # For our export macros @@ -42,23 +44,20 @@ HEADERS = \ api/qwebengineview_p.h \ render_widget_host_view_qt_delegate_widget.h -!contains(WEBENGINE_CONFIG, no_ui_delegates) { +qtConfig(webengine-ui-delegates) { SOURCES += ui/messagebubblewidget.cpp HEADERS += ui/messagebubblewidget_p.h DEFINES += QT_UI_DELEGATES } -contains(WEBENGINE_CONFIG, use_spellchecker) { +qtConfig(webengine-spellchecker) { DEFINES += ENABLE_SPELLCHECK } -use?(printing) { +qtConfig(webengine-printing-and-pdf) { DEFINES += ENABLE_PRINTING - QT += printsupport -} - -use?(pdf) { DEFINES += ENABLE_PDF + QT += printsupport } load(qt_module) |