diff --git a/.gitignore b/.gitignore index 22753a30f2..8f047f3bfe 100644 --- a/.gitignore +++ b/.gitignore @@ -475,3 +475,5 @@ # /utils/wxrc/ /utils/wxrc/wxrc_vc[789].sln + +/3rdparty/webview2 diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index 8df1296a50..5efad18cfa 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -2835,6 +2835,7 @@ set(HTML_CMN_HDR set(WEBVIEW_MSW_SRC src/msw/webview_ie.cpp + src/msw/webview_edgec.cpp ) set(WEBVIEW_CMN_SRC diff --git a/build/cmake/lib/webview/CMakeLists.txt b/build/cmake/lib/webview/CMakeLists.txt index ac4caca35e..ea8b3cbe89 100644 --- a/build/cmake/lib/webview/CMakeLists.txt +++ b/build/cmake/lib/webview/CMakeLists.txt @@ -34,6 +34,22 @@ endif() if(APPLE) wx_lib_link_libraries(webview PUBLIC "-framework WebKit") +elseif(WXMSW) + if(wxUSE_WEBVIEW_EDGE) + wx_lib_include_directories(webview PRIVATE ${PROJECT_SOURCE_DIR}/3rdparty/webview2/build/native/include) + + if (${CMAKE_SIZEOF_VOID_P} EQUAL 4) + set(WEBVIEW2_ARCH x86) + else() + set(WEBVIEW2_ARCH x64) + endif() + + wx_lib_link_libraries(webview PUBLIC "${PROJECT_SOURCE_DIR}/3rdparty/webview2/build/native/${WEBVIEW2_ARCH}/WebView2Loader.dll.lib") + add_custom_command(TARGET webview POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${PROJECT_SOURCE_DIR}/3rdparty/webview2/build/native/${WEBVIEW2_ARCH}/WebView2Loader.dll" + $/"WebView2Loader.dll") + endif() elseif(WXGTK) if(LIBSOUP_FOUND) wx_lib_include_directories(webview PUBLIC ${LIBSOUP_INCLUDE_DIRS}) diff --git a/build/files b/build/files index 31e387eaf6..ec255b4188 100644 --- a/build/files +++ b/build/files @@ -2788,6 +2788,7 @@ HTML_CMN_HDR = WEBVIEW_MSW_SRC = src/msw/webview_ie.cpp + src/msw/webview_edgec.cpp WEBVIEW_CMN_SRC = src/common/webview.cpp src/common/webviewarchivehandler.cpp @@ -2796,6 +2797,7 @@ WEBVIEW_CMN_SRC = WEBVIEW_MSW_HDR = wx/msw/webviewhistoryitem_ie.h wx/msw/webview_ie.h + wx/msw/webview_edgec.h WEBVIEW_CMN_HDR = wx/webview.h wx/webviewarchivehandler.h diff --git a/include/wx/msw/webview_edgec.h b/include/wx/msw/webview_edgec.h new file mode 100644 index 0000000000..f81e01de38 --- /dev/null +++ b/include/wx/msw/webview_edgec.h @@ -0,0 +1,181 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: include/wx/msw/webview_edge.h +// Purpose: wxMSW Edge Chromium wxWebView backend +// Author: Markus Pingel +// Created: 2019-12-15 +// Copyright: (c) 2019 wxWidgets development team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef wxWebViewEdgeC_H +#define wxWebViewEdgeC_H + +#include "wx/setup.h" + +#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_EDGE && defined(__WXMSW__) + +#include "wx/control.h" +#include "wx/webview.h" +#include "wx/msw/private/comptr.h" + +#include + + +class WXDLLIMPEXP_WEBVIEW wxWebViewEdge : public wxWebView +{ +public: + + wxWebViewEdge() {} + + wxWebViewEdge(wxWindow* parent, + wxWindowID id, + const wxString& url = wxWebViewDefaultURLStr, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxWebViewNameStr) + { + Create(parent, id, url, pos, size, style, name); + } + + ~wxWebViewEdge(); + + bool Create(wxWindow* parent, + wxWindowID id, + const wxString& url = wxWebViewDefaultURLStr, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxWebViewNameStr) wxOVERRIDE; + + virtual void LoadURL(const wxString& url) wxOVERRIDE; + virtual void LoadHistoryItem(wxSharedPtr item) wxOVERRIDE; + virtual wxVector > GetBackwardHistory() wxOVERRIDE; + virtual wxVector > GetForwardHistory() wxOVERRIDE; + + virtual bool CanGoForward() const wxOVERRIDE; + virtual bool CanGoBack() const wxOVERRIDE; + virtual void GoBack() wxOVERRIDE; + virtual void GoForward() wxOVERRIDE; + virtual void ClearHistory() wxOVERRIDE; + virtual void EnableHistory(bool enable = true) wxOVERRIDE; + virtual void Stop() wxOVERRIDE; + virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) wxOVERRIDE; + + virtual wxString GetPageSource() const wxOVERRIDE; + virtual wxString GetPageText() const wxOVERRIDE; + + virtual bool IsBusy() const wxOVERRIDE; + virtual wxString GetCurrentURL() const wxOVERRIDE; + virtual wxString GetCurrentTitle() const wxOVERRIDE; + + virtual void SetZoomType(wxWebViewZoomType) wxOVERRIDE; + virtual wxWebViewZoomType GetZoomType() const wxOVERRIDE; + virtual bool CanSetZoomType(wxWebViewZoomType type) const wxOVERRIDE; + + virtual void Print() wxOVERRIDE; + + virtual wxWebViewZoom GetZoom() const wxOVERRIDE; + virtual void SetZoom(wxWebViewZoom zoom) wxOVERRIDE; + + //Clipboard functions + virtual bool CanCut() const wxOVERRIDE; + virtual bool CanCopy() const wxOVERRIDE; + virtual bool CanPaste() const wxOVERRIDE; + virtual void Cut() wxOVERRIDE; + virtual void Copy() wxOVERRIDE; + virtual void Paste() wxOVERRIDE; + + //Undo / redo functionality + virtual bool CanUndo() const wxOVERRIDE; + virtual bool CanRedo() const wxOVERRIDE; + virtual void Undo() wxOVERRIDE; + virtual void Redo() wxOVERRIDE; + + //Find function + virtual long Find(const wxString& text, int flags = wxWEBVIEW_FIND_DEFAULT) wxOVERRIDE; + + //Editing functions + virtual void SetEditable(bool enable = true) wxOVERRIDE; + virtual bool IsEditable() const wxOVERRIDE; + + //Selection + virtual void SelectAll() wxOVERRIDE; + virtual bool HasSelection() const wxOVERRIDE; + virtual void DeleteSelection() wxOVERRIDE; + virtual wxString GetSelectedText() const wxOVERRIDE; + virtual wxString GetSelectedSource() const wxOVERRIDE; + virtual void ClearSelection() wxOVERRIDE; + + virtual void EnableContextMenu(bool enable = true) wxOVERRIDE; + virtual bool IsContextMenuEnabled() const wxOVERRIDE; + + virtual bool RunScript(const wxString& javascript, wxString* output = NULL) wxOVERRIDE; + + virtual void RegisterHandler(wxSharedPtr handler) wxOVERRIDE; + + virtual void* GetNativeBackend() const wxOVERRIDE { return m_webView; } + + // ---- Edge-specific methods + + static bool IsAvailable(); + +protected: + virtual void DoSetPage(const wxString& html, const wxString& baseUrl) wxOVERRIDE; + +private: + bool m_initialized = false; + bool m_isBusy = false; + wxString m_pendingURL; + + wxCOMPtr m_webViewEnvironment; + wxCOMPtr m_webView; + + EventRegistrationToken m_navigationStartingToken = { }; + EventRegistrationToken m_navigationCompletedToken = { }; + EventRegistrationToken m_newWindowRequestedToken = { }; + EventRegistrationToken m_documentStateChangedToken = { }; + + void OnSize(wxSizeEvent& event); + + void UpdateBounds(); + + void InitWebViewCtrl(); + + bool RunScriptSync(const wxString& javascript, wxString* output = NULL); + + static int ms_isAvailable; + + static void Initialize(); + + static void Uninitalize(); + + friend class wxWebViewEdgeModule; + + wxVector > m_historyList; + int m_historyPosition; + bool m_historyLoadingFromList; + bool m_historyEnabled; + + wxDECLARE_DYNAMIC_CLASS(wxWebViewEdge); +}; + +class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryEdge : public wxWebViewFactory +{ +public: + virtual wxWebView* Create() wxOVERRIDE { return new wxWebViewEdge; } + virtual wxWebView* Create(wxWindow* parent, + wxWindowID id, + const wxString& url = wxWebViewDefaultURLStr, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxWebViewNameStr) wxOVERRIDE + { + return new wxWebViewEdge(parent, id, url, pos, size, style, name); + } +}; + +#endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_EDGE && defined(__WXMSW__) + +#endif // wxWebViewEdgeC_H diff --git a/include/wx/msw/webviewhistoryitem_ie.h b/include/wx/msw/webviewhistoryitem_ie.h index 6edfbb3932..e719b82a9f 100644 --- a/include/wx/msw/webviewhistoryitem_ie.h +++ b/include/wx/msw/webviewhistoryitem_ie.h @@ -11,7 +11,7 @@ #include "wx/setup.h" -#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE && defined(__WXMSW__) +#if wxUSE_WEBVIEW && (wxUSE_WEBVIEW_IE || wxUSE_WEBVIEW_EDGE) && defined(__WXMSW__) class WXDLLIMPEXP_WEBVIEW wxWebViewHistoryItem { diff --git a/include/wx/webview.h b/include/wx/webview.h index 4ae7c8c616..6e5e4aafdd 100644 --- a/include/wx/webview.h +++ b/include/wx/webview.h @@ -101,6 +101,7 @@ extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewNameStr[]; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewDefaultURLStr[]; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendDefault[]; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendIE[]; +extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendEdge[]; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendWebKit[]; class WXDLLIMPEXP_WEBVIEW wxWebViewFactory : public wxObject diff --git a/interface/wx/webview.h b/interface/wx/webview.h index cc7cce47af..c1d5f1da11 100644 --- a/interface/wx/webview.h +++ b/interface/wx/webview.h @@ -279,6 +279,16 @@ public: this article for more information. This backend has full support for custom schemes and virtual file systems. + @par wxWEBVIEW_BACKEND_EDGE (MSW) + + The Edge (Chromium) backend uses Microsoft's + Edge WebView2. + It is available for Windows 7 and newer. + This backend has currently a few features missing but is still + a better choice than IE when just displaying web content. The unsupported + features are the following: virtual filesystems, custom urls, + text selection, find, source code. + @par wxWEBVIEW_WEBKIT (GTK) Under GTK the WebKit backend uses diff --git a/samples/webview/webview.cpp b/samples/webview/webview.cpp index 60160c56ce..d7c7c16667 100644 --- a/samples/webview/webview.cpp +++ b/samples/webview/webview.cpp @@ -21,7 +21,7 @@ #include "wx/wx.h" #endif -#if !wxUSE_WEBVIEW_WEBKIT && !wxUSE_WEBVIEW_WEBKIT2 && !wxUSE_WEBVIEW_IE +#if !wxUSE_WEBVIEW_WEBKIT && !wxUSE_WEBVIEW_WEBKIT2 && !wxUSE_WEBVIEW_IE && !wxUSE_WEBVIEW_EDGE #error "A wxWebView backend is required by this sample" #endif @@ -365,7 +365,12 @@ WebFrame::WebFrame(const wxString& url) : topsizer->Add(m_info, wxSizerFlags().Expand()); // Create the webview - m_browser = wxWebView::New(this, wxID_ANY, url); + wxString backend = wxWebViewBackendDefault; +#ifdef __WXMSW__ + if (wxWebView::IsBackendAvailable(wxWebViewBackendEdge)) + backend = wxWebViewBackendEdge; +#endif + m_browser = wxWebView::New(this, wxID_ANY, url, wxDefaultPosition, wxDefaultSize, backend); topsizer->Add(m_browser, wxSizerFlags().Expand().Proportion(1)); //We register the wxfs:// protocol for testing purposes diff --git a/src/common/webview.cpp b/src/common/webview.cpp index 214d82ab5d..c9be93add5 100644 --- a/src/common/webview.cpp +++ b/src/common/webview.cpp @@ -23,6 +23,7 @@ #include "wx/gtk/webview_webkit.h" #elif defined(__WXMSW__) #include "wx/msw/webview_ie.h" +#include "wx/msw/webview_edgec.h" #endif // DLL options compatibility check: @@ -32,6 +33,7 @@ WX_CHECK_BUILD_OPTIONS("wxWEBVIEW") extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewNameStr[] = "wxWebView"; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewDefaultURLStr[] = "about:blank"; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendIE[] = "wxWebViewIE"; +extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendEdge[] = "wxWebViewEdge"; extern WXDLLIMPEXP_DATA_WEBVIEW(const char) wxWebViewBackendWebKit[] = "wxWebViewWebKit"; #ifdef __WXMSW__ @@ -108,6 +110,14 @@ void wxWebView::InitFactoryMap() if(m_factoryMap.find(wxWebViewBackendIE) == m_factoryMap.end()) RegisterFactory(wxWebViewBackendIE, wxSharedPtr (new wxWebViewFactoryIE)); + +#if wxUSE_WEBVIEW_EDGE + if (wxWebViewEdge::IsAvailable() && + m_factoryMap.find(wxWebViewBackendEdge) == m_factoryMap.end()) + RegisterFactory(wxWebViewBackendEdge, wxSharedPtr + (new wxWebViewFactoryEdge)); +#endif + #else if(m_factoryMap.find(wxWebViewBackendWebKit) == m_factoryMap.end()) RegisterFactory(wxWebViewBackendWebKit, wxSharedPtr diff --git a/src/msw/webview_edgec.cpp b/src/msw/webview_edgec.cpp new file mode 100644 index 0000000000..778a673c1e --- /dev/null +++ b/src/msw/webview_edgec.cpp @@ -0,0 +1,712 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: source/msw/webview_edgec.cpp +// Purpose: wxMSW Edge Chromium wxWebView backend implementation +// Author: Markus Pingel +// Created: 2019-12-15 +// Copyright: (c) 2019 wxWidgets development team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) +#pragma hdrstop +#endif + +#include "wx/msw/webview_edgec.h" + +#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_EDGE + +#include "wx/filename.h" +#include "wx/module.h" +#include "wx/thread.h" +#include "wx/private/jsscriptwrapper.h" + +#include + +using namespace Microsoft::WRL; + +wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewEdge, wxWebView); + +#define WX_ERROR2_CASE(error, wxerror) \ + case error: \ + event.SetString(#error); \ + event.SetInt(wxerror); \ + break; + +int wxWebViewEdge::ms_isAvailable = -1; + +bool wxWebViewEdge::IsAvailable() +{ + if (ms_isAvailable == -1) + Initialize(); + + return (ms_isAvailable == 1); +} + +void wxWebViewEdge::Initialize() +{ + LPWSTR versionStr; + if (SUCCEEDED(GetWebView2BrowserVersionInfo(NULL, &versionStr))) + { + if (versionStr) + ms_isAvailable = 1; + } +} + +void wxWebViewEdge::Uninitalize() +{ + if (ms_isAvailable == 1) + { + ms_isAvailable = -1; + } +} + +wxWebViewEdge::~wxWebViewEdge() +{ + if (m_webView) + { + // TOOD: Remove additional events + m_webView->remove_NavigationCompleted(m_navigationCompletedToken); + m_webView->remove_NavigationStarting(m_navigationStartingToken); + m_webView->remove_DocumentStateChanged(m_documentStateChangedToken); + m_webView->remove_NewWindowRequested(m_newWindowRequestedToken); + } +} + +bool wxWebViewEdge::Create(wxWindow* parent, + wxWindowID id, + const wxString& url, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + m_initialized = false; + m_isBusy = false; + + m_historyLoadingFromList = false; + m_historyEnabled = true; + m_historyPosition = -1; + + if (!wxControl::Create(parent, id, pos, size, style, + wxDefaultValidator, name)) + { + return false; + } + + if (!IsAvailable()) + return false; + + m_pendingURL = url; + + Bind(wxEVT_SIZE, &wxWebViewEdge::OnSize, this); + + LPCWSTR subFolder = nullptr; + LPCWSTR additionalBrowserSwitches = nullptr; + + HRESULT hr = CreateWebView2EnvironmentWithDetails( + subFolder, nullptr, additionalBrowserSwitches, + Callback( + [this](HRESULT WXUNUSED(result), IWebView2Environment* environment) -> HRESULT + { + environment->QueryInterface(IID_PPV_ARGS(&m_webViewEnvironment)); + m_webViewEnvironment->CreateWebView( + GetHWND(), Callback( + [this](HRESULT WXUNUSED(result), IWebView2WebView* webview) -> HRESULT + { + webview->QueryInterface(IID_PPV_ARGS(&m_webView)); + UpdateBounds(); + InitWebViewCtrl(); + return S_OK; + }) + .Get()); + return S_OK; + }).Get()); + return SUCCEEDED(hr); +} + +void wxWebViewEdge::InitWebViewCtrl() +{ + m_initialized = true; + UpdateBounds(); + + // Connect and handle the various WebView events + + m_webView->add_NavigationStarting( + Callback( + [this](IWebView2WebView* WXUNUSED(sender), IWebView2NavigationStartingEventArgs* args) -> HRESULT + { + m_isBusy = true; + wxString evtURL; + PWSTR uri; + if (SUCCEEDED(args->get_Uri(&uri))) + evtURL = wxString(uri); + wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING, GetId(), evtURL, wxString()); + event.SetEventObject(this); + HandleWindowEvent(event); + + if (!event.IsAllowed()) + args->put_Cancel(true); + + return S_OK; + }) + .Get(), &m_navigationStartingToken); + + m_webView->add_DocumentStateChanged( + Callback( + [this](IWebView2WebView* sender, IWebView2DocumentStateChangedEventArgs* WXUNUSED(args)) -> HRESULT + { + PWSTR uri; + sender->get_Source(&uri); + wxString evtURL(uri); + if (evtURL.Cmp(L"about:blank") == 0) + { + evtURL = L""; + } + + // AddPendingEvent(wxWebViewEvent(wxEVT_WEBVIEW_NAVIGATED, GetId(), uri, wxString())); + // SetWindowText(m_toolbar->addressBarWindow, uri.get()); + return S_OK; + }) + .Get(), + &m_documentStateChangedToken); + + m_webView->add_NavigationCompleted( + Callback( + [this](IWebView2WebView* sender, IWebView2NavigationCompletedEventArgs* args) -> HRESULT + { + BOOL isSuccess; + if (FAILED(args->get_IsSuccess(&isSuccess))) + isSuccess = false; + m_isBusy = false; + PWSTR _uri; + sender->get_Source(&_uri); + wxString uri(_uri); + + if (!isSuccess) + { + WEBVIEW2_WEB_ERROR_STATUS status; + + wxWebViewEvent event(wxEVT_WEBVIEW_ERROR, GetId(), uri, wxString()); + event.SetEventObject(this); + + if (SUCCEEDED(args->get_WebErrorStatus(&status))) + { + switch (status) + { + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_UNKNOWN, wxWEBVIEW_NAV_ERR_OTHER) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT, wxWEBVIEW_NAV_ERR_CERTIFICATE) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED, wxWEBVIEW_NAV_ERR_CERTIFICATE) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS, wxWEBVIEW_NAV_ERR_CERTIFICATE) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED, wxWEBVIEW_NAV_ERR_CERTIFICATE) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID, wxWEBVIEW_NAV_ERR_CERTIFICATE) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_SERVER_UNREACHABLE, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_TIMEOUT, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_ERROR_HTTP_INVALID_SERVER_RESPONSE, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CONNECTION_RESET, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_DISCONNECTED, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_CANNOT_CONNECT, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_HOST_NAME_NOT_RESOLVED, wxWEBVIEW_NAV_ERR_CONNECTION) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED, wxWEBVIEW_NAV_ERR_USER_CANCELLED) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_REDIRECT_FAILED, wxWEBVIEW_NAV_ERR_OTHER) + WX_ERROR2_CASE(WEBVIEW2_WEB_ERROR_STATUS_UNEXPECTED_ERROR, wxWEBVIEW_NAV_ERR_OTHER) + } + } + HandleWindowEvent(event); + } + else + { + AddPendingEvent(wxWebViewEvent(wxEVT_WEBVIEW_NAVIGATED, GetId(), uri, wxString())); + if (m_historyEnabled && !m_historyLoadingFromList && + (uri == GetCurrentURL()) || + (GetCurrentURL().substr(0, 4) == "file" && + wxFileName::URLToFileName(GetCurrentURL()).GetFullPath() == uri)) + { + // If we are not at the end of the list, then erase everything + // between us and the end before adding the new page + if (m_historyPosition != static_cast(m_historyList.size()) - 1) + { + m_historyList.erase(m_historyList.begin() + m_historyPosition + 1, + m_historyList.end()); + } + wxSharedPtr item(new wxWebViewHistoryItem(uri, GetCurrentTitle())); + m_historyList.push_back(item); + m_historyPosition++; + } + //Reset as we are done now + m_historyLoadingFromList = false; + } + return S_OK; + }) + .Get(), &m_navigationCompletedToken); + m_webView->add_NewWindowRequested( + Callback( + [this](IWebView2WebView* WXUNUSED(sender), IWebView2NewWindowRequestedEventArgs* args) -> HRESULT + { + PWSTR uri; + args->get_Uri(&uri); + wxString evtURL(uri); + AddPendingEvent(wxWebViewEvent(wxEVT_WEBVIEW_NEWWINDOW, GetId(), evtURL, wxString())); + args->put_Handled(true); + return S_OK; + }).Get(), &m_newWindowRequestedToken); + LoadURL(m_pendingURL); +} + +void wxWebViewEdge::OnSize(wxSizeEvent& event) +{ + UpdateBounds(); + event.Skip(); +} + +void wxWebViewEdge::UpdateBounds() +{ + RECT r; + wxCopyRectToRECT(GetClientRect(), r); + if (m_webView) + m_webView->put_Bounds(r); +} + +void wxWebViewEdge::LoadURL(const wxString& url) +{ + if (!m_webView) + { + m_pendingURL = url; + return; + } + if (FAILED(m_webView->Navigate(url.wc_str()))) + wxLogError("Could not navigate to URL"); +} + +void wxWebViewEdge::LoadHistoryItem(wxSharedPtr item) +{ + int pos = -1; + for (unsigned int i = 0; i < m_historyList.size(); i++) + { + //We compare the actual pointers to find the correct item + if (m_historyList[i].get() == item.get()) + pos = i; + } + // TODO: wxASSERT_MSG(pos != static_cast(m_impl->m_historyList.size()), "invalid history item"); + m_historyLoadingFromList = true; + LoadURL(item->GetUrl()); + m_historyPosition = pos; +} + +wxVector > wxWebViewEdge::GetBackwardHistory() +{ + wxVector > backhist; + //As we don't have std::copy or an iterator constructor in the wxwidgets + //native vector we construct it by hand + for (int i = 0; i < m_historyPosition; i++) + { + backhist.push_back(m_historyList[i]); + } + return backhist; +} + +wxVector > wxWebViewEdge::GetForwardHistory() +{ + wxVector > forwardhist; + //As we don't have std::copy or an iterator constructor in the wxwidgets + //native vector we construct it by hand + for (int i = m_historyPosition + 1; i < static_cast(m_historyList.size()); i++) + { + forwardhist.push_back(m_historyList[i]); + } + return forwardhist; +} + +bool wxWebViewEdge::CanGoForward() const +{ + if (m_historyEnabled) + return m_historyPosition != static_cast(m_historyList.size()) - 1; + else + return false; + + /* + BOOL result = false; + if (m_webView && SUCCEEDED(m_webView->get_CanGoForward(&result))) + return result; + else + return false; + */ +} + +bool wxWebViewEdge::CanGoBack() const +{ + if (m_historyEnabled) + return m_historyPosition > 0; + else + return false; + /* + BOOL result = false; + + if (m_webView && SUCCEEDED(m_webView->get_CanGoBack(&result))) + return result; + else + return false; + */ +} + +void wxWebViewEdge::GoBack() +{ + LoadHistoryItem(m_historyList[m_historyPosition - 1]); + /* if (m_webView) + m_webView->GoBack(); */ +} + +void wxWebViewEdge::GoForward() +{ + LoadHistoryItem(m_historyList[m_historyPosition + 1]); + /* if (m_webView) + m_webView->GoForward(); */ +} + +void wxWebViewEdge::ClearHistory() +{ + m_historyList.clear(); + m_historyPosition = -1; +} + +void wxWebViewEdge::EnableHistory(bool enable) +{ + m_historyEnabled = enable; + m_historyList.clear(); + m_historyPosition = -1; +} + +void wxWebViewEdge::Stop() +{ + if (m_webView) + m_webView->Stop(); +} + +void wxWebViewEdge::Reload(wxWebViewReloadFlags WXUNUSED(flags)) +{ + if (m_webView) + m_webView->Reload(); +} + +wxString wxWebViewEdge::GetPageSource() const +{ + return wxString(); +} + +wxString wxWebViewEdge::GetPageText() const +{ + return wxString(); +} + +bool wxWebViewEdge::IsBusy() const +{ + return m_isBusy; +} + +wxString wxWebViewEdge::GetCurrentURL() const +{ + LPWSTR uri; + if (m_webView && SUCCEEDED(m_webView->get_Source(&uri))) + return wxString(uri); + else + return wxString(); +} + +wxString wxWebViewEdge::GetCurrentTitle() const +{ + PWSTR _title; + if (m_webView && SUCCEEDED(m_webView->get_DocumentTitle(&_title))) + return wxString(_title); + else + return wxString(); +} + +void wxWebViewEdge::SetZoomType(wxWebViewZoomType) +{ + +} + +wxWebViewZoomType wxWebViewEdge::GetZoomType() const +{ + return wxWEBVIEW_ZOOM_TYPE_LAYOUT; +} + +bool wxWebViewEdge::CanSetZoomType(wxWebViewZoomType type) const +{ + return (type == wxWEBVIEW_ZOOM_TYPE_LAYOUT); +} + +void wxWebViewEdge::Print() +{ + +} + +wxWebViewZoom wxWebViewEdge::GetZoom() const +{ + double old_zoom_factor = 0.0f; + m_webView->get_ZoomFactor(&old_zoom_factor); + if (old_zoom_factor > 1.7f) + return wxWEBVIEW_ZOOM_LARGEST; + if (old_zoom_factor > 1.3f) + return wxWEBVIEW_ZOOM_LARGE; + if (old_zoom_factor > 0.8f) + return wxWEBVIEW_ZOOM_MEDIUM; + if (old_zoom_factor > 0.6f) + return wxWEBVIEW_ZOOM_SMALL; + return wxWEBVIEW_ZOOM_TINY; +} + +void wxWebViewEdge::SetZoom(wxWebViewZoom zoom) +{ + double old_zoom_factor = 0.0f; + m_webView->get_ZoomFactor(&old_zoom_factor); + double zoom_factor = 1.0f; + switch (zoom) + { + case wxWEBVIEW_ZOOM_LARGEST: + zoom_factor = 2.0f; + break; + case wxWEBVIEW_ZOOM_LARGE: + zoom_factor = 1.5f; + break; + case wxWEBVIEW_ZOOM_MEDIUM: + zoom_factor = 1.0f; + break; + case wxWEBVIEW_ZOOM_SMALL: + zoom_factor = 0.75f; + break; + case wxWEBVIEW_ZOOM_TINY: + zoom_factor = 0.5f; + break; + default: + break; + } + m_webView->put_ZoomFactor(zoom_factor); +} + +bool wxWebViewEdge::CanCut() const +{ + return false; +} + +bool wxWebViewEdge::CanCopy() const +{ + return false; +} + +bool wxWebViewEdge::CanPaste() const +{ + return false; +} + +void wxWebViewEdge::Cut() +{ + +} + +void wxWebViewEdge::Copy() +{ + +} + +void wxWebViewEdge::Paste() +{ + +} + +bool wxWebViewEdge::CanUndo() const +{ + return false; +} + +bool wxWebViewEdge::CanRedo() const +{ + return false; +} + +void wxWebViewEdge::Undo() +{ + +} + +void wxWebViewEdge::Redo() +{ + +} + +long wxWebViewEdge::Find(const wxString& WXUNUSED(text), int WXUNUSED(flags)) +{ + return -1; +} + +//Editing functions +void wxWebViewEdge::SetEditable(bool WXUNUSED(enable)) +{ + +} + +bool wxWebViewEdge::IsEditable() const +{ + return false; +} + +void wxWebViewEdge::SelectAll() +{ + +} + +bool wxWebViewEdge::HasSelection() const +{ + return false; +} + +void wxWebViewEdge::DeleteSelection() +{ + +} + +wxString wxWebViewEdge::GetSelectedText() const +{ + return wxString(); +} + +wxString wxWebViewEdge::GetSelectedSource() const +{ + return wxString(); +} + +void wxWebViewEdge::ClearSelection() +{ + +} + +void wxWebViewEdge::EnableContextMenu(bool enable) +{ + wxCOMPtr settings; + if (SUCCEEDED(m_webView->get_Settings(&settings))) + { + wxCOMPtr settings2; + if (SUCCEEDED(settings->QueryInterface(IID_PPV_ARGS(&settings2)))) + { + settings2->put_AreDefaultContextMenusEnabled(enable); + } + } +} + +bool wxWebViewEdge::IsContextMenuEnabled() const +{ + wxCOMPtr settings; + if (SUCCEEDED(m_webView->get_Settings(&settings))) + { + wxCOMPtr settings2; + if (SUCCEEDED(settings->QueryInterface(IID_PPV_ARGS(&settings2)))) + { + BOOL menusEnabled = TRUE; + settings2->get_AreDefaultContextMenusEnabled(&menusEnabled); + + if (!menusEnabled) + return false; + } + } + + return true; +} + +bool wxWebViewEdge::RunScriptSync(const wxString& javascript, wxString* output) +{ + bool scriptExecuted = false; + + HRESULT hr = m_webView->ExecuteScript(javascript.wc_str(), Callback( + [&scriptExecuted, output](HRESULT error, PCWSTR result) -> HRESULT + { + if (error == S_OK) + { + if (output) + output->assign(result); + } + else + wxLogError(_("RunScript failed: %.8x"), error); + + scriptExecuted = true; + + return S_OK; + }).Get()); + + + while (!scriptExecuted) + wxYield(); + + return SUCCEEDED(hr); +} + +bool wxWebViewEdge::RunScript(const wxString& javascript, wxString* output) +{ + wxJSScriptWrapper wrapJS(javascript, &m_runScriptCount); + + // This string is also used as an error indicator: it's cleared if there is + // no error or used in the warning message below if there is one. + wxString result; + if (RunScriptSync(wrapJS.GetWrappedCode(), &result) + && result == wxS("true")) + { + if (RunScriptSync(wrapJS.GetOutputCode(), &result)) + { + if (output) + *output = result; + result.clear(); + } + + RunScriptSync(wrapJS.GetCleanUpCode()); + } + + if (!result.empty()) + { + wxLogWarning(_("Error running JavaScript: %s"), result); + return false; + } + + return true; +} + +void wxWebViewEdge::RegisterHandler(wxSharedPtr handler) +{ + +} + +void wxWebViewEdge::DoSetPage(const wxString& html, const wxString& WXUNUSED(baseUrl)) +{ + if (m_webView) + m_webView->NavigateToString(html.wc_str()); +} + +// ---------------------------------------------------------------------------- +// Module ensuring all global/singleton objects are destroyed on shutdown. +// ---------------------------------------------------------------------------- + +class wxWebViewEdgeModule : public wxModule +{ +public: + wxWebViewEdgeModule() + { + } + + virtual bool OnInit() wxOVERRIDE + { + return true; + } + + virtual void OnExit() wxOVERRIDE + { + wxWebViewEdge::Uninitalize(); + } + +private: + wxDECLARE_DYNAMIC_CLASS(wxWebViewEdgeModule); +}; + +wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewEdgeModule, wxModule); + +#endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_EDGE