summaryrefslogtreecommitdiffstats
path: root/src/plugins/windows/qwebview2webview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/windows/qwebview2webview.cpp')
-rw-r--r--src/plugins/windows/qwebview2webview.cpp631
1 files changed, 631 insertions, 0 deletions
diff --git a/src/plugins/windows/qwebview2webview.cpp b/src/plugins/windows/qwebview2webview.cpp
new file mode 100644
index 0000000..255c5ab
--- /dev/null
+++ b/src/plugins/windows/qwebview2webview.cpp
@@ -0,0 +1,631 @@
+// Copyright (C) 2025 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
+
+#include "qwebview2webview_p.h"
+#include <private/qwebviewloadrequest_p.h>
+#include <QtCore/private/qfunctions_win_p.h>
+#include <QtWidgets/QtWidgets>
+
+QString WebErrorStatusToString(COREWEBVIEW2_WEB_ERROR_STATUS status)
+{
+ switch (status)
+ {
+#define STATUS_ENTRY(statusValue) \
+ case statusValue: \
+ return QString(L#statusValue);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_UNKNOWN);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_SERVER_UNREACHABLE);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_TIMEOUT);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_ERROR_HTTP_INVALID_SERVER_RESPONSE);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_RESET);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_DISCONNECTED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_CANNOT_CONNECT);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_HOST_NAME_NOT_RESOLVED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_REDIRECT_FAILED);
+ STATUS_ENTRY(COREWEBVIEW2_WEB_ERROR_STATUS_UNEXPECTED_ERROR);
+
+#undef STATUS_ENTRY
+ case COREWEBVIEW2_WEB_ERROR_STATUS_VALID_AUTHENTICATION_CREDENTIALS_REQUIRED:
+ case COREWEBVIEW2_WEB_ERROR_STATUS_VALID_PROXY_AUTHENTICATION_REQUIRED:
+ break;
+ }
+
+ return QString(L"ERROR");
+}
+
+QWebview2WebViewSettingsPrivate::QWebview2WebViewSettingsPrivate(QObject *p)
+ : QAbstractWebViewSettings(p)
+{
+}
+
+void QWebview2WebViewSettingsPrivate::init(ICoreWebView2Controller* viewController)
+{
+ if (viewController != nullptr) {
+ m_webviewController = viewController;
+ HRESULT hr = m_webviewController->get_CoreWebView2(&m_webview);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+}
+
+bool QWebview2WebViewSettingsPrivate::localStorageEnabled() const
+{
+ return true;
+}
+
+bool QWebview2WebViewSettingsPrivate::javaScriptEnabled() const
+{
+ if (!m_webview)
+ return false;
+ ComPtr<ICoreWebView2Settings> settings;
+ HRESULT hr = m_webview->get_Settings(&settings);
+ Q_ASSERT_SUCCEEDED(hr);
+ BOOL isEnabled;
+ hr = settings->get_IsScriptEnabled(&isEnabled);
+ Q_ASSERT_SUCCEEDED(hr);
+ return isEnabled;
+}
+
+bool QWebview2WebViewSettingsPrivate::localContentCanAccessFileUrls() const
+{
+ return m_allowFileAccess;
+}
+
+bool QWebview2WebViewSettingsPrivate::allowFileAccess() const
+{
+ return m_allowFileAccess;
+}
+
+void QWebview2WebViewSettingsPrivate::setLocalContentCanAccessFileUrls(bool enabled)
+{
+ Q_UNUSED(enabled);
+ qWarning("setLocalContentCanAccessFileUrls() not supported on this platform");
+}
+
+void QWebview2WebViewSettingsPrivate::setJavaScriptEnabled(bool enabled)
+{
+ if (!m_webview)
+ return;
+
+ ComPtr<ICoreWebView2Settings> settings;
+ HRESULT hr = m_webview->get_Settings(&settings);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = settings->put_IsScriptEnabled(enabled);
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+void QWebview2WebViewSettingsPrivate::setLocalStorageEnabled(bool enabled)
+{
+ Q_UNUSED(enabled);
+ qWarning("setLocalStorageEnabled() not supported on this platform");
+}
+
+void QWebview2WebViewSettingsPrivate::setAllowFileAccess(bool enabled)
+{
+ m_allowFileAccess = enabled;
+}
+
+QWebView2WebViewPrivate::QWebView2WebViewPrivate(QObject *parent)
+ : QAbstractWebView(parent),
+ m_settings(new QWebview2WebViewSettingsPrivate(this)),
+ m_isLoading(false)
+{
+ // Create a QWindow without a parent
+ // This window is used for initializing the WebView2
+ QWindow *hiddenWindow = new QWindow();
+ hiddenWindow->setFlag(Qt::Tool);
+ hiddenWindow->setFlag(Qt::FramelessWindowHint); // No border
+ hiddenWindow->setFlag(Qt::WindowDoesNotAcceptFocus); // No focus
+ hiddenWindow->setGeometry(0, 0, 1, 1);
+ hiddenWindow->setOpacity(0);
+ hiddenWindow->show();
+ m_webViewWindow = hiddenWindow;
+ HWND hWnd = (HWND)m_webViewWindow->winId();
+
+ // This is the container for WebView2 window after initialization
+ // is finished (WebView2 window initialization seems to be very
+ // sensitive, so we put it in the container after making sure that
+ // the initialization is done successfully).
+ // This needs reconsideration later because it might be the same
+ // kind of problem with this bug (QTBUG-137230)
+ m_window = new QWindow();
+ connect(m_window, &QWindow::widthChanged, this,
+ &QWebView2WebViewPrivate::updateWindowGeometry, Qt::QueuedConnection);
+ connect(m_window, &QWindow::heightChanged, this,
+ &QWebView2WebViewPrivate::updateWindowGeometry, Qt::QueuedConnection);
+ connect(m_window, &QWindow::screenChanged, this,
+ &QWebView2WebViewPrivate::updateWindowGeometry, Qt::QueuedConnection);
+
+ CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
+ Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
+ [hWnd, this](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
+ env->CreateCoreWebView2Controller(hWnd,
+ Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
+ [this](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
+ HRESULT hr;
+ if (controller != nullptr) {
+ m_webviewController = controller;
+ hr = m_webviewController->get_CoreWebView2(&m_webview);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ICoreWebView2_2> webview2;
+ HRESULT hr = m_webview->QueryInterface(IID_PPV_ARGS(&webview2));
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = webview2->get_CookieManager(&m_cookieManager);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ m_settings->init(m_webviewController.Get());
+
+ // Add a few settings for the webview
+ ComPtr<ICoreWebView2Settings> settings;
+ hr = m_webview->get_Settings(&settings);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = settings->put_IsScriptEnabled(TRUE);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = settings->put_AreDefaultScriptDialogsEnabled(TRUE);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = settings->put_IsWebMessageEnabled(TRUE);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ QMetaObject::invokeMethod(this,"updateWindowGeometry", Qt::QueuedConnection);
+
+ //Schedule an async task to navigate to the url
+ //Because this is a callback and it might be triggered with a delay
+ if (!m_url.isEmpty() && m_url.isValid() && !m_url.scheme().isEmpty()) {
+ hr = m_webview->Navigate((wchar_t*)m_url.toString().utf16());
+ Q_ASSERT_SUCCEEDED(hr);
+ } else if (m_initData != nullptr && !m_initData->m_html.isEmpty()) {
+ hr = m_webview->NavigateToString((wchar_t*)m_initData->m_html.utf16());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (m_initData != nullptr && m_initData->m_cookies.size() > 0) {
+ for (auto it = m_initData->m_cookies.constBegin();
+ it != m_initData->m_cookies.constEnd(); ++it)
+ setCookie(it->domain, it->name, it.value().value);
+ }
+ m_initData.release();
+
+ EventRegistrationToken token;
+ hr = m_webview->add_NavigationStarting(
+ Microsoft::WRL::Callback<ICoreWebView2NavigationStartingEventHandler>(
+ [this](ICoreWebView2* webview,
+ ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT {
+ return this->onNavigationStarting(webview, args);
+ }).Get(), &token);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = m_webview->add_NavigationCompleted(
+ Microsoft::WRL::Callback<ICoreWebView2NavigationCompletedEventHandler>(
+ [this](ICoreWebView2* webview,
+ ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT {
+ return this->onNavigationCompleted(webview, args);
+ }).Get(), &token);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ m_webview->add_WebResourceRequested(
+ Microsoft::WRL::Callback<ICoreWebView2WebResourceRequestedEventHandler>(
+ [this](ICoreWebView2* webview,
+ ICoreWebView2WebResourceRequestedEventArgs* args) -> HRESULT {
+ return this->onWebResourceRequested(webview, args);
+ }).Get(), &token);
+
+ hr = m_webview->add_ContentLoading(
+ Microsoft::WRL::Callback<ICoreWebView2ContentLoadingEventHandler>(
+ [this](ICoreWebView2* webview,
+ ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT {
+ return this->onContentLoading(webview, args);
+ }).Get(), &token);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ICoreWebView2_22> webview2;
+ hr = m_webview->QueryInterface(IID_PPV_ARGS(&webview2));
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = webview2->AddWebResourceRequestedFilterWithRequestSourceKinds(
+ L"file://*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL,
+ COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL);
+ Q_ASSERT_SUCCEEDED(hr);
+ return S_OK;
+ }).Get());
+ return S_OK;
+ }).Get());
+}
+
+QWebView2WebViewPrivate::~QWebView2WebViewPrivate()
+{
+ m_webViewWindow->destroy();
+ m_window->destroy();
+ m_webviewController = nullptr;
+ m_webViewWindow = nullptr;
+ m_webview = nullptr;
+}
+
+QString QWebView2WebViewPrivate::httpUserAgent() const
+{
+ if (m_webviewController) {
+ ComPtr<ICoreWebView2Settings> settings;
+ HRESULT hr = m_webview->get_Settings(&settings);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ICoreWebView2Settings2> settings2;
+ hr = settings->QueryInterface(IID_PPV_ARGS(&settings2));
+
+ if (settings2) {
+ wchar_t *userAgent;
+ hr = settings2->get_UserAgent(&userAgent);
+ Q_ASSERT_SUCCEEDED(hr);
+ QString userAgentString(userAgent);
+ CoTaskMemFree(userAgent);
+ return userAgentString;
+ }
+ }
+ qWarning() << "No http user agent available.";
+ return "";
+}
+
+void QWebView2WebViewPrivate::setHttpUserAgent(const QString &userAgent)
+{
+ if (m_webviewController) {
+ ComPtr<ICoreWebView2Settings> settings;
+ HRESULT hr = m_webview->get_Settings(&settings);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ICoreWebView2Settings2> settings2;
+ hr = settings->QueryInterface(IID_PPV_ARGS(&settings2));
+ if (settings2) {
+ hr = settings2->put_UserAgent((wchar_t*)userAgent.utf16());
+ Q_ASSERT_SUCCEEDED(hr);
+ emit httpUserAgentChanged(userAgent);
+ return;
+ }
+ }
+ qWarning() << "No http user agent setting available.";
+}
+
+void QWebView2WebViewPrivate::setUrl(const QUrl &url)
+{
+ m_url = url;
+ if (m_webview) {
+ HRESULT hr = m_webview->Navigate((wchar_t*)url.toString().utf16());
+ if (FAILED(hr)) {
+ emit loadingChanged(QWebViewLoadRequestPrivate(url,
+ QWebView::LoadFailedStatus,
+ QString()));
+ emit loadProgressChanged(100);
+ }
+ }
+}
+
+bool QWebView2WebViewPrivate::canGoBack() const
+{
+ BOOL canGoBack = false;
+ if (m_webviewController) {
+ HRESULT hr = m_webview->get_CanGoBack(&canGoBack);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ return canGoBack;
+}
+
+bool QWebView2WebViewPrivate::canGoForward() const
+{
+ BOOL canGoForward = false;
+ if (m_webviewController) {
+ HRESULT hr = m_webview->get_CanGoForward(&canGoForward);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ return canGoForward;
+}
+
+QString QWebView2WebViewPrivate::title() const
+{
+ if (m_webviewController) {
+ wchar_t *title;
+ HRESULT hr = m_webview->get_DocumentTitle(&title);
+ Q_ASSERT_SUCCEEDED(hr);
+ QString titleString(title);
+ CoTaskMemFree(title);
+ return titleString;
+ }
+ return QString();
+}
+
+int QWebView2WebViewPrivate::loadProgress() const
+{
+ return m_isLoading ? 0 : 100;
+}
+
+bool QWebView2WebViewPrivate::isLoading() const
+{
+ return m_isLoading;
+}
+
+
+QWindow* QWebView2WebViewPrivate::nativeWindow() const
+{
+ return m_window;
+}
+
+void QWebView2WebViewPrivate::goBack()
+{
+ if (m_webview)
+ Q_ASSERT_SUCCEEDED(m_webview->GoBack());
+}
+
+void QWebView2WebViewPrivate::goForward()
+{
+ if (m_webview)
+ Q_ASSERT_SUCCEEDED(m_webview->GoForward());
+}
+
+void QWebView2WebViewPrivate::reload()
+{
+ if (m_webview)
+ Q_ASSERT_SUCCEEDED(m_webview->Reload());
+}
+
+void QWebView2WebViewPrivate::stop()
+{
+ if (m_webview)
+ Q_ASSERT_SUCCEEDED(m_webview->Stop());
+}
+
+void QWebView2WebViewPrivate::loadHtml(const QString &html, const QUrl &baseUrl)
+{
+ if (!baseUrl.isEmpty())
+ qWarning("Base URLs for loadHtml() are not supported on this platform. The document will be treated as coming from 'about:blank'.");
+
+ QByteArray encoded("data:text/html;charset=UTF-8,");
+ encoded.append(html.toUtf8().toPercentEncoding());
+ m_url = QUrl(encoded);
+
+ if (m_webview) {
+ Q_ASSERT_SUCCEEDED(m_webview->NavigateToString((wchar_t*)html.utf16()));
+ } else {
+ if (m_initData == nullptr)
+ m_initData = std::make_unique<QWebViewInitData>();
+ m_initData->m_html = html;
+ }
+}
+
+void QWebView2WebViewPrivate::setCookie(const QString &domain,
+ const QString &name,
+ const QString &value)
+{
+ if (m_webview) {
+ if (m_cookieManager) {
+ ComPtr<ICoreWebView2Cookie> cookie;
+ HRESULT hr = m_cookieManager->CreateCookie((wchar_t*)name.utf16(),
+ (wchar_t*)value.utf16(),
+ (wchar_t*)domain.utf16(),
+ L"",
+ &cookie);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = m_cookieManager->AddOrUpdateCookie(cookie.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ emit cookieAdded(domain, name);
+ }
+ } else {
+ if (m_initData == nullptr)
+ m_initData = std::make_unique<QWebViewInitData>();
+ m_initData->m_cookies.insert(domain + "/" + name, {domain, name, value});
+ }
+}
+
+void QWebView2WebViewPrivate::deleteCookie(const QString &domain, const QString &cookieName)
+{
+ if (m_webview) {
+ if (m_cookieManager) {
+ QString uri = domain;
+ if (!uri.startsWith("http"))
+ uri = "https://" + uri;
+ HRESULT hr = m_cookieManager->GetCookies((wchar_t*)uri.utf16(),
+ Microsoft::WRL::Callback<ICoreWebView2GetCookiesCompletedHandler>(
+ [cookieName, domain, this](HRESULT result, ICoreWebView2CookieList* cookieList)->HRESULT
+ {
+ UINT count = 0;
+ cookieList->get_Count(&count);
+ bool cookieFound = false;
+
+ for (UINT i = 0; i < count; ++i) {
+ ComPtr<ICoreWebView2Cookie> cookie;
+ if (SUCCEEDED(cookieList->GetValueAtIndex(i, &cookie))) {
+ wchar_t *namePtr;
+ if (SUCCEEDED(cookie->get_Name(&namePtr))) {
+ QString name(namePtr);
+ CoTaskMemFree(namePtr);
+ if (cookieName == name) {
+ cookieFound = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (cookieFound) {
+ HRESULT hr = m_cookieManager->DeleteCookiesWithDomainAndPath((wchar_t*)cookieName.utf16(),
+ (wchar_t*)domain.utf16(),
+ L"");
+ Q_ASSERT_SUCCEEDED(hr);
+ emit cookieRemoved(domain, cookieName);
+ }
+
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ } else if (m_initData != nullptr) {
+ m_initData->m_cookies.remove(domain + "/" + cookieName);
+ }
+}
+
+void QWebView2WebViewPrivate::deleteAllCookies()
+{
+ if (m_webview) {
+ if (m_cookieManager) {
+ HRESULT hr = m_cookieManager->GetCookies(L"",
+ Microsoft::WRL::Callback<ICoreWebView2GetCookiesCompletedHandler>(
+ [this](HRESULT result, ICoreWebView2CookieList* cookieList) -> HRESULT
+ {
+ UINT count = 0;
+ cookieList->get_Count(&count);
+ for (UINT i = 0; i < count; ++i) {
+ ComPtr<ICoreWebView2Cookie> cookie;
+ if (SUCCEEDED(cookieList->GetValueAtIndex(i, &cookie))) {
+ wchar_t *domain;
+ wchar_t *name;
+ if (SUCCEEDED(cookie->get_Domain(&domain))) {
+ if (SUCCEEDED(cookie->get_Name(&name))) {
+ emit cookieRemoved(QString(domain), QString(name));
+ CoTaskMemFree(name);
+ }
+ CoTaskMemFree(domain);
+ }
+ }
+ }
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = m_cookieManager->DeleteAllCookies();
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ } else if (m_initData != nullptr) {
+ m_initData->m_cookies.clear();
+ }
+}
+
+HRESULT QWebView2WebViewPrivate::onNavigationStarting(ICoreWebView2* webview, ICoreWebView2NavigationStartingEventArgs* args)
+{
+ wchar_t *uri;
+ HRESULT hr = args->get_Uri(&uri);
+ Q_ASSERT_SUCCEEDED(hr);
+ std::wstring_view source(uri);
+ m_url = QString(source);
+ emit urlChanged(m_url);
+ CoTaskMemFree(uri);
+ return S_OK;
+}
+
+
+HRESULT QWebView2WebViewPrivate::onNavigationCompleted(ICoreWebView2* webview, ICoreWebView2NavigationCompletedEventArgs* args)
+{
+ m_isLoading = false;
+
+ BOOL isSuccess;
+ HRESULT hr = args->get_IsSuccess(&isSuccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QWebView::LoadStatus status = isSuccess ?
+ QWebView::LoadSucceededStatus :
+ QWebView::LoadFailedStatus;
+
+ COREWEBVIEW2_WEB_ERROR_STATUS errorStatus;
+ hr = args->get_WebErrorStatus(&errorStatus);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (errorStatus != COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED) {
+ const QString errorStr = isSuccess ? "" : WebErrorStatusToString(errorStatus);
+ emit loadingChanged(QWebViewLoadRequestPrivate(m_url,
+ status,
+ errorStr));
+ emit titleChanged(title());
+ emit loadProgressChanged(100);
+ } else {
+ emit loadingChanged(QWebViewLoadRequestPrivate(m_url,
+ QWebView::LoadStoppedStatus,
+ QString()));
+ }
+ return S_OK;
+}
+
+HRESULT QWebView2WebViewPrivate::onWebResourceRequested(ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args)
+{
+ ComPtr<ICoreWebView2WebResourceRequest> request;
+ ComPtr<ICoreWebView2WebResourceResponse> response;
+ HRESULT hr = args->get_Request(&request);
+ Q_ASSERT_SUCCEEDED(hr);
+ wchar_t *uri;
+ hr = request->get_Uri(&uri);
+ std::wstring_view source(uri);
+
+ if (!m_settings->allowFileAccess()) {
+ ComPtr<ICoreWebView2Environment> environment;
+ ComPtr<ICoreWebView2_2> webview2;
+ m_webview->QueryInterface(IID_PPV_ARGS(&webview2));
+ webview2->get_Environment(&environment);
+ Q_ASSERT_SUCCEEDED(
+ environment->CreateWebResourceResponse(
+ nullptr, 403, L"Access Denied", L"", &response));
+ Q_ASSERT_SUCCEEDED(args->put_Response(response.Get()));
+ }
+
+ CoTaskMemFree(uri);
+ return S_OK;
+}
+
+HRESULT QWebView2WebViewPrivate::onContentLoading(ICoreWebView2* webview, ICoreWebView2ContentLoadingEventArgs* args)
+{
+ m_isLoading = true;
+ emit loadingChanged(QWebViewLoadRequestPrivate(m_url,
+ QWebView::LoadStartedStatus,
+ QString()));
+ emit loadProgressChanged(0);
+ return S_OK;
+}
+
+void QWebView2WebViewPrivate::updateWindowGeometry()
+{
+ if (!m_webviewController)
+ return;
+ if (m_webViewWindow->opacity() <= 0) {
+ m_webViewWindow->setFlag(Qt::WindowDoesNotAcceptFocus, false);
+ m_webViewWindow->setParent(m_window);
+ m_webViewWindow->setOpacity(1);
+ }
+ RECT bounds;
+ GetClientRect((HWND)m_window->winId(), &bounds);
+ Q_ASSERT_SUCCEEDED(m_webviewController->put_Bounds(bounds));
+ m_webViewWindow->setGeometry(0, 0, m_window->width(), m_window->height());
+}
+
+void QWebView2WebViewPrivate::runJavaScriptPrivate(const QString &script, int callbackId)
+{
+ QEventLoop loop;
+ if (m_webview)
+ Q_ASSERT_SUCCEEDED(m_webview->ExecuteScript((wchar_t*)script.utf16(),
+ Microsoft::WRL::Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
+ [&loop, this, &callbackId](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT {
+ QString resultStr = QString::fromWCharArray(resultObjectAsJson);
+
+ QJsonParseError parseError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(resultStr.toUtf8(), &parseError);
+
+ QVariant resultVariant;
+ if (parseError.error == QJsonParseError::NoError) {
+ resultVariant = jsonDoc.toVariant();
+ } else {
+ QString wrapped = QString("{\"value\":%1}").arg(resultStr);
+ jsonDoc = QJsonDocument::fromJson(wrapped.toUtf8(), &parseError);
+ if (parseError.error == QJsonParseError::NoError) {
+ resultVariant = jsonDoc.object().value("value").toVariant();
+ } else {
+ QJsonValue val = QJsonValue::fromVariant(resultStr);
+ resultVariant = val.toVariant();
+ }
+ }
+ if (errorCode != S_OK)
+ emit javaScriptResult(callbackId, qt_error_string(errorCode));
+ else
+ emit javaScriptResult(callbackId, resultVariant);
+ loop.quit();
+ return errorCode;
+ }).Get()));
+ loop.exec();
+}
+
+QAbstractWebViewSettings *QWebView2WebViewPrivate::getSettings() const
+{
+ return m_settings;
+}