diff options
Diffstat (limited to 'src/webenginewidgets/api/qwebenginepage.cpp')
-rw-r--r-- | src/webenginewidgets/api/qwebenginepage.cpp | 2845 |
1 files changed, 0 insertions, 2845 deletions
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp deleted file mode 100644 index 6fb3c5c43..000000000 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ /dev/null @@ -1,2845 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwebenginepage.h" -#include "qwebenginepage_p.h" - -#include "authentication_dialog_controller.h" -#include "profile_adapter.h" -#include "certificate_error_controller.h" -#include "color_chooser_controller.h" -#include "favicon_manager.h" -#include "find_text_helper.h" -#include "file_picker_controller.h" -#include "javascript_dialog_controller.h" -#if QT_CONFIG(webengine_printing_and_pdf) -#include "printer_worker.h" -#endif -#include "qwebenginecertificateerror.h" -#include "qwebenginefindtextresult.h" -#include "qwebenginefullscreenrequest.h" -#include "qwebenginehistory.h" -#include "qwebenginehistory_p.h" -#include "qwebenginenotification.h" -#include "qwebengineprofile.h" -#include "qwebengineprofile_p.h" -#include "qwebenginequotarequest.h" -#include "qwebengineregisterprotocolhandlerrequest.h" -#include "qwebenginescriptcollection_p.h" -#include "qwebenginesettings.h" -#include "qwebengineview.h" -#include "qwebengineview_p.h" -#include "user_notification_controller.h" -#include "render_widget_host_view_qt_delegate_widget.h" -#include "web_contents_adapter.h" -#include "web_engine_settings.h" -#include "qwebenginescript.h" - -#include <QAction> -#include <QApplication> -#include <QAuthenticator> -#include <QClipboard> -#if QT_CONFIG(colordialog) -#include <QColorDialog> -#endif -#include <QContextMenuEvent> -#if QT_CONFIG(filedialog) -#include <QFileDialog> -#endif -#include <QKeyEvent> -#include <QIcon> -#if QT_CONFIG(inputdialog) -#include <QInputDialog> -#endif -#include <QLayout> -#include <QLoggingCategory> -#if QT_CONFIG(menu) -#include <QMenu> -#endif -#if QT_CONFIG(messagebox) -#include <QMessageBox> -#endif -#include <QMimeData> -#if QT_CONFIG(webengine_printing_and_pdf) -#include <QPrinter> -#include <QThread> -#endif -#include <QStandardPaths> -#include <QStyle> -#include <QTimer> -#include <QUrl> - -QT_BEGIN_NAMESPACE - -using namespace QtWebEngineCore; - -static const int MaxTooltipLength = 1024; - -static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::WindowOpenDisposition disposition) -{ - switch (disposition) { - case WebContentsAdapterClient::NewForegroundTabDisposition: - return QWebEnginePage::WebBrowserTab; - case WebContentsAdapterClient::NewBackgroundTabDisposition: - return QWebEnginePage::WebBrowserBackgroundTab; - case WebContentsAdapterClient::NewPopupDisposition: - return QWebEnginePage::WebDialog; - case WebContentsAdapterClient::NewWindowDisposition: - return QWebEnginePage::WebBrowserWindow; - default: - Q_UNREACHABLE(); - } -} - -QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) - : adapter(QSharedPointer<WebContentsAdapter>::create()) - , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this))) - , profile(_profile ? _profile : QWebEngineProfile::defaultProfile()) - , settings(new QWebEngineSettings(profile->settings())) - , view(0) - , isLoading(false) - , scriptCollection(new QWebEngineScriptCollectionPrivate(profileAdapter()->userResourceController(), adapter)) - , m_isBeingAdopted(false) - , m_backgroundColor(Qt::white) - , fullscreenMode(false) - , webChannel(nullptr) - , webChannelWorldId(QWebEngineScript::MainWorld) - , defaultAudioMuted(false) - , defaultZoomFactor(1.0) -#if QT_CONFIG(webengine_printing_and_pdf) - , currentPrinter(nullptr) -#endif -{ - memset(actions, 0, sizeof(actions)); - - qRegisterMetaType<QWebEngineQuotaRequest>(); - qRegisterMetaType<QWebEngineRegisterProtocolHandlerRequest>(); - qRegisterMetaType<QWebEngineFindTextResult>(); - - // See setVisible(). - wasShownTimer.setSingleShot(true); - QObject::connect(&wasShownTimer, &QTimer::timeout, [this](){ - ensureInitialized(); - }); - - profile->d_ptr->addWebContentsAdapterClient(this); -} - -QWebEnginePagePrivate::~QWebEnginePagePrivate() -{ - delete history; - delete settings; - profile->d_ptr->removeWebContentsAdapterClient(this); -} - -RenderWidgetHostViewQtDelegate *QWebEnginePagePrivate::CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) -{ - // Set the QWebEngineView as the parent for a popup delegate, so that the new popup window - // responds properly to clicks in case the QWebEngineView is inside a modal QDialog. Setting the - // parent essentially notifies the OS that the popup window is part of the modal session, and - // should allow interaction. - // The new delegate will not be deleted by the parent view though, because we unset the parent - // when the parent is destroyed. The delegate will be destroyed by Chromium when the popup is - // dismissed. - return new RenderWidgetHostViewQtDelegateWidget(client, this->view); -} - -void QWebEnginePagePrivate::initializationFinished() -{ - if (m_backgroundColor != Qt::white) - adapter->setBackgroundColor(m_backgroundColor); -#if QT_CONFIG(webengine_webchannel) - if (webChannel) - adapter->setWebChannel(webChannel, webChannelWorldId); -#endif - if (defaultAudioMuted != adapter->isAudioMuted()) - adapter->setAudioMuted(defaultAudioMuted); - if (!qFuzzyCompare(adapter->currentZoomFactor(), defaultZoomFactor)) - adapter->setZoomFactor(defaultZoomFactor); - if (view) - adapter->setVisible(view->isVisible()); - - scriptCollection.d->initializationFinished(adapter); - - m_isBeingAdopted = false; -} - -void QWebEnginePagePrivate::titleChanged(const QString &title) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->titleChanged(title); -} - -void QWebEnginePagePrivate::urlChanged() -{ - Q_Q(QWebEnginePage); - QUrl qurl = adapter->activeUrl(); - if (url != qurl) { - url = qurl; - Q_EMIT q->urlChanged(qurl); - } -} - -void QWebEnginePagePrivate::iconChanged(const QUrl &url) -{ - Q_Q(QWebEnginePage); - if (iconUrl == url) - return; - iconUrl = url; - Q_EMIT q->iconUrlChanged(iconUrl); - Q_EMIT q->iconChanged(adapter->faviconManager()->getIcon()); -} - -void QWebEnginePagePrivate::loadProgressChanged(int progress) -{ - Q_Q(QWebEnginePage); - QTimer::singleShot(0, q, [q, progress] () { Q_EMIT q->loadProgress(progress); }); -} - -void QWebEnginePagePrivate::didUpdateTargetURL(const QUrl &hoveredUrl) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->linkHovered(hoveredUrl.toString()); -} - -void QWebEnginePagePrivate::selectionChanged() -{ - Q_Q(QWebEnginePage); - QTimer::singleShot(0, q, [this, q]() { - updateEditActions(); - Q_EMIT q->selectionChanged(); - }); -} - -void QWebEnginePagePrivate::recentlyAudibleChanged(bool recentlyAudible) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->recentlyAudibleChanged(recentlyAudible); -} - -void QWebEnginePagePrivate::renderProcessPidChanged(qint64 pid) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->renderProcessPidChanged(pid); -} - -QRectF QWebEnginePagePrivate::viewportRect() const -{ - return view ? view->rect() : QRectF(); -} - -QColor QWebEnginePagePrivate::backgroundColor() const -{ - return m_backgroundColor; -} - -void QWebEnginePagePrivate::loadStarted(const QUrl &provisionalUrl, bool isErrorPage) -{ - Q_UNUSED(provisionalUrl); - Q_Q(QWebEnginePage); - - if (isErrorPage) - return; - - isLoading = true; - m_certificateErrorControllers.clear(); - QTimer::singleShot(0, q, &QWebEnginePage::loadStarted); -} - -void QWebEnginePagePrivate::loadFinished(bool success, const QUrl &url, bool isErrorPage, int errorCode, const QString &errorDescription) -{ - Q_Q(QWebEnginePage); - Q_UNUSED(url); - Q_UNUSED(errorCode); - Q_UNUSED(errorDescription); - - if (isErrorPage) { - Q_ASSERT(settings->testAttribute(QWebEngineSettings::ErrorPageEnabled)); - QTimer::singleShot(0, q, [q](){ - emit q->loadFinished(false); - }); - return; - } - - isLoading = false; - // Delay notifying failure until the error-page is done loading. - // Error-pages are not loaded on failures due to abort. - if (success || errorCode == -3 /* ERR_ABORTED*/ || !settings->testAttribute(QWebEngineSettings::ErrorPageEnabled)) { - QTimer::singleShot(0, q, [q, success](){ - emit q->loadFinished(success); - }); - } -} - -void QWebEnginePagePrivate::didPrintPageToPdf(const QString &filePath, bool success) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->pdfPrintingFinished(filePath, success); -} - -void QWebEnginePagePrivate::focusContainer() -{ - if (view) { - view->activateWindow(); - view->setFocus(); - } -} - -void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event) -{ - if (view && view->parentWidget()) - QGuiApplication::sendEvent(view->parentWidget(), event); -} - -QSharedPointer<WebContentsAdapter> -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) - return nullptr; - - if (!newWebContents->webContents()) - return newPage->d_func()->adapter; // Reuse existing adapter - - // Mark the new page as being in the process of being adopted, so that a second mouse move event - // sent by newWebContents->initialize() gets filtered in RenderWidgetHostViewQt::forwardEvent. - // The first mouse move event is being sent by q->createWindow(). This is necessary because - // Chromium does not get a mouse move acknowledgment message between the two events, and - // InputRouterImpl::ProcessMouseAck is not executed, thus all subsequent mouse move events - // get coalesced together, and don't get processed at all. - // The mouse move events are actually sent as a result of show() being called on - // RenderWidgetHostViewQtDelegateWidget, both when creating the window and when initialize is - // called. - newPage->d_func()->m_isBeingAdopted = true; - - // Overwrite the new page's WebContents with ours. - newPage->d_func()->adapter = newWebContents; - newWebContents->setClient(newPage->d_func()); - - if (!initialGeometry.isEmpty()) - emit newPage->geometryChangeRequested(initialGeometry); - - return newWebContents; -} - -bool QWebEnginePagePrivate::isBeingAdopted() -{ - return m_isBeingAdopted; -} - -void QWebEnginePagePrivate::close() -{ - Q_Q(QWebEnginePage); - Q_EMIT q->windowCloseRequested(); -} - -void QWebEnginePagePrivate::windowCloseRejected() -{ - // Do nothing for now. -} - -void QWebEnginePagePrivate::didRunJavaScript(quint64 requestId, const QVariant& result) -{ - m_callbacks.invoke(requestId, result); -} - -void QWebEnginePagePrivate::didFetchDocumentMarkup(quint64 requestId, const QString& result) -{ - m_callbacks.invoke(requestId, result); -} - -void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const QString& result) -{ - m_callbacks.invoke(requestId, result); -} - -void QWebEnginePagePrivate::didPrintPage(quint64 requestId, QSharedPointer<QByteArray> result) -{ -#if QT_CONFIG(webengine_printing_and_pdf) - Q_Q(QWebEnginePage); - - // If no currentPrinter is set that means that were printing to PDF only. - if (!currentPrinter) { - if (!result.data()) - return; - m_callbacks.invoke(requestId, *(result.data())); - return; - } - - QThread *printerThread = new QThread; - QObject::connect(printerThread, &QThread::finished, printerThread, &QThread::deleteLater); - printerThread->start(); - - PrinterWorker *printerWorker = new PrinterWorker(result, currentPrinter); - QObject::connect(printerWorker, &PrinterWorker::resultReady, q, [requestId, this](bool success) { - currentPrinter = nullptr; - m_callbacks.invoke(requestId, success); - }); - - QObject::connect(printerWorker, &PrinterWorker::resultReady, printerThread, &QThread::quit); - QObject::connect(printerThread, &QThread::finished, printerWorker, &PrinterWorker::deleteLater); - - printerWorker->moveToThread(printerThread); - QMetaObject::invokeMethod(printerWorker, "print"); - -#else - // we should never enter this branch, but just for safe-keeping... - Q_UNUSED(result); - m_callbacks.invoke(requestId, QByteArray()); -#endif -} - -bool QWebEnginePagePrivate::passOnFocus(bool reverse) -{ - if (view) - return view->focusNextPrevChild(!reverse); - return false; -} - -void QWebEnginePagePrivate::authenticationRequired(QSharedPointer<AuthenticationDialogController> controller) -{ - Q_Q(QWebEnginePage); - QAuthenticator networkAuth; - networkAuth.setRealm(controller->realm()); - - if (controller->isProxy()) - Q_EMIT q->proxyAuthenticationRequired(controller->url(), &networkAuth, controller->host()); - else - Q_EMIT q->authenticationRequired(controller->url(), &networkAuth); - - // Authentication has been cancelled - if (networkAuth.isNull()) { - controller->reject(); - return; - } - - controller->accept(networkAuth.user(), networkAuth.password()); -} - -void QWebEnginePagePrivate::releaseProfile() -{ - qWarning("Release of profile requested but WebEnginePage still not deleted. Expect troubles !"); - // this is not the way to go, but might avoid the crash if user code does not make any calls to page. - delete q_ptr->d_ptr.take(); -} - -void QWebEnginePagePrivate::showColorDialog(QSharedPointer<ColorChooserController> controller) -{ -#if QT_CONFIG(colordialog) - QColorDialog *dialog = new QColorDialog(controller.data()->initialColor(), view); - - QColorDialog::connect(dialog, SIGNAL(colorSelected(QColor)), controller.data(), SLOT(accept(QColor))); - QColorDialog::connect(dialog, SIGNAL(rejected()), controller.data(), SLOT(reject())); - - // Delete when done - QColorDialog::connect(dialog, SIGNAL(colorSelected(QColor)), dialog, SLOT(deleteLater())); - QColorDialog::connect(dialog, SIGNAL(rejected()), dialog, SLOT(deleteLater())); - - dialog->open(); -#else - Q_UNUSED(controller); -#endif -} - -void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags requestFlags) -{ - Q_Q(QWebEnginePage); - QWebEnginePage::Feature feature; - if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && - requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QWebEnginePage::MediaAudioVideoCapture; - else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) - feature = QWebEnginePage::MediaAudioCapture; - else if (requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - 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); -} - -static QWebEnginePage::Feature toFeature(QtWebEngineCore::ProfileAdapter::PermissionType type) -{ - switch (type) { - case QtWebEngineCore::ProfileAdapter::NotificationPermission: - return QWebEnginePage::Notifications; - case QtWebEngineCore::ProfileAdapter::GeolocationPermission: - return QWebEnginePage::Geolocation; - default: - break; - } - Q_UNREACHABLE(); - return QWebEnginePage::Feature(-1); -} - -void QWebEnginePagePrivate::runFeaturePermissionRequest(QtWebEngineCore::ProfileAdapter::PermissionType permission, const QUrl &securityOrigin) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->featurePermissionRequested(securityOrigin, toFeature(permission)); -} - -void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock); -} - -void QWebEnginePagePrivate::runQuotaRequest(QWebEngineQuotaRequest request) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->quotaRequested(request); -} - -void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest request) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->registerProtocolHandlerRequested(request); -} - -QObject *QWebEnginePagePrivate::accessibilityParentObject() -{ - return view; -} - -void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const -{ -#ifdef QT_NO_ACTION - Q_UNUSED(action) -#else - QAction *a = actions[action]; - if (!a) - return; - - bool enabled = true; - - switch (action) { - case QWebEnginePage::Back: - enabled = adapter->canGoToOffset(-1); - break; - case QWebEnginePage::Forward: - enabled = adapter->canGoToOffset(1); - break; - case QWebEnginePage::Stop: - enabled = isLoading; - break; - case QWebEnginePage::Reload: - case QWebEnginePage::ReloadAndBypassCache: - enabled = !isLoading; - break; - case QWebEnginePage::ViewSource: - enabled = adapter->canViewSource(); - break; - case QWebEnginePage::Cut: - case QWebEnginePage::Copy: - case QWebEnginePage::Unselect: - enabled = adapter->hasFocusedFrame() && !adapter->selectedText().isEmpty(); - break; - case QWebEnginePage::Paste: - case QWebEnginePage::Undo: - case QWebEnginePage::Redo: - case QWebEnginePage::SelectAll: - case QWebEnginePage::PasteAndMatchStyle: - enabled = adapter->hasFocusedFrame(); - break; - default: - break; - } - - a->setEnabled(enabled); -#endif // QT_NO_ACTION -} - -void QWebEnginePagePrivate::updateNavigationActions() -{ - updateAction(QWebEnginePage::Back); - updateAction(QWebEnginePage::Forward); - updateAction(QWebEnginePage::Stop); - updateAction(QWebEnginePage::Reload); - updateAction(QWebEnginePage::ReloadAndBypassCache); - updateAction(QWebEnginePage::ViewSource); -} - -void QWebEnginePagePrivate::updateEditActions() -{ - updateAction(QWebEnginePage::Cut); - updateAction(QWebEnginePage::Copy); - updateAction(QWebEnginePage::Paste); - updateAction(QWebEnginePage::Undo); - updateAction(QWebEnginePage::Redo); - updateAction(QWebEnginePage::SelectAll); - updateAction(QWebEnginePage::PasteAndMatchStyle); - updateAction(QWebEnginePage::Unselect); -} - -#ifndef QT_NO_ACTION -void QWebEnginePagePrivate::_q_webActionTriggered(bool checked) -{ - Q_Q(QWebEnginePage); - QAction *a = qobject_cast<QAction *>(q->sender()); - if (!a) - return; - QWebEnginePage::WebAction action = static_cast<QWebEnginePage::WebAction>(a->data().toInt()); - q->triggerAction(action, checked); -} -#endif // QT_NO_ACTION - -void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) -{ - QSharedPointer<WebContentsAdapter> newWebContents = WebContentsAdapter::createFromSerializedNavigationHistory(input, this); - if (newWebContents) { - adapter = std::move(newWebContents); - adapter->setClient(this); - adapter->loadDefault(); - } -} - -void QWebEnginePagePrivate::updateScrollPosition(const QPointF &position) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->scrollPositionChanged(position); -} - -void QWebEnginePagePrivate::updateContentsSize(const QSizeF &size) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->contentsSizeChanged(size); -} - -void QWebEnginePagePrivate::setFullScreenMode(bool fullscreen) -{ - if (fullscreenMode != fullscreen) { - fullscreenMode = fullscreen; - adapter->changedFullScreen(); - } -} - -ProfileAdapter* QWebEnginePagePrivate::profileAdapter() -{ - return profile->d_ptr->profileAdapter(); -} - -WebContentsAdapter *QWebEnginePagePrivate::webContentsAdapter() -{ - ensureInitialized(); - return adapter.data(); -} - -const QObject *QWebEnginePagePrivate::holdingQObject() const -{ - Q_Q(const QWebEnginePage); - return q; -} - -void QWebEnginePagePrivate::widgetChanged(RenderWidgetHostViewQtDelegate *newWidgetBase) -{ - Q_Q(QWebEnginePage); - bindPageAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateWidget *>(newWidgetBase)); -} - -void QWebEnginePagePrivate::findTextFinished(const QWebEngineFindTextResult &result) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->findTextFinished(result); -} - -void QWebEnginePagePrivate::ensureInitialized() const -{ - if (!adapter->isInitialized()) - adapter->loadDefault(); -} - -void QWebEnginePagePrivate::bindPageAndView(QWebEnginePage *page, QWebEngineView *view) -{ - auto oldView = page ? page->d_func()->view : nullptr; - auto oldPage = view ? view->d_func()->page : nullptr; - - bool ownNewPage = false; - bool deleteOldPage = false; - - // Change pointers first. - - if (page && oldView != view) { - if (oldView) { - ownNewPage = oldView->d_func()->m_ownsPage; - oldView->d_func()->page = nullptr; - oldView->d_func()->m_ownsPage = false; - } - page->d_func()->view = view; - } - - if (view && oldPage != page) { - if (oldPage) { - if (oldPage->d_func()) - oldPage->d_func()->view = nullptr; - deleteOldPage = view->d_func()->m_ownsPage; - } - view->d_func()->m_ownsPage = ownNewPage; - view->d_func()->page = page; - } - - // Then notify. - - auto widget = page ? page->d_func()->widget : nullptr; - auto oldWidget = (oldPage && oldPage->d_func()) ? oldPage->d_func()->widget : nullptr; - - if (page && oldView != view && oldView) { - oldView->d_func()->pageChanged(page, nullptr); - if (widget) - oldView->d_func()->widgetChanged(widget, nullptr); - } - - if (view && oldPage != page) { - if (oldPage && oldPage->d_func()) - view->d_func()->pageChanged(oldPage, page); - else - view->d_func()->pageChanged(nullptr, page); - if (oldWidget != widget) - view->d_func()->widgetChanged(oldWidget, widget); - } - if (deleteOldPage) - delete oldPage; -} - -void QWebEnginePagePrivate::bindPageAndWidget(QWebEnginePage *page, RenderWidgetHostViewQtDelegateWidget *widget) -{ - auto oldPage = widget ? widget->m_page : nullptr; - auto oldWidget = page ? page->d_func()->widget : nullptr; - - // Change pointers first. - - if (widget && oldPage != page) { - if (oldPage && oldPage->d_func()) - oldPage->d_func()->widget = nullptr; - widget->m_page = page; - } - - if (page && oldWidget != widget) { - if (oldWidget) - oldWidget->m_page = nullptr; - page->d_func()->widget = widget; - } - - // Then notify. - - if (widget && oldPage != page && oldPage && oldPage->d_func()) { - if (auto oldView = oldPage->d_func()->view) - oldView->d_func()->widgetChanged(widget, nullptr); - } - - if (page && oldWidget != widget) { - if (auto view = page->d_func()->view) - view->d_func()->widgetChanged(oldWidget, widget); - } -} - -QWebEnginePage::QWebEnginePage(QObject* parent) - : QObject(parent) - , d_ptr(new QWebEnginePagePrivate()) -{ - Q_D(QWebEnginePage); - d->q_ptr = this; - d->adapter->setClient(d); -} - -/*! - \fn void QWebEnginePage::findTextFinished(const QWebEngineFindTextResult &result) - \since 5.14 - - This signal is emitted when a search string search on a page is completed. \a result is - the result of the string search. - - \sa findText() -*/ - -/*! - \fn void QWebEnginePage::printRequested() - \since 5.12 - - This signal is emitted when the JavaScript \c{window.print()} method is called. - Typically, the signal handler can simply call printToPdf(). - - \sa printToPdf() -*/ - -/*! - \enum QWebEnginePage::RenderProcessTerminationStatus - \since 5.6 - - This enum describes the status with which the render process terminated: - - \value NormalTerminationStatus - The render process terminated normally. - \value AbnormalTerminationStatus - The render process terminated with with a non-zero exit status. - \value CrashedTerminationStatus - The render process crashed, for example because of a segmentation fault. - \value KilledTerminationStatus - The render process was killed, for example by \c SIGKILL or task manager kill. -*/ - -/*! - \fn QWebEnginePage::renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) - \since 5.6 - - This signal is emitted when the render process is terminated with a non-zero exit status. - \a terminationStatus is the termination status of the process and \a exitCode is the status code - with which the process terminated. -*/ - -/*! - \fn QWebEnginePage::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) - - This signal is emitted when the web page issues the request to enter fullscreen mode for - a web-element, usually a video element. - - The request object \a fullScreenRequest can be used to accept or reject the request. - - If the request is accepted the element requesting fullscreen will fill the viewport, - but it is up to the application to make the view fullscreen or move the page to a view - that is fullscreen. - - \sa QWebEngineSettings::FullScreenSupportEnabled -*/ - -/*! - \fn QWebEnginePage::quotaRequested(QWebEngineQuotaRequest quotaRequest) - \since 5.11 - - This signal is emitted when the web page requests larger persistent storage - than the application's current allocation in File System API. The default quota - is 0 bytes. - - The request object \a quotaRequest can be used to accept or reject the request. -*/ - -/*! - \fn QWebEnginePage::registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request) - \since 5.11 - - This signal is emitted when the web page tries to register a custom protocol - using the \l registerProtocolHandler API. - - The request object \a request can be used to accept or reject the request: - - \snippet webenginewidgets/simplebrowser/webpage.cpp registerProtocolHandlerRequested -*/ - -/*! - \fn void QWebEnginePage::pdfPrintingFinished(const QString &filePath, bool success) - \since 5.9 - - This signal is emitted when printing the web page into a PDF file has - finished. - \a filePath will contain the path the file was requested to be created - at, and \a success will be \c true if the file was successfully created and - \c false otherwise. - - \sa printToPdf() -*/ - -/*! - \property QWebEnginePage::scrollPosition - \since 5.7 - - \brief The scroll position of the page contents. -*/ - -/*! - \property QWebEnginePage::contentsSize - \since 5.7 - - \brief The size of the page contents. -*/ - -/*! - \fn void QWebEnginePage::audioMutedChanged(bool muted) - \since 5.7 - - This signal is emitted when the page's \a muted state changes. - \note Not to be confused with a specific HTML5 audio or video element being muted. -*/ - -/*! - \fn void QWebEnginePage::recentlyAudibleChanged(bool recentlyAudible); - \since 5.7 - - This signal is emitted when the page's audible state, \a recentlyAudible, changes, because - the audio is played or stopped. - - \note The signal is also emitted when calling the setAudioMuted() method. - Also, if the audio is paused, this signal is emitted with an approximate \b{two-second - delay}, from the moment the audio is paused. -*/ - -/*! - \fn void QWebEnginePage::renderProcessPidChanged(qint64 pid); - \since 5.15 - - This signal is emitted when the underlying render process PID, \a renderProcessPid, changes. -*/ - -/*! - \fn void QWebEnginePage::iconUrlChanged(const QUrl &url) - - This signal is emitted when the URL of the icon ("favicon") associated with the - page is changed. The new URL is specified by \a url. - - \sa iconUrl(), icon(), iconChanged() -*/ - -/*! - \fn void QWebEnginePage::iconChanged(const QIcon &icon) - \since 5.7 - - This signal is emitted when the icon ("favicon") associated with the - page is changed. The new icon is specified by \a icon. - - \sa icon(), iconUrl(), iconUrlChanged() -*/ - -/*! - Constructs an empty web engine page in the web engine profile \a profile with the parent - \a parent. - - If the profile is not the default profile, the caller must ensure that the profile stays alive - for as long as the page does. - - \since 5.5 -*/ -QWebEnginePage::QWebEnginePage(QWebEngineProfile *profile, QObject* parent) - : QObject(parent) - , d_ptr(new QWebEnginePagePrivate(profile)) -{ - Q_D(QWebEnginePage); - d->q_ptr = this; - d->adapter->setClient(d); -} - -QWebEnginePage::~QWebEnginePage() -{ - if (d_ptr) { - // d_ptr might be exceptionally null if profile adapter got deleted first - setDevToolsPage(nullptr); - QWebEnginePagePrivate::bindPageAndView(this, nullptr); - QWebEnginePagePrivate::bindPageAndWidget(this, nullptr); - } -} - -QWebEngineHistory *QWebEnginePage::history() const -{ - Q_D(const QWebEnginePage); - return d->history; -} - -QWebEngineSettings *QWebEnginePage::settings() const -{ - Q_D(const QWebEnginePage); - return d->settings; -} - -/*! - * Returns a pointer to the web channel instance used by this page or a null pointer if none was set. - * This channel automatically uses the internal web engine transport mechanism over Chromium IPC - * that is exposed in the JavaScript context of this page as \c qt.webChannelTransport. - * - * \since 5.5 - * \sa setWebChannel() - */ -QWebChannel *QWebEnginePage::webChannel() const -{ -#if QT_CONFIG(webengine_webchannel) - Q_D(const QWebEnginePage); - return d->webChannel; -#endif - qWarning("WebEngine compiled without webchannel support"); - return nullptr; -} - -/*! - * \overload - * - * Sets the web channel instance to be used by this page to \a channel and installs - * it in the main JavaScript world. - * - * With this method the web channel can be accessed by web page content. If the content - * is not under your control and might be hostile, this could be a security issue and - * you should consider installing it in a private JavaScript world. - * - * \since 5.5 - * \sa QWebEngineScript::MainWorld - */ - -void QWebEnginePage::setWebChannel(QWebChannel *channel) -{ - setWebChannel(channel, QWebEngineScript::MainWorld); -} - -/*! - * Sets the web channel instance to be used by this page to \a channel and connects it to - * web engine's transport using Chromium IPC messages. The transport is exposed in the JavaScript - * world \a worldId as - * \c qt.webChannelTransport, which should be used when using the \l{Qt WebChannel JavaScript API}. - * - * \note The page does not take ownership of the channel object. - * \note Only one web channel can be installed per page, setting one even in another JavaScript - * world uninstalls any already installed web channel. - * - * \since 5.7 - * \sa QWebEngineScript::ScriptWorldId - */ -void QWebEnginePage::setWebChannel(QWebChannel *channel, uint worldId) -{ -#if QT_CONFIG(webengine_webchannel) - Q_D(QWebEnginePage); - if (d->webChannel != channel || d->webChannelWorldId != worldId) { - d->webChannel = channel; - d->webChannelWorldId = worldId; - d->adapter->setWebChannel(channel, worldId); - } -#else - Q_UNUSED(channel) - Q_UNUSED(worldId) - qWarning("WebEngine compiled without webchannel support"); -#endif -} - -/*! - \property QWebEnginePage::backgroundColor - \brief The page's background color behind the document's body. - \since 5.6 - - You can set the background color to Qt::transparent or to a translucent - color to see through the document, or you can set it to match your - web content in a hybrid application to prevent the white flashes that may appear - during loading. - - The default value is white. -*/ -QColor QWebEnginePage::backgroundColor() const -{ - Q_D(const QWebEnginePage); - return d->m_backgroundColor; -} - -void QWebEnginePage::setBackgroundColor(const QColor &color) -{ - Q_D(QWebEnginePage); - if (d->m_backgroundColor == color) - return; - d->m_backgroundColor = color; - d->adapter->setBackgroundColor(color); -} - -/*! - * Save the currently loaded web page to disk. - * - * The web page is saved to \a filePath in the specified \a{format}. - * - * This is a short cut for the following actions: - * \list - * \li Trigger the Save web action. - * \li Accept the next download item and set the specified file path and save format. - * \endlist - * - * This function issues an asynchronous download request for the web page and returns immediately. - * - * \sa QWebEngineDownloadItem::SavePageFormat - * \since 5.8 - */ -void QWebEnginePage::save(const QString &filePath, - QWebEngineDownloadItem::SavePageFormat format) const -{ - Q_D(const QWebEnginePage); - d->ensureInitialized(); - d->adapter->save(filePath, format); -} - -/*! - \property QWebEnginePage::audioMuted - \brief Whether the current page audio is muted. - \since 5.7 - - The default value is \c false. - \sa recentlyAudible -*/ -bool QWebEnginePage::isAudioMuted() const { - Q_D(const QWebEnginePage); - if (d->adapter->isInitialized()) - return d->adapter->isAudioMuted(); - return d->defaultAudioMuted; -} - -void QWebEnginePage::setAudioMuted(bool muted) { - Q_D(QWebEnginePage); - bool wasAudioMuted = isAudioMuted(); - d->defaultAudioMuted = muted; - d->adapter->setAudioMuted(muted); - if (wasAudioMuted != isAudioMuted()) - Q_EMIT audioMutedChanged(muted); -} - -/*! - \property QWebEnginePage::recentlyAudible - \brief The current page's \e {audible state}, that is, whether audio was recently played - or not. - \since 5.7 - - The default value is \c false. - \sa audioMuted -*/ -bool QWebEnginePage::recentlyAudible() const -{ - Q_D(const QWebEnginePage); - return d->adapter->isInitialized() && d->adapter->recentlyAudible(); -} - -/*! - \property QWebEnginePage::renderProcessPid - \brief The process ID (PID) of the render process assigned to the current - page's main frame. - \since 5.15 - - If no render process is available yet, \c 0 is returned. -*/ -qint64 QWebEnginePage::renderProcessPid() const -{ - Q_D(const QWebEnginePage); - return d->adapter->renderProcessPid(); -} - -void QWebEnginePage::setView(QWidget *newViewBase) -{ - QWebEnginePagePrivate::bindPageAndView(this, qobject_cast<QWebEngineView *>(newViewBase)); -} - -QWidget *QWebEnginePage::view() const -{ - Q_D(const QWebEnginePage); - return d->view; -} - -/*! - Returns the web engine profile the page belongs to. - \since 5.5 -*/ -QWebEngineProfile *QWebEnginePage::profile() const -{ - Q_D(const QWebEnginePage); - return d->profile; -} - -bool QWebEnginePage::hasSelection() const -{ - return !selectedText().isEmpty(); -} - -QString QWebEnginePage::selectedText() const -{ - Q_D(const QWebEnginePage); - return d->adapter->selectedText(); -} - -#ifndef QT_NO_ACTION -QAction *QWebEnginePage::action(WebAction action) const -{ - Q_D(const QWebEnginePage); - if (action == QWebEnginePage::NoWebAction) - return 0; - if (d->actions[action]) - return d->actions[action]; - - QString text; - QIcon icon; - QStyle *style = d->view ? d->view->style() : qApp->style(); - - switch (action) { - case Back: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Back); - icon = style->standardIcon(QStyle::SP_ArrowBack); - break; - case Forward: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Forward); - icon = style->standardIcon(QStyle::SP_ArrowForward); - break; - case Stop: - text = tr("Stop"); - icon = style->standardIcon(QStyle::SP_BrowserStop); - break; - case Reload: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Reload); - icon = style->standardIcon(QStyle::SP_BrowserReload); - break; - case ReloadAndBypassCache: - text = tr("Reload and Bypass Cache"); - icon = style->standardIcon(QStyle::SP_BrowserReload); - break; - case Cut: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Cut); - break; - case Copy: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Copy); - break; - case Paste: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Paste); - break; - case Undo: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Undo); - break; - case Redo: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Redo); - break; - case SelectAll: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SelectAll); - break; - case PasteAndMatchStyle: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::PasteAndMatchStyle); - break; - case OpenLinkInThisWindow: - text = tr("Open link in this window"); - break; - case OpenLinkInNewWindow: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewWindow); - break; - case OpenLinkInNewTab: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewTab); - break; - case OpenLinkInNewBackgroundTab: - text = tr("Open link in new background tab"); - break; - case CopyLinkToClipboard: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyLinkToClipboard); - break; - case DownloadLinkToDisk: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadLinkToDisk); - break; - case CopyImageToClipboard: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageToClipboard); - break; - case CopyImageUrlToClipboard: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageUrlToClipboard); - break; - case DownloadImageToDisk: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadImageToDisk); - break; - case CopyMediaUrlToClipboard: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyMediaUrlToClipboard); - break; - case ToggleMediaControls: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaControls); - break; - case ToggleMediaLoop: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaLoop); - break; - case ToggleMediaPlayPause: - text = tr("Toggle Play/Pause"); - break; - case ToggleMediaMute: - text = tr("Toggle Mute"); - break; - case DownloadMediaToDisk: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadMediaToDisk); - break; - case InspectElement: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::InspectElement); - break; - case ExitFullScreen: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ExitFullScreen); - break; - case RequestClose: - text = tr("Close Page"); - break; - case Unselect: - text = tr("Unselect"); - break; - case SavePage: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SavePage); - break; - case ViewSource: - text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ViewSource); - 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(); - break; - } - - QAction *a = new QAction(const_cast<QWebEnginePage*>(this)); - a->setText(text); - a->setData(action); - a->setIcon(icon); - - connect(a, SIGNAL(triggered(bool)), this, SLOT(_q_webActionTriggered(bool))); - - d->actions[action] = a; - d->updateAction(action); - return a; -} -#endif // QT_NO_ACTION - -void QWebEnginePage::triggerAction(WebAction action, bool) -{ - Q_D(QWebEnginePage); - d->ensureInitialized(); - const QtWebEngineCore::WebEngineContextMenuData *menuData = d->contextData.d; - switch (action) { - case Back: - d->adapter->navigateBack(); - break; - case Forward: - d->adapter->navigateForward(); - break; - case Stop: - d->adapter->stop(); - break; - case Reload: - d->adapter->reload(); - break; - case ReloadAndBypassCache: - d->adapter->reloadAndBypassCache(); - break; - case Cut: - d->adapter->cut(); - break; - case Copy: - d->adapter->copy(); - break; - case Paste: - d->adapter->paste(); - break; - case Undo: - d->adapter->undo(); - break; - case Redo: - d->adapter->redo(); - break; - case SelectAll: - d->adapter->selectAll(); - break; - case PasteAndMatchStyle: - d->adapter->pasteAndMatchStyle(); - break; - case Unselect: - d->adapter->unselect(); - break; - case OpenLinkInThisWindow: - if (menuData && menuData->linkUrl().isValid()) - setUrl(menuData->linkUrl()); - break; - case OpenLinkInNewWindow: - if (menuData && menuData->linkUrl().isValid()) { - QWebEnginePage *newPage = createWindow(WebBrowserWindow); - if (newPage) - newPage->setUrl(menuData->linkUrl()); - } - break; - case OpenLinkInNewTab: - if (menuData && menuData->linkUrl().isValid()) { - QWebEnginePage *newPage = createWindow(WebBrowserTab); - if (newPage) - newPage->setUrl(menuData->linkUrl()); - } - break; - case OpenLinkInNewBackgroundTab: - if (menuData && menuData->linkUrl().isValid()) { - QWebEnginePage *newPage = createWindow(WebBrowserBackgroundTab); - if (newPage) - newPage->setUrl(menuData->linkUrl()); - } - break; - case CopyLinkToClipboard: - if (menuData && !menuData->unfilteredLinkUrl().isEmpty()) { - QString urlString = menuData->unfilteredLinkUrl().toString(QUrl::FullyEncoded); - QString linkText = menuData->linkText().toHtmlEscaped(); - QString title = menuData->titleText(); - if (!title.isEmpty()) - title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); - QMimeData *data = new QMimeData(); - data->setText(urlString); - QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral(">") - + linkText + QStringLiteral("</a>"); - data->setHtml(html); - data->setUrls(QList<QUrl>() << menuData->unfilteredLinkUrl()); - qApp->clipboard()->setMimeData(data); - } - break; - case DownloadLinkToDisk: - if (menuData && menuData->linkUrl().isValid()) - d->adapter->download(menuData->linkUrl(), menuData->suggestedFileName(), - menuData->referrerUrl(), menuData->referrerPolicy()); - - break; - case CopyImageToClipboard: - if (menuData && menuData->hasImageContent() && - (menuData->mediaType() == WebEngineContextMenuData::MediaTypeImage || - menuData->mediaType() == WebEngineContextMenuData::MediaTypeCanvas)) - { - d->adapter->copyImageAt(menuData->position()); - } - break; - case CopyImageUrlToClipboard: - if (menuData && menuData->mediaUrl().isValid() && menuData->mediaType() == WebEngineContextMenuData::MediaTypeImage) { - QString urlString = menuData->mediaUrl().toString(QUrl::FullyEncoded); - QString alt = menuData->altText(); - if (!alt.isEmpty()) - alt = QStringLiteral(" alt=\"%1\"").arg(alt.toHtmlEscaped()); - QString title = menuData->titleText(); - if (!title.isEmpty()) - title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); - QMimeData *data = new QMimeData(); - data->setText(urlString); - QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + alt + QStringLiteral("></img>"); - data->setHtml(html); - data->setUrls(QList<QUrl>() << menuData->mediaUrl()); - qApp->clipboard()->setMimeData(data); - } - break; - case DownloadImageToDisk: - case DownloadMediaToDisk: - if (menuData && menuData->mediaUrl().isValid()) - d->adapter->download(menuData->mediaUrl(), menuData->suggestedFileName(), - menuData->referrerUrl(), menuData->referrerPolicy()); - break; - case CopyMediaUrlToClipboard: - if (menuData && menuData->mediaUrl().isValid() && - (menuData->mediaType() == WebEngineContextMenuData::MediaTypeAudio || - menuData->mediaType() == WebEngineContextMenuData::MediaTypeVideo)) - { - QString urlString = menuData->mediaUrl().toString(QUrl::FullyEncoded); - QString title = menuData->titleText(); - if (!title.isEmpty()) - title = QStringLiteral(" title=\"%1\"").arg(title.toHtmlEscaped()); - QMimeData *data = new QMimeData(); - data->setText(urlString); - if (menuData->mediaType() == WebEngineContextMenuData::MediaTypeAudio) - data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"") + title + - QStringLiteral("></audio>")); - else - data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"") + title + - QStringLiteral("></video>")); - data->setUrls(QList<QUrl>() << menuData->mediaUrl()); - qApp->clipboard()->setMimeData(data); - } - break; - case ToggleMediaControls: - if (menuData && menuData->mediaUrl().isValid() && menuData->mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls) { - bool enable = !(menuData->mediaFlags() & WebEngineContextMenuData::MediaControls); - d->adapter->executeMediaPlayerActionAt(menuData->position(), WebContentsAdapter::MediaPlayerControls, enable); - } - break; - case ToggleMediaLoop: - if (menuData && menuData->mediaUrl().isValid() && - (menuData->mediaType() == WebEngineContextMenuData::MediaTypeAudio || - menuData->mediaType() == WebEngineContextMenuData::MediaTypeVideo)) - { - bool enable = !(menuData->mediaFlags() & WebEngineContextMenuData::MediaLoop); - d->adapter->executeMediaPlayerActionAt(menuData->position(), WebContentsAdapter::MediaPlayerLoop, enable); - } - break; - case ToggleMediaPlayPause: - if (menuData && menuData->mediaUrl().isValid() && - (menuData->mediaType() == WebEngineContextMenuData::MediaTypeAudio || - menuData->mediaType() == WebEngineContextMenuData::MediaTypeVideo)) - { - bool enable = (menuData->mediaFlags() & WebEngineContextMenuData::MediaPaused); - d->adapter->executeMediaPlayerActionAt(menuData->position(), WebContentsAdapter::MediaPlayerPlay, enable); - } - break; - case ToggleMediaMute: - if (menuData && menuData->mediaUrl().isValid() && menuData->mediaFlags() & WebEngineContextMenuData::MediaHasAudio) { - // Make sure to negate the value, so that toggling actually works. - bool enable = !(menuData->mediaFlags() & WebEngineContextMenuData::MediaMuted); - d->adapter->executeMediaPlayerActionAt(menuData->position(), WebContentsAdapter::MediaPlayerMute, enable); - } - break; - case InspectElement: - if (menuData) - d->adapter->inspectElementAt(menuData->position()); - break; - case ExitFullScreen: - // See under ViewSource, anything that can trigger a delete of the current view is dangerous to call directly here. - QTimer::singleShot(0, this, [d](){ d->adapter->exitFullScreen(); }); - break; - case RequestClose: - d->adapter->requestClose(); - break; - case SavePage: - d->adapter->save(); - break; - case ViewSource: - // This is a workaround to make the ViewSource action working in a context menu. - // The WebContentsAdapter::viewSource() method deletes a - // RenderWidgetHostViewQtDelegateWidget instance which passes the control to the event - // loop. If the QMenu::aboutToHide() signal is connected to the QObject::deleteLater() - // slot the QMenu is deleted by the event handler while the ViewSource action is still not - // completed. This may lead to a crash. To avoid this the WebContentsAdapter::viewSource() - // method is called indirectly via the QTimer::singleShot() function which schedules the - // 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: - Q_UNREACHABLE(); - break; - } -} - -/*! - * \since 5.8 - * Replace the current misspelled word with \a replacement. - * - * The current misspelled word can be found in QWebEngineContextMenuData::misspelledWord(), - * and suggested replacements in QWebEngineContextMenuData::spellCheckerSuggestions(). - * - * \sa contextMenuData(), - */ - -void QWebEnginePage::replaceMisspelledWord(const QString &replacement) -{ - Q_D(QWebEnginePage); - d->adapter->replaceMisspelling(replacement); -} - -void QWebEnginePage::findText(const QString &subString, FindFlags options, const QWebEngineCallback<bool> &resultCallback) -{ - Q_D(QWebEnginePage); - if (!d->adapter->isInitialized()) { - QtWebEngineCore::CallbackDirectory().invokeEmpty(resultCallback); - return; - } - - d->adapter->findTextHelper()->startFinding(subString, options & FindCaseSensitively, options & FindBackward, resultCallback); -} - -/*! - * \reimp - */ -bool QWebEnginePage::event(QEvent *e) -{ - return QObject::event(e); -} - -void QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData &data) -{ -#if QT_CONFIG(action) - if (!view) - return; - - contextData.reset(); - switch (view->contextMenuPolicy()) { - case Qt::DefaultContextMenu: - { - contextData = data; - QContextMenuEvent event(QContextMenuEvent::Mouse, data.position(), view->mapToGlobal(data.position())); - view->contextMenuEvent(&event); - return; - } - case Qt::CustomContextMenu: - contextData = data; - Q_EMIT view->customContextMenuRequested(data.position()); - 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); - } - return; - case Qt::PreventContextMenu: - case Qt::NoContextMenu: - return; - } - - Q_UNREACHABLE(); -#else - Q_UNUSED(data); -#endif // QT_CONFIG(action) -} - -void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) -{ - Q_Q(QWebEnginePage); - bool accepted = q->acceptNavigationRequest(url, static_cast<QWebEnginePage::NavigationType>(navigationType), isMainFrame); - if (accepted && adapter->findTextHelper()->isFindTextInProgress()) - adapter->findTextHelper()->stopFinding(); - navigationRequestAction = accepted ? WebContentsAdapterClient::AcceptRequest : WebContentsAdapterClient::IgnoreRequest; -} - -void QWebEnginePagePrivate::requestFullScreenMode(const QUrl &origin, bool fullscreen) -{ - Q_Q(QWebEnginePage); - QWebEngineFullScreenRequest request(q, origin, fullscreen); - Q_EMIT q->fullScreenRequested(request); -} - -bool QWebEnginePagePrivate::isFullScreenMode() const -{ - return fullscreenMode; -} - -void QWebEnginePagePrivate::javascriptDialog(QSharedPointer<JavaScriptDialogController> controller) -{ - Q_Q(QWebEnginePage); - bool accepted = false; - QString promptResult; - switch (controller->type()) { - case AlertDialog: - q->javaScriptAlert(controller->securityOrigin(), controller->message()); - accepted = true; - break; - case ConfirmDialog: - accepted = q->javaScriptConfirm(controller->securityOrigin(), controller->message()); - break; - case PromptDialog: - accepted = q->javaScriptPrompt(controller->securityOrigin(), controller->message(), controller->defaultPrompt(), &promptResult); - if (accepted) - controller->textProvided(promptResult); - break; - case UnloadDialog: - accepted = q->javaScriptConfirm(controller->securityOrigin(), QCoreApplication::translate("QWebEnginePage", "Are you sure you want to leave this page? Changes that you made may not be saved.")); - break; - case InternalAuthorizationDialog: -#if QT_CONFIG(messagebox) - accepted = (QMessageBox::question(view, controller->title(), controller->message(), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes); -#endif // QT_CONFIG(messagebox) - break; - } - if (accepted) - controller->accept(); - else - controller->reject(); -} - -void QWebEnginePagePrivate::allowCertificateError(const QSharedPointer<CertificateErrorController> &controller) -{ - Q_Q(QWebEnginePage); - bool accepted = false; - - QWebEngineCertificateError error(controller); - accepted = q->certificateError(error); - if (error.deferred() && !error.answered()) - m_certificateErrorControllers.append(controller); - else if (!error.answered()) - controller->accept(error.isOverridable() && accepted); -} - -void QWebEnginePagePrivate::selectClientCert(const QSharedPointer<ClientCertSelectController> &controller) -{ -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) - Q_Q(QWebEnginePage); - QWebEngineClientCertificateSelection certSelection(controller); - - Q_EMIT q->selectClientCertificate(certSelection); -#else - Q_UNUSED(controller); -#endif -} - -#if !defined(QT_NO_SSL) || QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) -/*! - \fn void QWebEnginePage::selectClientCertificate(QWebEngineClientCertificateSelection clientCertificateSelection) - \since 5.12 - - This signal is emitted when a web site requests an SSL client certificate, and one or more were - found in system's client certificate store. - - Handling the signal is asynchronous, and loading will be waiting until a certificate is selected, - or the last copy of \a clientCertificateSelection is destroyed. - - If the signal is not handled, \a clientCertificateSelection is automatically destroyed, and loading - will continue without a client certificate. - - \sa QWebEngineClientCertificateSelection -*/ -#endif - -void QWebEnginePagePrivate::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) -{ - Q_Q(QWebEnginePage); - q->javaScriptConsoleMessage(static_cast<QWebEnginePage::JavaScriptConsoleMessageLevel>(level), message, lineNumber, sourceID); -} - -void QWebEnginePagePrivate::renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, - int exitCode) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->renderProcessTerminated(static_cast<QWebEnginePage::RenderProcessTerminationStatus>( - terminationStatus), exitCode); -} - -void QWebEnginePagePrivate::requestGeometryChange(const QRect &geometry, const QRect &frameGeometry) -{ - Q_UNUSED(geometry); - Q_Q(QWebEnginePage); - Q_EMIT q->geometryChangeRequested(frameGeometry); -} - -void QWebEnginePagePrivate::startDragging(const content::DropData &dropData, - Qt::DropActions allowedActions, const QPixmap &pixmap, - const QPoint &offset) -{ -#if !QT_CONFIG(draganddrop) - Q_UNUSED(dropData); - Q_UNUSED(allowedActions); - Q_UNUSED(pixmap); - Q_UNUSED(offset); -#else - adapter->startDragging(view, dropData, allowedActions, pixmap, offset); -#endif // QT_CONFIG(draganddrop) -} - -bool QWebEnginePagePrivate::supportsDragging() const -{ - return true; -} - -bool QWebEnginePagePrivate::isEnabled() const -{ - const Q_Q(QWebEnginePage); - const QWidget *view = q->view(); - if (view) - return view->isEnabled(); - return true; -} - -void QWebEnginePagePrivate::setToolTip(const QString &toolTipText) -{ - if (!view) - return; - - // Hide tooltip if shown. - if (toolTipText.isEmpty()) { - if (!view->toolTip().isEmpty()) - view->setToolTip(QString()); - - return; - } - - // Update tooltip if text was changed. - QString wrappedTip = QLatin1String("<p style=\"white-space:pre-wrap\">") - % toolTipText.toHtmlEscaped().left(MaxTooltipLength) - % QLatin1String("</p>"); - if (view->toolTip() != wrappedTip) - view->setToolTip(wrappedTip); -} - -void QWebEnginePagePrivate::printRequested() -{ - Q_Q(QWebEnginePage); - QTimer::singleShot(0, q, [q](){ - Q_EMIT q->printRequested(); - }); -} - -void QWebEnginePagePrivate::lifecycleStateChanged(LifecycleState state) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->lifecycleStateChanged(static_cast<QWebEnginePage::LifecycleState>(state)); -} - -void QWebEnginePagePrivate::recommendedStateChanged(LifecycleState state) -{ - Q_Q(QWebEnginePage); - QTimer::singleShot(0, q, [q, state]() { - Q_EMIT q->recommendedStateChanged(static_cast<QWebEnginePage::LifecycleState>(state)); - }); -} - -void QWebEnginePagePrivate::visibleChanged(bool visible) -{ - Q_Q(QWebEnginePage); - Q_EMIT q->visibleChanged(visible); -} - -/*! - \since 5.13 - - Registers the request interceptor \a interceptor to intercept URL requests. - - The page does not take ownership of the pointer. This interceptor is called - after any interceptors on the profile, and unlike profile interceptors, only - URL requests from this page are intercepted. - - To unset the request interceptor, set a \c nullptr. - - \sa QWebEngineUrlRequestInfo, QWebEngineProfile::setUrlRequestInterceptor() -*/ - -void QWebEnginePage::setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) -{ - Q_D(QWebEnginePage); - d->adapter->setRequestInterceptor(interceptor); -} - -#if QT_CONFIG(menu) -QMenu *QWebEnginePage::createStandardContextMenu() -{ - Q_D(QWebEnginePage); - if (!d->contextData.d) - return nullptr; - d->ensureInitialized(); - - QMenu *menu = new QMenu(d->view); - const WebEngineContextMenuData &contextMenuData = *d->contextData.d; - - QContextMenuBuilder contextMenuBuilder(contextMenuData, this, menu); - - contextMenuBuilder.initMenu(); - - menu->setAttribute(Qt::WA_DeleteOnClose, true); - - return menu; -} -#endif // QT_CONFIG(menu) - -void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy) -{ - Q_D(QWebEnginePage); - if (policy == PermissionUnknown) { - switch (feature) { - case MediaAudioVideoCapture: - case MediaAudioCapture: - case MediaVideoCapture: - case DesktopAudioVideoCapture: - case DesktopVideoCapture: - case MouseLock: - break; - case Geolocation: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AskPermission); - break; - case Notifications: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AskPermission); - break; - } - return; - } - - 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 MouseLock: - d->adapter->grantMouseLockPermission(securityOrigin, true); - break; - case Geolocation: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AllowedPermission); - break; - case Notifications: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AllowedPermission); - 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->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::DeniedPermission); - break; - case MouseLock: - d->adapter->grantMouseLockPermission(securityOrigin, false); - break; - case Notifications: - d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::DeniedPermission); - break; - } - } -} - -static inline QWebEnginePage::FileSelectionMode toPublic(FilePickerController::FileChooserMode mode) -{ - // Should the underlying values change, we'll need a switch here. - return static_cast<QWebEnginePage::FileSelectionMode>(mode); -} - -void QWebEnginePagePrivate::runFileChooser(QSharedPointer<FilePickerController> controller) -{ - Q_Q(QWebEnginePage); - - QStringList selectedFileNames = q->chooseFiles(toPublic(controller->mode()), (QStringList() << controller->defaultFileName()), controller->acceptedMimeTypes()); - - if (!selectedFileNames.empty()) - controller->accepted(selectedFileNames); - else - controller->rejected(); -} - -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->ensureInitialized(); - d->adapter->download(url, filename); -} - -void QWebEnginePage::load(const QUrl& url) -{ - Q_D(QWebEnginePage); - d->adapter->load(url); -} - -/*! - \since 5.9 - Issues the specified \a request and loads the response. - - \sa load(), setUrl(), url(), urlChanged(), QUrl::fromUserInput() -*/ -void QWebEnginePage::load(const QWebEngineHttpRequest& request) -{ - Q_D(QWebEnginePage); - d->adapter->load(request); -} - -void QWebEnginePage::toHtml(const QWebEngineCallback<const QString &> &resultCallback) const -{ - Q_D(const QWebEnginePage); - d->ensureInitialized(); - quint64 requestId = d->adapter->fetchDocumentMarkup(); - d->m_callbacks.registerCallback(requestId, resultCallback); -} - -void QWebEnginePage::toPlainText(const QWebEngineCallback<const QString &> &resultCallback) const -{ - Q_D(const QWebEnginePage); - d->ensureInitialized(); - quint64 requestId = d->adapter->fetchDocumentInnerText(); - d->m_callbacks.registerCallback(requestId, resultCallback); -} - -void QWebEnginePage::setHtml(const QString &html, const QUrl &baseUrl) -{ - setContent(html.toUtf8(), QStringLiteral("text/html;charset=UTF-8"), baseUrl); -} - -void QWebEnginePage::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl) -{ - Q_D(QWebEnginePage); - d->adapter->setContent(data, mimeType, baseUrl); -} - -QString QWebEnginePage::title() const -{ - Q_D(const QWebEnginePage); - return d->adapter->pageTitle(); -} - -void QWebEnginePage::setUrl(const QUrl &url) -{ - Q_D(QWebEnginePage); - if (d->url != url) { - d->url = url; - emit urlChanged(url); - } - load(url); -} - -QUrl QWebEnginePage::url() const -{ - Q_D(const QWebEnginePage); - return d->url; -} - -QUrl QWebEnginePage::requestedUrl() const -{ - Q_D(const QWebEnginePage); - return d->adapter->requestedUrl(); -} - -/*! - \property QWebEnginePage::iconUrl - \brief The URL of the icon associated with the page currently viewed. - - By default, this property contains an empty URL. - - \sa iconUrlChanged(), icon(), iconChanged() -*/ -QUrl QWebEnginePage::iconUrl() const -{ - Q_D(const QWebEnginePage); - return d->iconUrl; -} - -/*! - \property QWebEnginePage::icon - \brief The icon associated with the page currently viewed. - \since 5.7 - - By default, this property contains a null icon. If the web page specifies more than one icon, - the \c{icon} property encapsulates the available candidate icons in a single, - scalable \c{QIcon}. - - \sa iconChanged(), iconUrl(), iconUrlChanged() -*/ -QIcon QWebEnginePage::icon() const -{ - Q_D(const QWebEnginePage); - - if (d->iconUrl.isEmpty() || !d->adapter->isInitialized()) - return QIcon(); - - return d->adapter->faviconManager()->getIcon(); -} - -qreal QWebEnginePage::zoomFactor() const -{ - Q_D(const QWebEnginePage); - if (d->adapter->isInitialized()) - return d->adapter->currentZoomFactor(); - return d->defaultZoomFactor; -} - -void QWebEnginePage::setZoomFactor(qreal factor) -{ - Q_D(QWebEnginePage); - d->defaultZoomFactor = factor; - if (d->adapter->isInitialized()) - d->adapter->setZoomFactor(factor); -} - -void QWebEnginePage::runJavaScript(const QString &scriptSource) -{ - Q_D(QWebEnginePage); - d->ensureInitialized(); - if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { - qWarning("runJavaScript: disabled in Discarded state"); - return; - } - d->adapter->runJavaScript(scriptSource, QWebEngineScript::MainWorld); -} - -void QWebEnginePage::runJavaScript(const QString& scriptSource, const QWebEngineCallback<const QVariant &> &resultCallback) -{ - Q_D(QWebEnginePage); - d->ensureInitialized(); - if (d->adapter->lifecycleState() == WebContentsAdapter::LifecycleState::Discarded) { - qWarning("runJavaScript: disabled in Discarded state"); - d->m_callbacks.invokeEmpty(resultCallback); - return; - } - quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, QWebEngineScript::MainWorld); - d->m_callbacks.registerCallback(requestId, resultCallback); -} - -void QWebEnginePage::runJavaScript(const QString &scriptSource, quint32 worldId) -{ - Q_D(QWebEnginePage); - d->ensureInitialized(); - d->adapter->runJavaScript(scriptSource, worldId); -} - -void QWebEnginePage::runJavaScript(const QString& scriptSource, quint32 worldId, const QWebEngineCallback<const QVariant &> &resultCallback) -{ - Q_D(QWebEnginePage); - d->ensureInitialized(); - quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, worldId); - d->m_callbacks.registerCallback(requestId, resultCallback); -} - -/*! - Returns the collection of scripts that are injected into the page. - - In addition, a page might also execute scripts - added through QWebEngineProfile::scripts(). - - \sa QWebEngineScriptCollection, QWebEngineScript, {Script Injection} -*/ - -QWebEngineScriptCollection &QWebEnginePage::scripts() -{ - Q_D(QWebEnginePage); - return d->scriptCollection; -} - -QWebEnginePage *QWebEnginePage::createWindow(WebWindowType type) -{ - Q_D(QWebEnginePage); - if (d->view) { - QWebEngineView *newView = d->view->createWindow(type); - if (newView) - return newView->page(); - } - return 0; -} - -/*! - \since 5.11 - Returns the page this page is inspecting, if any. - - Returns \c nullptr if this page is not a developer tools page. - - \sa setInspectedPage(), devToolsPage() -*/ - -QWebEnginePage *QWebEnginePage::inspectedPage() const -{ - Q_D(const QWebEnginePage); - return d->inspectedPage; -} - -/*! - \since 5.11 - Navigates this page to an internal URL that is the developer - tools of \a page. - - This is the same as calling setDevToolsPage() on \a page - with \c this as argument. - - \sa inspectedPage(), setDevToolsPage() -*/ - -void QWebEnginePage::setInspectedPage(QWebEnginePage *page) -{ - Q_D(QWebEnginePage); - if (d->inspectedPage == page) - return; - QWebEnginePage *oldPage = d->inspectedPage; - d->inspectedPage = nullptr; - if (oldPage) - oldPage->setDevToolsPage(nullptr); - d->inspectedPage = page; - if (page) - page->setDevToolsPage(this); -} - -/*! - \since 5.11 - Returns the page that is hosting the developer tools - of this page, if any. - - Returns \c nullptr if no developer tools page is set. - - \sa setDevToolsPage(), inspectedPage() -*/ - -QWebEnginePage *QWebEnginePage::devToolsPage() const -{ - Q_D(const QWebEnginePage); - return d->devToolsPage; -} - -/*! - \since 5.11 - Binds \a devToolsPage to be the developer tools of this page. - Triggers \a devToolsPage to navigate to an internal URL - with the developer tools. - - This is the same as calling setInspectedPage() on \a devToolsPage - with \c this as argument. - - \sa devToolsPage(), setInspectedPage() -*/ - -void QWebEnginePage::setDevToolsPage(QWebEnginePage *devToolsPage) -{ - Q_D(QWebEnginePage); - if (d->devToolsPage == devToolsPage) - return; - d->ensureInitialized(); - QWebEnginePage *oldDevTools = d->devToolsPage; - d->devToolsPage = nullptr; - if (oldDevTools) - oldDevTools->setInspectedPage(nullptr); - d->devToolsPage = devToolsPage; - if (devToolsPage) - devToolsPage->setInspectedPage(this); - if (d->adapter) { - if (devToolsPage) - d->adapter->openDevToolsFrontend(devToolsPage->d_ptr->adapter); - else - d->adapter->closeDevToolsFrontend(); - } -} - -ASSERT_ENUMS_MATCH(FilePickerController::Open, QWebEnginePage::FileSelectOpen) -ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, QWebEnginePage::FileSelectOpenMultiple) - -QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) -{ -#if QT_CONFIG(filedialog) - const QStringList &filter = FilePickerController::nameFilters(acceptedMimeTypes); - QStringList ret; - QString str; - switch (static_cast<FilePickerController::FileChooserMode>(mode)) { - case FilePickerController::OpenMultiple: - ret = QFileDialog::getOpenFileNames(view(), QString(), QString(), filter.join(QStringLiteral(";;")), nullptr, QFileDialog::HideNameFilterDetails); - 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")); - if (!str.isNull()) - ret << str; - break; - case FilePickerController::Save: - str = QFileDialog::getSaveFileName(view(), QString(), (QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + oldFiles.first())); - if (!str.isNull()) - ret << str; - break; - case FilePickerController::Open: - str = QFileDialog::getOpenFileName(view(), QString(), oldFiles.first(), filter.join(QStringLiteral(";;")), nullptr, QFileDialog::HideNameFilterDetails); - if (!str.isNull()) - ret << str; - break; - } - return ret; -#else - Q_UNUSED(mode); - Q_UNUSED(oldFiles); - Q_UNUSED(acceptedMimeTypes); - - return QStringList(); -#endif // QT_CONFIG(filedialog) -} - -void QWebEnginePage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg) -{ - Q_UNUSED(securityOrigin); -#if QT_CONFIG(messagebox) - QMessageBox::information(view(), - QStringLiteral("Javascript Alert - %1").arg(url().toString()), - msg.toHtmlEscaped()); -#else - Q_UNUSED(msg); -#endif // QT_CONFIG(messagebox) -} - -bool QWebEnginePage::javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) -{ - Q_UNUSED(securityOrigin); -#if QT_CONFIG(messagebox) - return (QMessageBox::information(view(), - QStringLiteral("Javascript Confirm - %1").arg(url().toString()), - msg.toHtmlEscaped(), - QMessageBox::Ok, - QMessageBox::Cancel) == QMessageBox::Ok); -#else - Q_UNUSED(msg); - return false; -#endif // QT_CONFIG(messagebox) -} - -bool QWebEnginePage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString *result) -{ - Q_UNUSED(securityOrigin); -#if QT_CONFIG(inputdialog) - bool ret = false; - if (result) - *result = QInputDialog::getText(view(), - QStringLiteral("Javascript Prompt - %1").arg(url().toString()), - msg.toHtmlEscaped(), - QLineEdit::Normal, - defaultValue.toHtmlEscaped(), - &ret); - return ret; -#else - Q_UNUSED(msg); - Q_UNUSED(defaultValue); - Q_UNUSED(result); - return false; -#endif // QT_CONFIG(inputdialog) -} - -void QWebEnginePage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) -{ - static QLoggingCategory loggingCategory("js", QtWarningMsg); - static QByteArray file = sourceID.toUtf8(); - QMessageLogger logger(file.constData(), lineNumber, nullptr, loggingCategory.categoryName()); - - switch (level) { - case JavaScriptConsoleMessageLevel::InfoMessageLevel: - if (loggingCategory.isInfoEnabled()) - logger.info().noquote() << message; - break; - case JavaScriptConsoleMessageLevel::WarningMessageLevel: - if (loggingCategory.isWarningEnabled()) - logger.warning().noquote() << message; - break; - case JavaScriptConsoleMessageLevel::ErrorMessageLevel: - if (loggingCategory.isCriticalEnabled()) - logger.critical().noquote() << message; - break; - } -} - -bool QWebEnginePage::certificateError(const QWebEngineCertificateError &) -{ - return false; -} - -bool QWebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) -{ - Q_UNUSED(url); - Q_UNUSED(type); - Q_UNUSED(isMainFrame); - return true; -} - -QPointF QWebEnginePage::scrollPosition() const -{ - Q_D(const QWebEnginePage); - return d->adapter->lastScrollOffset(); -} - -QSizeF QWebEnginePage::contentsSize() const -{ - Q_D(const QWebEnginePage); - return d->adapter->lastContentsSize(); -} - -/*! - Renders the current content of the page into a PDF document and saves it - in the location specified in \a filePath. - The page size and orientation of the produced PDF document are taken from - the values specified in \a pageLayout. - - This method issues an asynchronous request for printing the web page into - a PDF and returns immediately. - To be informed about the result of the request, connect to the signal - pdfPrintingFinished(). - - If a file already exists at the provided file path, it will be overwritten. - \since 5.7 - \sa pdfPrintingFinished() -*/ -void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &pageLayout) -{ -#if QT_CONFIG(webengine_printing_and_pdf) - Q_D(const QWebEnginePage); - if (d->currentPrinter) { - qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); - return; - } - d->ensureInitialized(); - d->adapter->printToPDF(pageLayout, filePath); -#else - Q_UNUSED(filePath); - Q_UNUSED(pageLayout); -#endif -} - - -/*! - Renders the current content of the page into a PDF document and returns a byte array containing the PDF data - as parameter to \a resultCallback. - The page size and orientation of the produced PDF document are taken from the values specified in \a pageLayout. - - The \a resultCallback must take a const reference to a QByteArray as parameter. If printing was successful, this byte array - will contain the PDF data, otherwise, the byte array will be empty. - - \warning We guarantee that the callback (\a resultCallback) is always called, but it might be done - during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid - value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it. - - \since 5.7 -*/ -void QWebEnginePage::printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &pageLayout) -{ - Q_D(QWebEnginePage); -#if QT_CONFIG(webengine_printing_and_pdf) - if (d->currentPrinter) { - qWarning("Cannot print to PDF while at the same time printing on printer %ls", qUtf16Printable(d->currentPrinter->printerName())); - d->m_callbacks.invokeEmpty(resultCallback); - return; - } - d->ensureInitialized(); - quint64 requestId = d->adapter->printToPDFCallbackResult(pageLayout); - d->m_callbacks.registerCallback(requestId, resultCallback); -#else - Q_UNUSED(pageLayout); - d->m_callbacks.invokeEmpty(resultCallback); -#endif -} - -/*! - Renders the current content of the page into a temporary PDF document, then prints it using \a printer. - - The settings for creating and printing the PDF document will be retrieved from the \a printer - object. - It is the users responsibility to ensure the \a printer remains valid until \a resultCallback - has been called. - - \note Printing runs on the browser process, which is by default not sandboxed. - - The \a resultCallback must take a boolean as parameter. If printing was successful, this - boolean will have the value \c true, otherwise, its value will be \c false. - - \warning We guarantee that the callback (\a resultCallback) is always called, but it might be done - during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid - value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it. - - \since 5.8 -*/ -void QWebEnginePage::print(QPrinter *printer, const QWebEngineCallback<bool> &resultCallback) -{ - Q_D(QWebEnginePage); -#if QT_CONFIG(webengine_printing_and_pdf) - if (d->currentPrinter) { - qWarning("Cannot print page on printer %ls: Already printing on %ls.", qUtf16Printable(printer->printerName()), qUtf16Printable(d->currentPrinter->printerName())); - d->m_callbacks.invokeDirectly(resultCallback, false); - return; - } - d->currentPrinter = printer; - d->ensureInitialized(); - quint64 requestId = d->adapter->printToPDFCallbackResult(printer->pageLayout(), - printer->colorMode() == QPrinter::Color, - false); - d->m_callbacks.registerCallback(requestId, resultCallback); -#else - Q_UNUSED(printer); - d->m_callbacks.invokeDirectly(resultCallback, false); -#endif -} - -/*! - \since 5.7 - - Returns additional data about the current context menu. It is only guaranteed to be valid during the call to the QWebEngineView::contextMenuEvent() - handler of the associated QWebEngineView. - - \sa createStandardContextMenu() -*/ -const QWebEngineContextMenuData &QWebEnginePage::contextMenuData() const -{ - Q_D(const QWebEnginePage); - return d->contextData; -} - -/*! - \enum QWebEnginePage::LifecycleState - \since 5.14 - - This enum describes the lifecycle state of the page: - - \value Active - Normal state. - \value Frozen - Low CPU usage state where most HTML task sources are suspended. - \value Discarded - Very low resource usage state where the entire browsing context is discarded. - - \sa lifecycleState, {Page Lifecycle API}, {WebEngine Lifecycle Example} -*/ - -/*! - \property QWebEnginePage::lifecycleState - \since 5.14 - - \brief The current lifecycle state of the page. - - The following restrictions are enforced by the setter: - - \list - \li A \l{visible} page must remain in the \c{Active} state. - \li If the page is being inspected by a \l{devToolsPage} then both pages must - remain in the \c{Active} states. - \li A page in the \c{Discarded} state can only transition to the \c{Active} - state. This will cause a reload of the page. - \endlist - - These are the only hard limits on the lifecycle state, but see also - \l{recommendedState} for the recommended soft limits. - - \sa recommendedState, {Page Lifecycle API}, {WebEngine Lifecycle Example} -*/ - -QWebEnginePage::LifecycleState QWebEnginePage::lifecycleState() const -{ - Q_D(const QWebEnginePage); - return static_cast<LifecycleState>(d->adapter->lifecycleState()); -} - -void QWebEnginePage::setLifecycleState(LifecycleState state) -{ - Q_D(QWebEnginePage); - d->adapter->setLifecycleState(static_cast<WebContentsAdapterClient::LifecycleState>(state)); -} - -/*! - \property QWebEnginePage::recommendedState - \since 5.14 - - \brief The recommended limit for the lifecycle state of the page. - - Setting the lifecycle state to a lower resource usage state than the - recommended state may cause side-effects such as stopping background audio - playback or loss of HTML form input. Setting the lifecycle state to a higher - resource state is however completely safe. - - \sa lifecycleState, {Page Lifecycle API}, {WebEngine Lifecycle Example} -*/ - -QWebEnginePage::LifecycleState QWebEnginePage::recommendedState() const -{ - Q_D(const QWebEnginePage); - return static_cast<LifecycleState>(d->adapter->recommendedState()); -} - -/*! - \property QWebEnginePage::visible - \since 5.14 - - \brief Whether the page is considered visible in the Page Visibility API. - - Setting this property changes the \c{Document.hidden} and the - \c{Document.visibilityState} properties in JavaScript which web sites can use - to voluntarily reduce their resource usage if they are not visible to the - user. - - If the page is connected to a \l{view} then this property will be managed - automatically by the view according to it's own visibility. - - \sa lifecycleState -*/ - -bool QWebEnginePage::isVisible() const -{ - Q_D(const QWebEnginePage); - return d->adapter->isVisible(); -} - -void QWebEnginePage::setVisible(bool visible) -{ - Q_D(QWebEnginePage); - - if (!d->adapter->isInitialized()) { - // On the one hand, it is too early to initialize here. The application - // may call show() before load(), or it may call show() from - // createWindow(), and then we would create an unnecessary blank - // WebContents here. On the other hand, if the application calls show() - // then it expects something to be shown, so we have to initialize. - // Therefore we have to delay the initialization via the event loop. - if (visible) - d->wasShownTimer.start(); - else - d->wasShownTimer.stop(); - return; - } - - d->adapter->setVisible(visible); -} - -#if QT_CONFIG(action) -QContextMenuBuilder::QContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data, - QWebEnginePage *page, - QMenu *menu) - : QtWebEngineCore::RenderViewContextMenuQt(data) - , m_page(page) - , m_menu(menu) -{ -} - -bool QContextMenuBuilder::hasInspector() -{ - return m_page->d_ptr->adapter->hasInspector(); -} - -bool QContextMenuBuilder::isFullScreenMode() -{ - return m_page->d_ptr->isFullScreenMode(); -} - -void QContextMenuBuilder::addMenuItem(ContextMenuItem menuItem) -{ - QPointer<QWebEnginePage> thisRef(m_page); - QAction *action = 0; - - switch (menuItem) { - case ContextMenuItem::Back: - action = thisRef->action(QWebEnginePage::Back); - break; - case ContextMenuItem::Forward: - action = thisRef->action(QWebEnginePage::Forward); - break; - case ContextMenuItem::Reload: - action = thisRef->action(QWebEnginePage::Reload); - break; - case ContextMenuItem::Cut: - action = thisRef->action(QWebEnginePage::Cut); - break; - case ContextMenuItem::Copy: - action = thisRef->action(QWebEnginePage::Copy); - break; - case ContextMenuItem::Paste: - action = thisRef->action(QWebEnginePage::Paste); - break; - case ContextMenuItem::Undo: - action = thisRef->action(QWebEnginePage::Undo); - break; - case ContextMenuItem::Redo: - action = thisRef->action(QWebEnginePage::Redo); - break; - case ContextMenuItem::SelectAll: - action = thisRef->action(QWebEnginePage::SelectAll); - break; - case ContextMenuItem::PasteAndMatchStyle: - action = thisRef->action(QWebEnginePage::PasteAndMatchStyle); - break; - case ContextMenuItem::OpenLinkInNewWindow: - action = thisRef->action(QWebEnginePage::OpenLinkInNewWindow); - break; - case ContextMenuItem::OpenLinkInNewTab: - action = thisRef->action(QWebEnginePage::OpenLinkInNewTab); - break; - case ContextMenuItem::CopyLinkToClipboard: - action = thisRef->action(QWebEnginePage::CopyLinkToClipboard); - break; - case ContextMenuItem::DownloadLinkToDisk: - action = thisRef->action(QWebEnginePage::DownloadLinkToDisk); - break; - case ContextMenuItem::CopyImageToClipboard: - action = thisRef->action(QWebEnginePage::CopyImageToClipboard); - break; - case ContextMenuItem::CopyImageUrlToClipboard: - action = thisRef->action(QWebEnginePage::CopyImageUrlToClipboard); - break; - case ContextMenuItem::DownloadImageToDisk: - action = thisRef->action(QWebEnginePage::DownloadImageToDisk); - break; - case ContextMenuItem::CopyMediaUrlToClipboard: - action = thisRef->action(QWebEnginePage::CopyMediaUrlToClipboard); - break; - case ContextMenuItem::ToggleMediaControls: - action = thisRef->action(QWebEnginePage::ToggleMediaControls); - break; - case ContextMenuItem::ToggleMediaLoop: - action = thisRef->action(QWebEnginePage::ToggleMediaLoop); - break; - case ContextMenuItem::DownloadMediaToDisk: - action = thisRef->action(QWebEnginePage::DownloadMediaToDisk); - break; - case ContextMenuItem::InspectElement: - action = thisRef->action(QWebEnginePage::InspectElement); - break; - case ContextMenuItem::ExitFullScreen: - action = thisRef->action(QWebEnginePage::ExitFullScreen); - break; - case ContextMenuItem::SavePage: - action = thisRef->action(QWebEnginePage::SavePage); - break; - case ContextMenuItem::ViewSource: - action = thisRef->action(QWebEnginePage::ViewSource); - break; - case ContextMenuItem::SpellingSuggestions: - for (int i=0; i < m_contextData.spellCheckerSuggestions().count() && i < 4; i++) { - action = new QAction(m_menu); - QString replacement = m_contextData.spellCheckerSuggestions().at(i); - QObject::connect(action, &QAction::triggered, [thisRef, replacement] { if (thisRef) thisRef->replaceMisspelledWord(replacement); }); - action->setText(replacement); - m_menu->addAction(action); - } - return; - case ContextMenuItem::Separator: - if (!m_menu->isEmpty()) - m_menu->addSeparator(); - return; - } - action->setEnabled(isMenuItemEnabled(menuItem)); - m_menu->addAction(action); -} - -bool QContextMenuBuilder::isMenuItemEnabled(ContextMenuItem menuItem) -{ - switch (menuItem) { - case ContextMenuItem::Back: - return m_page->d_ptr->adapter->canGoBack(); - case ContextMenuItem::Forward: - return m_page->d_ptr->adapter->canGoForward(); - case ContextMenuItem::Reload: - return true; - case ContextMenuItem::Cut: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanCut; - case ContextMenuItem::Copy: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanCopy; - case ContextMenuItem::Paste: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanPaste; - case ContextMenuItem::Undo: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanUndo; - case ContextMenuItem::Redo: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanRedo; - case ContextMenuItem::SelectAll: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanSelectAll; - case ContextMenuItem::PasteAndMatchStyle: - return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanPaste; - case ContextMenuItem::OpenLinkInNewWindow: - case ContextMenuItem::OpenLinkInNewTab: - case ContextMenuItem::CopyLinkToClipboard: - case ContextMenuItem::DownloadLinkToDisk: - case ContextMenuItem::CopyImageToClipboard: - case ContextMenuItem::CopyImageUrlToClipboard: - case ContextMenuItem::DownloadImageToDisk: - case ContextMenuItem::CopyMediaUrlToClipboard: - case ContextMenuItem::ToggleMediaControls: - case ContextMenuItem::ToggleMediaLoop: - case ContextMenuItem::DownloadMediaToDisk: - case ContextMenuItem::InspectElement: - case ContextMenuItem::ExitFullScreen: - case ContextMenuItem::SavePage: - return true; - case ContextMenuItem::ViewSource: - return m_page->d_ptr->adapter->canViewSource(); - case ContextMenuItem::SpellingSuggestions: - case ContextMenuItem::Separator: - return true; - } - Q_UNREACHABLE(); -} -#endif // QT_CONFIG(action) - -QT_END_NAMESPACE - -#include "moc_qwebenginepage.cpp" |