summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@intopalo.com>2015-08-23 23:40:01 +0300
committerAndrew Knight <andrew.knight@intopalo.com>2015-08-25 04:47:33 +0000
commit5bbbd6cdfec885a1ecd88687ce7e5497df5ba09a (patch)
treebd61cbb7f36b4870d9b8afc92e1c4c81add6484e
parent119db3c806220038ba3a10bc9dc0b4afb1e3bfbf (diff)
Add support for Windows Runtime
Now that WinRT uses XAML-based windows, it can support creating native WebView controls. Change-Id: I04361956eba9de5b5d41fcc6b57a9772b49f6a2b Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
-rw-r--r--examples/webview/minibrowser/main.cpp6
-rw-r--r--examples/webview/minibrowser/minibrowser.pro2
-rw-r--r--src/imports/imports.pro2
-rw-r--r--src/webview/qwebview_winrt.cpp662
-rw-r--r--src/webview/qwebview_winrt_p.h109
-rw-r--r--src/webview/webview-lib.pri6
6 files changed, 785 insertions, 2 deletions
diff --git a/examples/webview/minibrowser/main.cpp b/examples/webview/minibrowser/main.cpp
index 5daecc0..390d591 100644
--- a/examples/webview/minibrowser/main.cpp
+++ b/examples/webview/minibrowser/main.cpp
@@ -78,7 +78,11 @@ int main(int argc, char *argv[])
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("url", "The initial URL to open.");
- parser.process(app);
+ QStringList arguments = app.arguments();
+#ifdef Q_OS_WINRT
+ arguments.removeAt(1); // The launcher always passes in the -ServerName parameter, breaking the command line parser
+#endif
+ parser.process(arguments);
const QString initialUrl = parser.positionalArguments().isEmpty() ?
QStringLiteral("qt.io") : parser.positionalArguments().first();
diff --git a/examples/webview/minibrowser/minibrowser.pro b/examples/webview/minibrowser/minibrowser.pro
index c7ffb31..a9b3222 100644
--- a/examples/webview/minibrowser/minibrowser.pro
+++ b/examples/webview/minibrowser/minibrowser.pro
@@ -2,6 +2,8 @@ TEMPLATE = app
QT += qml quick webview
+winrt: WINRT_MANIFEST.capabilities += internetClient
+
SOURCES += main.cpp
RESOURCES += qml.qrc
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index dfb1f19..4fd268d 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -7,7 +7,7 @@ QT += qml quick
SOURCES += \
$$PWD/webview.cpp
-android|mac {
+android|mac|winrt {
QT += webview-private
} else:qtHaveModule(webengine) {
QT += webengine webengine-private
diff --git a/src/webview/qwebview_winrt.cpp b/src/webview/qwebview_winrt.cpp
new file mode 100644
index 0000000..0b132b4
--- /dev/null
+++ b/src/webview/qwebview_winrt.cpp
@@ -0,0 +1,662 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebView module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwebview_winrt_p.h"
+#include "qwebviewloadrequest_p.h"
+
+#include <functional>
+
+#include <QPointer>
+#include <QHash>
+#include <QRegularExpression>
+#include <qfunctions_winrt.h>
+#include <private/qeventdispatcher_winrt_p.h>
+
+#include <wrl.h>
+#include <windows.graphics.display.h>
+#include <windows.ui.xaml.h>
+#include <windows.ui.xaml.controls.h>
+#include <windows.ui.xaml.markup.h>
+#include <windows.web.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Graphics::Display;
+using namespace ABI::Windows::UI;
+using namespace ABI::Windows::UI::Xaml;
+using namespace ABI::Windows::UI::Xaml::Controls;
+using namespace ABI::Windows::UI::Xaml::Markup;
+using namespace ABI::Windows::Web;
+
+class HStringListIterator : public RuntimeClass<RuntimeClassFlags<WinRt>, IIterator<HSTRING>>
+{
+public:
+ HStringListIterator(HSTRING *data, int size) : data(data), size(size), pos(0)
+ {
+ }
+
+ HRESULT __stdcall get_Current(HSTRING *current) override
+ {
+ *current = pos >= size ? nullptr : data[pos];
+ return S_OK;
+ }
+
+ HRESULT __stdcall get_HasCurrent(boolean *hasCurrent) override
+ {
+ *hasCurrent = pos < size;
+ return S_OK;
+ }
+
+ HRESULT __stdcall MoveNext(boolean *hasCurrent) override
+ {
+ *hasCurrent = ++pos < size;
+ return S_OK;
+ }
+
+ HRESULT __stdcall GetMany(unsigned capacity, HSTRING *value, unsigned *actual)
+ {
+ unsigned i = 0;
+ for (; i < qMin(capacity, unsigned(size)); ++i)
+ value[i] = data[pos + i];
+ *actual = i;
+ pos += i;
+ return S_OK;
+ }
+
+private:
+ HSTRING *data;
+ int size;
+ int pos;
+};
+
+class HStringList : public RuntimeClass<RuntimeClassFlags<WinRt>, IIterable<HSTRING>>
+{
+public:
+ HStringList(const QList<QString> &stringList)
+ {
+ d.resize(stringList.size());
+ for (int i = 0; i < stringList.size(); ++i) {
+ const QString qString = stringList.at(i).trimmed();
+ HStringReference hString(reinterpret_cast<const wchar_t *>(qString.utf16()), qString.length());
+ hString.CopyTo(&d[i++]);
+ }
+ }
+
+ ~HStringList()
+ {
+ foreach (const HSTRING &hString, d)
+ WindowsDeleteString(hString);
+ }
+
+ HRESULT __stdcall First(IIterator<HSTRING> **first) override
+ {
+ ComPtr<HStringListIterator> it = Make<HStringListIterator>(d.data(), d.size());
+ return it.Get()->QueryInterface(IID_PPV_ARGS(first));
+ }
+
+private:
+ QVector<HSTRING> d;
+};
+
+static QUrl qurlFromUri(IUriRuntimeClass *uri)
+{
+ HRESULT hr;
+ HString uriString;
+ hr = uri->get_AbsoluteUri(uriString.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 uriStringLength;
+ const wchar_t *uriStringBuffer = uriString.GetRawBuffer(&uriStringLength);
+ return QUrl(QString::fromWCharArray(uriStringBuffer, uriStringLength));
+}
+
+static QString webErrorStatusString(WebErrorStatus status)
+{
+ switch (status) {
+ case WebErrorStatus_Unknown:
+ return QStringLiteral("Unknown");
+ case WebErrorStatus_CertificateCommonNameIsIncorrect:
+ return QStringLiteral("CertificateCommonNameIsIncorrect");
+ case WebErrorStatus_CertificateExpired:
+ return QStringLiteral("CertificateExpired");
+ case WebErrorStatus_CertificateContainsErrors:
+ return QStringLiteral("CertificateContainsErrors");
+ case WebErrorStatus_CertificateRevoked:
+ return QStringLiteral("CertificateRevoked");
+ case WebErrorStatus_CertificateIsInvalid:
+ return QStringLiteral("CertificateIsInvalid");
+ case WebErrorStatus_ServerUnreachable:
+ return QStringLiteral("ServerUnreachable");
+ case WebErrorStatus_Timeout:
+ return QStringLiteral("Timeout");
+ case WebErrorStatus_ErrorHttpInvalidServerResponse:
+ return QStringLiteral("ErrorHttpInvalidServerResponse");
+ case WebErrorStatus_ConnectionAborted:
+ return QStringLiteral("ConnectionAborted");
+ case WebErrorStatus_ConnectionReset:
+ return QStringLiteral("ConnectionReset");
+ case WebErrorStatus_Disconnected:
+ return QStringLiteral("Disconnected");
+ case WebErrorStatus_HttpToHttpsOnRedirection:
+ return QStringLiteral("HttpToHttpsOnRedirection");
+ case WebErrorStatus_HttpsToHttpOnRedirection:
+ return QStringLiteral("HttpsToHttpOnRedirection");
+ case WebErrorStatus_CannotConnect:
+ return QStringLiteral("CannotConnect");
+ case WebErrorStatus_HostNameNotResolved:
+ return QStringLiteral("HostNameNotResolved");
+ case WebErrorStatus_OperationCanceled:
+ return QStringLiteral("OperationCanceled");
+ case WebErrorStatus_RedirectFailed:
+ return QStringLiteral("RedirectFailed");
+ case WebErrorStatus_UnexpectedStatusCode:
+ return QStringLiteral("UnexpectedStatusCode");
+ case WebErrorStatus_UnexpectedRedirection:
+ return QStringLiteral("UnexpectedRedirection");
+ case WebErrorStatus_UnexpectedClientError:
+ return QStringLiteral("UnexpectedClientError");
+ case WebErrorStatus_UnexpectedServerError:
+ return QStringLiteral("UnexpectedServerError");
+ case WebErrorStatus_MultipleChoices:
+ return QStringLiteral("MultipleChoices");
+ case WebErrorStatus_MovedPermanently:
+ return QStringLiteral("MovedPermanently");
+ case WebErrorStatus_Found:
+ return QStringLiteral("Found");
+ case WebErrorStatus_SeeOther:
+ return QStringLiteral("SeeOther");
+ case WebErrorStatus_NotModified:
+ return QStringLiteral("NotModified");
+ case WebErrorStatus_UseProxy:
+ return QStringLiteral("UseProxy");
+ case WebErrorStatus_TemporaryRedirect:
+ return QStringLiteral("TemporaryRedirect");
+ case WebErrorStatus_BadRequest:
+ return QStringLiteral("BadRequest");
+ case WebErrorStatus_Unauthorized:
+ return QStringLiteral("Unauthorized");
+ case WebErrorStatus_PaymentRequired:
+ return QStringLiteral("PaymentRequired");
+ case WebErrorStatus_Forbidden:
+ return QStringLiteral("Forbidden");
+ case WebErrorStatus_NotFound:
+ return QStringLiteral("NotFound");
+ case WebErrorStatus_MethodNotAllowed:
+ return QStringLiteral("MethodNotAllowed");
+ case WebErrorStatus_NotAcceptable:
+ return QStringLiteral("NotAcceptable");
+ case WebErrorStatus_ProxyAuthenticationRequired:
+ return QStringLiteral("ProxyAuthenticationRequired");
+ case WebErrorStatus_RequestTimeout:
+ return QStringLiteral("RequestTimeout");
+ case WebErrorStatus_Conflict:
+ return QStringLiteral("Conflict");
+ case WebErrorStatus_Gone:
+ return QStringLiteral("Gone");
+ case WebErrorStatus_LengthRequired:
+ return QStringLiteral("LengthRequired");
+ case WebErrorStatus_PreconditionFailed:
+ return QStringLiteral("PreconditionFailed");
+ case WebErrorStatus_RequestEntityTooLarge:
+ return QStringLiteral("RequestEntityTooLarge");
+ case WebErrorStatus_RequestUriTooLong:
+ return QStringLiteral("RequestUriTooLong");
+ case WebErrorStatus_UnsupportedMediaType:
+ return QStringLiteral("UnsupportedMediaType");
+ case WebErrorStatus_RequestedRangeNotSatisfiable:
+ return QStringLiteral("RequestedRangeNotSatisfiable");
+ case WebErrorStatus_ExpectationFailed:
+ return QStringLiteral("ExpectationFailed");
+ case WebErrorStatus_InternalServerError:
+ return QStringLiteral("InternalServerError");
+ case WebErrorStatus_NotImplemented:
+ return QStringLiteral("NotImplemented");
+ case WebErrorStatus_BadGateway:
+ return QStringLiteral("BadGateway");
+ case WebErrorStatus_ServiceUnavailable:
+ return QStringLiteral("ServiceUnavailable");
+ case WebErrorStatus_GatewayTimeout:
+ return QStringLiteral("GatewayTimeout");
+ case WebErrorStatus_HttpVersionNotSupported:
+ return QStringLiteral("HttpVersionNotSupported");
+ default:
+ break;
+ }
+ return QString();
+}
+
+QWebViewPrivate *QWebViewPrivate::create(QWebView *q)
+{
+ return new QWinRTWebViewPrivate(q);
+}
+
+struct WinRTWebView
+{
+ ComPtr<IWebView> base;
+ ComPtr<IWebView2> ext;
+ ComPtr<IPanel> host;
+
+ ComPtr<ICanvasStatics> canvas;
+ ComPtr<IUriRuntimeClassFactory> uriFactory;
+ ComPtr<IDisplayInformation> displayInformation;
+
+ QPointer<QWindow> window;
+ QHash<IAsyncOperation<HSTRING> *, int> callbacks;
+
+ EventRegistrationToken navigationStartingToken;
+ EventRegistrationToken navigationCompletedToken;
+ bool isLoading : 1;
+};
+
+#define LSTRING(str) L#str
+static const wchar_t webviewXaml[] = LSTRING(
+<WebView xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
+);
+
+QWinRTWebViewPrivate::QWinRTWebViewPrivate(QObject *parent)
+ : QWebViewPrivate(parent), d(new WinRTWebView)
+{
+ d->isLoading = false;
+
+ QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ ComPtr<IXamlReaderStatics> xamlReader;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Markup_XamlReader).Get(),
+ IID_PPV_ARGS(&xamlReader));
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Directly instantiating a WebView works, but it throws an exception
+ // when navigating. Using a XamlReader appears to set it up properly.
+ ComPtr<IInspectable> element;
+ hr = xamlReader->Load(HString::MakeReference(webviewXaml).Get(), &element);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = element.As(&d->base);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->base.As(&d->ext);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = d->ext->add_NavigationStarting(
+ Callback<ITypedEventHandler<WebView *, WebViewNavigationStartingEventArgs *>>(this, &QWinRTWebViewPrivate::onNavigationStarted).Get(),
+ &d->navigationStartingToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ d->ext->add_NavigationCompleted(
+ Callback<ITypedEventHandler<WebView *, WebViewNavigationCompletedEventArgs *>>(this, &QWinRTWebViewPrivate::onNavigationCompleted).Get(),
+ &d->navigationCompletedToken);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IDisplayInformationStatics> displayInformationStatics;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(),
+ IID_PPV_ARGS(&displayInformationStatics));
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = displayInformationStatics->GetForCurrentView(&d->displayInformation);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+
+ HRESULT hr;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(),
+ IID_PPV_ARGS(&d->canvas));
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(),
+ IID_PPV_ARGS(&d->uriFactory));
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+QWinRTWebViewPrivate::~QWinRTWebViewPrivate()
+{
+ QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ ComPtr<IVector<UIElement *>> children;
+ hr = d->host->get_Children(&children);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IUIElement> uiElement;
+ hr = d->base.As(&uiElement);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 index;
+ boolean found;
+ hr = children->IndexOf(uiElement.Get(), &index, &found);
+ Q_ASSERT_SUCCEEDED(hr);
+ if (found) {
+ hr = children->RemoveAt(index);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ return hr;
+ });
+}
+
+QUrl QWinRTWebViewPrivate::url() const
+{
+ ComPtr<IUriRuntimeClass> uri;
+ QEventDispatcherWinRT::runOnXamlThread([this, &uri]() {
+ HRESULT hr;
+ hr = d->base->get_Source(&uri);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+ return qurlFromUri(uri.Get());
+}
+
+void QWinRTWebViewPrivate::setUrl(const QUrl &url)
+{
+ QEventDispatcherWinRT::runOnXamlThread([this, &url]() {
+ HRESULT hr;
+ const QString urlString = url.toString();
+ ComPtr<IUriRuntimeClass> uri;
+ HStringReference uriString(reinterpret_cast<const wchar_t *>(urlString.utf16()),
+ urlString.length());
+ hr = d->uriFactory->CreateUri(uriString.Get(), &uri);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->base->Navigate(uri.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+bool QWinRTWebViewPrivate::canGoBack() const
+{
+ boolean canGoBack;
+ QEventDispatcherWinRT::runOnXamlThread([this, &canGoBack]() {
+ HRESULT hr;
+ hr = d->ext->get_CanGoBack(&canGoBack);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+ return canGoBack;
+}
+
+bool QWinRTWebViewPrivate::canGoForward() const
+{
+ boolean canGoForward;
+ QEventDispatcherWinRT::runOnXamlThread([this, &canGoForward]() {
+ HRESULT hr;
+ hr = d->ext->get_CanGoForward(&canGoForward);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+ return canGoForward;
+}
+
+QString QWinRTWebViewPrivate::title() const
+{
+ HString title;
+ QEventDispatcherWinRT::runOnXamlThread([this, &title]() {
+ HRESULT hr;
+ hr = d->ext->get_DocumentTitle(title.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+ quint32 titleLength;
+ const wchar_t *titleBuffer = title.GetRawBuffer(&titleLength);
+ return QString::fromWCharArray(titleBuffer, titleLength);
+}
+
+int QWinRTWebViewPrivate::loadProgress() const
+{
+ return d->isLoading ? 0 : 100;
+}
+
+bool QWinRTWebViewPrivate::isLoading() const
+{
+ return d->isLoading;
+}
+
+void QWinRTWebViewPrivate::setParentView(QObject *view)
+{
+ d->window = qobject_cast<QWindow *>(view);
+ if (!d->window)
+ return;
+
+ ComPtr<IInspectable> host = reinterpret_cast<IInspectable *>(d->window->winId());
+ if (!host)
+ return;
+
+ QEventDispatcherWinRT::runOnXamlThread([this, &host]() {
+ HRESULT hr;
+ ComPtr<IFrameworkElement> frameworkHost;
+ hr = host.As(&frameworkHost);
+ RETURN_HR_IF_FAILED("Failed to cast the window ID to IFrameworkElement");
+ ComPtr<IDependencyObject> parent;
+ hr = frameworkHost->get_Parent(&parent);
+ RETURN_HR_IF_FAILED("Failed to get the parent object of the window");
+ hr = parent.As(&d->host);
+ RETURN_HR_IF_FAILED("Failed to cast the window container to IPanel");
+ ComPtr<IVector<UIElement *>> children;
+ hr = d->host->get_Children(&children);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IUIElement> uiElement;
+ hr = d->base.As(&uiElement);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = children->Append(uiElement.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+QObject *QWinRTWebViewPrivate::parentView() const
+{
+ return d->window;
+}
+
+void QWinRTWebViewPrivate::setGeometry(const QRect &geometry)
+{
+ QEventDispatcherWinRT::runOnXamlThread([this, &geometry]() {
+ HRESULT hr;
+ double scaleFactor;
+#ifdef Q_OS_WINPHONE
+ ComPtr<IDisplayInformation2> displayInformation;
+ hr = d->displayInformation.As(&displayInformation);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = displayInformation->get_RawPixelsPerViewPixel(&scaleFactor);
+ Q_ASSERT_SUCCEEDED(hr);
+#else
+ ResolutionScale resolutionScale;
+ hr = d->displayInformation->get_ResolutionScale(&resolutionScale);
+ Q_ASSERT_SUCCEEDED(hr);
+ scaleFactor = double(resolutionScale) / 100;
+#endif
+ scaleFactor = 1 / scaleFactor;
+
+ ComPtr<IUIElement> uiElement;
+ hr = d->base.As(&uiElement);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->canvas->SetLeft(uiElement.Get(), geometry.x() * scaleFactor);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->canvas->SetTop(uiElement.Get(), geometry.y() * scaleFactor);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IFrameworkElement> frameworkElement;
+ hr = d->base.As(&frameworkElement);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = frameworkElement->put_Width(geometry.width() * scaleFactor);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = frameworkElement->put_Height(geometry.height() * scaleFactor);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+void QWinRTWebViewPrivate::setVisibility(QWindow::Visibility visibility)
+{
+ setVisible(visibility != QWindow::Hidden);
+}
+
+void QWinRTWebViewPrivate::setVisible(bool visible)
+{
+ QEventDispatcherWinRT::runOnXamlThread([this, &visible]() {
+ HRESULT hr;
+ ComPtr<IUIElement> uiElement;
+ hr = d->base.As(&uiElement);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = uiElement->put_Visibility(visible ? Visibility_Visible : Visibility_Collapsed);
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+void QWinRTWebViewPrivate::goBack()
+{
+ QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ hr = d->ext->GoBack();
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+void QWinRTWebViewPrivate::goForward()
+{
+ QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ hr = d->ext->GoForward();
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+void QWinRTWebViewPrivate::reload()
+{
+ QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ hr = d->ext->Refresh();
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+void QWinRTWebViewPrivate::stop()
+{
+ QEventDispatcherWinRT::runOnXamlThread([this]() {
+ HRESULT hr;
+ hr = d->ext->Stop();
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+void QWinRTWebViewPrivate::loadHtml(const QString &html, const QUrl &baseUrl)
+{
+ if (!baseUrl.isEmpty())
+ qWarning("Base URLs for loadHtml() are not supported under WinRT.");
+
+ HRESULT hr;
+ HStringReference htmlText(reinterpret_cast<const wchar_t *>(html.utf16()), html.length());
+ hr = d->base->NavigateToString(htmlText.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+void QWinRTWebViewPrivate::runJavaScriptPrivate(const QString &script, int callbackId)
+{
+ static QRegularExpression functionTemplate(QStringLiteral("^(.*)\\((.*)\\)[\\s;]*?$"));
+ QRegularExpressionMatch match = functionTemplate.match(script);
+ if (!match.hasMatch()) {
+ qWarning("The WinRT WebView only supports calling global functions, so please make your call"
+ " in the form myFunction(a, b, c). Also note that only string arguments can be passed.");
+ return;
+ }
+
+ const QString method = match.captured(1).trimmed();
+ HStringReference methodString(reinterpret_cast<const wchar_t *>(method.utf16()), method.length());
+ ComPtr<HStringList> argumentStrings = Make<HStringList>(match.captured(2).split(QLatin1Char(',')));
+ QEventDispatcherWinRT::runOnXamlThread([this, &methodString, &argumentStrings, &callbackId]() {
+ HRESULT hr;
+ ComPtr<IAsyncOperation<HSTRING>> op;
+ hr = d->ext->InvokeScriptAsync(methodString.Get(), argumentStrings.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ d->callbacks.insert(op.Get(), callbackId);
+ hr = op->put_Completed(Callback<IAsyncOperationCompletedHandler<HSTRING>>([this](IAsyncOperation<HSTRING> *op, AsyncStatus status) {
+ int callbackId = d->callbacks.take(op);
+ HRESULT hr;
+ if (status != Completed) {
+ ComPtr<IAsyncInfo> info;
+ hr = op->QueryInterface(IID_PPV_ARGS(&info));
+ Q_ASSERT_SUCCEEDED(hr);
+ HRESULT errorCode;
+ hr = info->get_ErrorCode(&errorCode);
+ Q_ASSERT_SUCCEEDED(hr);
+ emit javaScriptResult(callbackId, qt_error_string(errorCode));
+ return S_OK;
+ }
+ HString result;
+ hr = op->GetResults(result.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 resultLength;
+ const wchar_t *resultBuffer = result.GetRawBuffer(&resultLength);
+ emit javaScriptResult(callbackId, QString::fromWCharArray(resultBuffer, resultLength));
+ return S_OK;
+ }).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ return hr;
+ });
+}
+
+HRESULT QWinRTWebViewPrivate::onNavigationStarted(IWebView *, IWebViewNavigationStartingEventArgs *args)
+{
+ d->isLoading = true;
+ HRESULT hr;
+ ComPtr<IUriRuntimeClass> uri;
+ hr = args->get_Uri(&uri);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QUrl url = qurlFromUri(uri.Get());
+
+ emit loadingChanged(QWebViewLoadRequestPrivate(url, QWebView::LoadStartedStatus, QString()));
+ emit loadProgressChanged(0);
+ return S_OK;
+}
+
+HRESULT QWinRTWebViewPrivate::onNavigationCompleted(IWebView *, IWebViewNavigationCompletedEventArgs *args)
+{
+ d->isLoading = false;
+ HRESULT hr;
+ ComPtr<IUriRuntimeClass> uri;
+ hr = args->get_Uri(&uri);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QUrl url = qurlFromUri(uri.Get());
+
+ boolean isSuccess;
+ hr = args->get_IsSuccess(&isSuccess);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QWebView::LoadStatus status = isSuccess ? QWebView::LoadSucceededStatus : QWebView::LoadFailedStatus;
+
+ WebErrorStatus errorStatus;
+ hr = args->get_WebErrorStatus(&errorStatus);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QString errorString = webErrorStatusString(errorStatus);
+
+ emit loadingChanged(QWebViewLoadRequestPrivate(url, status, errorString));
+ emit loadProgressChanged(100);
+ return S_OK;
+}
diff --git a/src/webview/qwebview_winrt_p.h b/src/webview/qwebview_winrt_p.h
new file mode 100644
index 0000000..dfff58e
--- /dev/null
+++ b/src/webview/qwebview_winrt_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebView module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBVIEW_WINRT_P_H
+#define QWEBVIEW_WINRT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qwebview_p.h"
+
+namespace ABI {
+ namespace Windows {
+ namespace UI {
+ namespace Xaml {
+ namespace Controls {
+ struct IWebView;
+ struct IWebViewNavigationStartingEventArgs;
+ struct IWebViewNavigationCompletedEventArgs;
+ }
+ }
+ }
+ }
+}
+
+QT_BEGIN_NAMESPACE
+
+struct WinRTWebView;
+class QWinRTWebViewPrivate : public QWebViewPrivate
+{
+ Q_OBJECT
+public:
+ explicit QWinRTWebViewPrivate(QObject *parent = Q_NULLPTR);
+ ~QWinRTWebViewPrivate() Q_DECL_OVERRIDE;
+
+ QUrl url() const Q_DECL_OVERRIDE;
+ void setUrl(const QUrl &url) Q_DECL_OVERRIDE;
+ bool canGoBack() const Q_DECL_OVERRIDE;
+ bool canGoForward() const Q_DECL_OVERRIDE;
+ QString title() const Q_DECL_OVERRIDE;
+ int loadProgress() const Q_DECL_OVERRIDE;
+ bool isLoading() const Q_DECL_OVERRIDE;
+
+ void setParentView(QObject *view) Q_DECL_OVERRIDE;
+ QObject *parentView() const Q_DECL_OVERRIDE;
+ void setGeometry(const QRect &geometry) Q_DECL_OVERRIDE;
+ void setVisibility(QWindow::Visibility visibility) Q_DECL_OVERRIDE;
+ void setVisible(bool visible) Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+ void goBack() Q_DECL_OVERRIDE;
+ void goForward() Q_DECL_OVERRIDE;
+ void reload() Q_DECL_OVERRIDE;
+ void stop() Q_DECL_OVERRIDE;
+ void loadHtml(const QString &html, const QUrl &baseUrl = QUrl()) Q_DECL_OVERRIDE;
+
+protected:
+ void runJavaScriptPrivate(const QString &script, int callbackId) Q_DECL_OVERRIDE;
+
+private:
+ HRESULT onNavigationStarted(ABI::Windows::UI::Xaml::Controls::IWebView *, ABI::Windows::UI::Xaml::Controls::IWebViewNavigationStartingEventArgs *);
+ HRESULT onNavigationCompleted(ABI::Windows::UI::Xaml::Controls::IWebView *, ABI::Windows::UI::Xaml::Controls::IWebViewNavigationCompletedEventArgs *);
+ QScopedPointer<WinRTWebView> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBVIEW_WINRT_P_H
diff --git a/src/webview/webview-lib.pri b/src/webview/webview-lib.pri
index 3577915..deafc74 100644
--- a/src/webview/webview-lib.pri
+++ b/src/webview/webview-lib.pri
@@ -58,6 +58,12 @@ android {
$$COMMON_HEADERS \
qwebview_osx_p.h
+} else: winrt {
+ NO_PCH_SOURCES += qwebview_winrt.cpp
+ SOURCES += $$COMMON_SOURCES
+ PRIVATE_HEADERS += \
+ $$COMMON_HEADERS \
+ qwebview_winrt_p.h
} else:qtHaveModule(webengine) {
QT += webengine webengine-private
DEFINES += QT_WEBVIEW_WEBENGINE_BACKEND