Revision control

Copy as Markdown

// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qquickwebview_p.h"
#include "qquickwebviewloadrequest_p.h"
#include "qquickwebviewsettings_p.h"
#include <QtWebView/qwebviewloadinginfo.h>
#include <QtWebView/private/qwebviewfactory_p.h>
#include <QtWebView/private/qwebview_p.h>
#include <QtQml/qqmlengine.h>
#include <QtCore/qmutex.h>
namespace {
class CallbackStorage
{
public:
int insertCallback(const QJSValue &callback)
{
QMutexLocker locker(&m_mtx);
const int nextId = qMax(++m_counter, 0);
if (nextId == 0)
m_counter = 1;
m_callbacks.insert(nextId, callback);
return nextId;
}
QJSValue takeCallback(int callbackId)
{
QMutexLocker lock(&m_mtx);
return m_callbacks.take(callbackId);
}
private:
QMutex m_mtx;
int m_counter;
QHash<int, QJSValue> m_callbacks;
};
} // namespace
Q_GLOBAL_STATIC(CallbackStorage, callbacks)
/*!
\qmltype WebView
\inqmlmodule QtWebView
\ingroup qtwebview
\brief A component for displaying web content.
WebView is a component for displaying web content which is implemented using native
APIs on the platforms where this is available, thus it does not necessarily require
including a full web browser stack as part of the application.
To make the Qt WebView module function correctly across all platforms, it is necessary
to call \l {qtwebview-initialize}{QtWebView::initialize}() right after creating the
QGuiApplication instance.
\note Due to platform limitations overlapping the WebView and other QML components
is not supported.
*/
QQuickWebView::QQuickWebView(QQuickItem *parent)
: QQuickWindowContainer(parent),
m_webView(new QWebView(QWebViewFactory::Hint::QuickInitialization)),
m_settings(new QQuickWebViewSettings(m_webView->settings()))
{
if (QWindow *nativeWindow = m_webView->d->nativeWindow())
setContainedWindow(nativeWindow);
connect(m_webView, &QWebView::titleChanged, this, &QQuickWebView::titleChanged);
connect(m_webView, &QWebView::urlChanged, this, &QQuickWebView::urlChanged);
connect(m_webView, &QWebView::loadProgressChanged, this, &QQuickWebView::loadProgressChanged);
connect(m_webView, &QWebView::loadingChanged, this, &QQuickWebView::onLoadingChanged);
connect(m_webView, &QWebView::httpUserAgentStringChanged,
this, &QQuickWebView::httpUserAgentChanged);
connect(m_webView, &QWebView::cookieAdded, this, &QQuickWebView::cookieAdded);
connect(m_webView, &QWebView::cookieRemoved, this, &QQuickWebView::cookieRemoved);
m_webView->QObject::setParent(this);
m_settings->QObject::setParent(this);
}
QQuickWebView::~QQuickWebView() { }
/*!
\qmlproperty url QtWebView::WebView::httpUserAgent
\since QtWebView 1.14
The user agent in use.
*/
/*!
\qmlsignal QtWebView::WebView::httpUserAgentChanged(string userAgent)
This signal is emitted whenever the \a userAgent of the view changes.
\sa httpUserAgent
*/
void QQuickWebView::setHttpUserAgent(const QString &userAgent)
{
m_webView->setHttpUserAgentString(userAgent);
}
QString QQuickWebView::httpUserAgent() const
{
return m_webView->httpUserAgentString();
}
/*!
\qmlproperty url QtWebView::WebView::url
The URL of currently loaded web page. Changing this will trigger
loading new content.
The URL is used as-is. URLs that originate from user input should
be parsed with QUrl::fromUserInput().
\note The WebView does not support loading content through the Qt Resource system.
*/
/*!
\qmlsignal QtWebView::WebView::urlChanged(url url)
This signal is emitted whenever the \a url of the view changes.
\sa url
*/
void QQuickWebView::setUrl(const QUrl &url)
{
m_webView->setUrl(url);
}
/*!
\qmlproperty string QtWebView::WebView::title
\readonly
The title of the currently loaded web page.
*/
/*!
\qmlsignal QtWebView::WebView::titleChanged(string title)
This signal is emitted whenever the \a title of the view changes.
\sa title
*/
QString QQuickWebView::title() const
{
return m_webView->title();
}
QUrl QQuickWebView::url() const
{
return m_webView->url();
}
/*!
\qmlproperty bool QtWebView::WebView::canGoBack
\readonly
Holds \c true if it's currently possible to navigate back in the web history.
*/
bool QQuickWebView::canGoBack() const
{
return m_webView->canGoBack();
}
/*!
\qmlproperty bool QtWebView::WebView::canGoForward
\readonly
Holds \c true if it's currently possible to navigate forward in the web history.
*/
bool QQuickWebView::canGoForward() const
{
return m_webView->canGoForward();
}
/*!
\qmlproperty int QtWebView::WebView::loadProgress
\readonly
The current load progress of the web content, represented as
an integer between 0 and 100.
*/
/*!
\qmlsignal QtWebView::WebView::loadProgressChanged(int loadProgress)
This signal is continuously emitted during the loading of a web page.
The \a loadProgress parameter is a value between 0 and 100, indicating
what percentage of the web page has been loaded. The intended use
for this is to display a progress bar to the user.
\note Some backends do not support fractional load progress changes,
and will only emit this signal at the start and end of a load, with
values of 0 and 100, respecively.
\sa loadingChanged
*/
int QQuickWebView::loadProgress() const
{
return m_webView->loadProgress();
}
/*!
\qmlproperty bool QtWebView::WebView::loading
\readonly
Holds \c true if the WebView is currently in the process of loading
new content, \c false otherwise.
\sa loadingChanged()
*/
/*!
\qmlsignal QtWebView::WebView::loadingChanged(WebViewLoadRequest loadRequest)
This signal is emitted when the state of loading the web content changes.
By handling this signal it's possible, for example, to react to page load
errors.
The \a loadRequest parameter holds the \e url and \e status of the request,
as well as an \e errorString containing an error message for a failed
request.
\sa WebViewLoadRequest
*/
bool QQuickWebView::isLoading() const
{
return m_webView->isLoading();
}
/*!
\qmlmethod void QtWebView::WebView::goBack()
Navigates back in the web history.
*/
void QQuickWebView::goBack()
{
m_webView->goBack();
}
/*!
\qmlmethod void QtWebView::WebView::goForward()
Navigates forward in the web history.
*/
void QQuickWebView::goForward()
{
m_webView->goForward();
}
/*!
\qmlmethod void QtWebView::WebView::reload()
Reloads the current \l url.
*/
void QQuickWebView::reload()
{
m_webView->reload();
}
/*!
\qmlmethod void QtWebView::WebView::stop()
Stops loading the current \l url.
*/
void QQuickWebView::stop()
{
m_webView->stop();
}
/*!
\qmlmethod void QtWebView::WebView::loadHtml(string html, url baseUrl)
Loads the specified \a html content to the web view.
This method offers a lower-level alternative to the \l url property,
which references HTML pages via URL.
External objects such as stylesheets or images referenced in the HTML
document should be located relative to \a baseUrl. For example, if \a html
is the base URL, then an image referenced with the relative url, \c diagram.png,
\note The WebView does not support loading content through the Qt Resource system.
\sa url
*/
void QQuickWebView::loadHtml(const QString &html, const QUrl &baseUrl)
{
m_webView->loadHtml(html, baseUrl);
}
/*!
\qmlmethod void QtWebView::WebView::runJavaScript(string script, variant callback)
Runs the specified JavaScript.
In case a \a callback function is provided, it will be invoked after the \a script
finished running.
\badcode
runJavaScript("document.title", function(result) { console.log(result); });
\endcode
*/
void QQuickWebView::runJavaScript(const QString &script, const QJSValue &callback)
{
if (callback.isCallable()) {
int callbackId = callbacks->insertCallback(callback);
QPointer<QQmlEngine> weakEngine = qmlEngine(this);
m_webView->runJavaScript(script, [callbackId, weakEngine](const QVariant &result) {
QJSValue callback = callbacks->takeCallback(callbackId);
if (!weakEngine) {
qWarning("No JavaScript engine, unable to handle JavaScript callback!");
return;
}
Q_ASSERT(callback.isCallable());
QJSValueList args;
args.append(weakEngine->toScriptValue(result));
callback.call(args);
});
} else {
m_webView->runJavaScript(script);
}
}
/*!
\qmlmethod void QtWebView::WebView::setCookie(string domain, string name, string value)
\since QtWebView 6.3
Adds a cookie with the specified \a domain, \a name and \a value.
The \l cookieAdded signal will be emitted when the cookie is added.
*/
/*!
\qmlsignal QtWebView::WebView::cookieAdded(string domain, string name)
This signal is emitted when a cookie is added.
The parameters provide information about the \a domain and the \a name of the added cookie.
\note When Qt WebEngine module is used as backend, cookieAdded signal will be emitted for any
cookie added to the underlying QWebEngineCookieStore, including those added by websites.
In other cases cookieAdded signal is only emitted for cookies explicitly added with \l setCookie().
*/
void QQuickWebView::setCookie(const QString &domain, const QString &name, const QString &value)
{
m_webView->setCookie(domain, name, value);
}
/*!
\qmlmethod void QtWebView::WebView::deleteCookie(string domain, string name)
\since QtWebView 6.3
Deletes a cookie with the specified \a domain and \a name.
The \l cookieRemoved signal will be emitted when the cookie is deleted.
*/
/*!
\qmlsignal QtWebView::WebView::cookieRemoved(string domain, string name)
This signal is emitted when a cookie is deleted.
The parameters provide information about the \a domain and the \a name of the deleted cookie.
*/
void QQuickWebView::deleteCookie(const QString &domain, const QString &name)
{
m_webView->deleteCookie(domain, name);
}
/*!
\qmlmethod void QtWebView::WebView::deleteAllCookies()
\since QtWebView 6.3
Deletes all the cookies.
*/
void QQuickWebView::deleteAllCookies()
{
m_webView->deleteAllCookies();
}
void QQuickWebView::onLoadingChanged(const QWebViewLoadingInfo &loadRequest)
{
QQuickWebViewLoadRequest qqLoadRequest(loadRequest);
Q_EMIT loadingChanged(&qqLoadRequest);
}
/*!
\qmlproperty WebViewSettings WebView::settings
\readonly
\since QtWebView 6.5
Settings object for the WebView.
\sa WebViewSettings
*/
QQuickWebViewSettings *QQuickWebView::settings() const
{
return m_settings;
}
void QQuickWebView::classBegin()
{
m_webView->d->initialize(this);
QQuickWindowContainer::classBegin();
}