From 207e5b97657db5c5465712ea4c673662f4eb82f9 Mon Sep 17 00:00:00 2001 From: Steven Lamerton Date: Wed, 16 Jan 2013 10:17:44 +0000 Subject: [PATCH] Initial commit --- .gitignore | 2 + CMakeLists.txt | 29 ++ FindCEF.cmake | 40 +++ LICENSE | 53 +++ sample/CMakeLists.txt | 9 + sample/simple.cpp | 29 ++ sample/simple.h | 21 ++ webview_chromium.cpp | 806 ++++++++++++++++++++++++++++++++++++++++++ webview_chromium.h | 166 +++++++++ 9 files changed, 1155 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 FindCEF.cmake create mode 100644 LICENSE create mode 100644 sample/CMakeLists.txt create mode 100644 sample/simple.cpp create mode 100644 sample/simple.h create mode 100644 webview_chromium.cpp create mode 100644 webview_chromium.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8d2bdf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Build folder +build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..88317d6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +# Author: Steven Lamerton +# Copyright: (c) 2013 Steven Lamerton +# Licence: wxWindows licence + +# Required to find the webview library +cmake_minimum_required(VERSION 2.8.8) + +project(wxwebviewchromium) + +# Set the module path so we can find FindCEF +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) + +# Find CEF +find_package(CEF) +include_directories(${CEF_INCLUDE_DIR}) + +if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +# Find wxWidgets +find_package(wxWidgets COMPONENTS webview core base REQUIRED) +include(${wxWidgets_USE_FILE}) + +# Addwxwebviewchromium to a simple library so we can use it in all samples +add_library(wvc STATIC webview_chromium.cpp webview_chromium.h) + + +add_subdirectory(sample) diff --git a/FindCEF.cmake b/FindCEF.cmake new file mode 100644 index 0000000..ce9b78e --- /dev/null +++ b/FindCEF.cmake @@ -0,0 +1,40 @@ +# Author: Steven Lamerton +# Copyright: (c) 2013 Steven Lamerton +# Licence: wxWindows licence + +# Find module for the Chromium Embedded Framework + +include(SelectLibraryConfigurations) +include(FindPackageHandleStandardArgs) + +set(CEF_ROOT_DIR "" CACHE PATH "CEF root directory") + +find_path(CEF_INCLUDE_DIR "include/cef_version.h" + HINTS ${CEF_ROOT_DIR}) + +# On Windows find the dll_wrapper +if(WIN32) +find_library(CEF_WRAPPER_LIBRARY_RELEASE NAMES libcef_dll_wrapper + HINTS "${CEF_ROOT_DIR}/lib" + PATH_SUFFIXES "Release") +find_library(CEF_WRAPPER_LIBRARY_DEBUG NAMES libcef_dll_wrapper + HINTS "${CEF_ROOT_DIR}/lib" + PATH_SUFFIXES "Debug") +select_library_configurations(CEF_WRAPPER) +endif() + +# Find the library itself +find_library(CEF_LIBRARY_RELEASE NAMES libcef + HINTS "${CEF_ROOT_DIR}/lib" + PATH_SUFFIXES "Release") +find_library(CEF_LIBRARY_DEBUG NAMES libcef + HINTS "${CEF_ROOT_DIR}/lib" + PATH_SUFFIXES "Debug") +select_library_configurations(CEF) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(CEF DEFAULT_MSG + CEF_INCLUDE_DIR) + +mark_as_advanced(CEF_INCLUDE_DIR) \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fa803b1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,53 @@ + wxWindows Library Licence, Version 3.1 + ====================================== + + Copyright (C) 1998-2005 Julian Smart, Robert Roebling et al + + Everyone is permitted to copy and distribute verbatim copies + of this licence document, but changing it is not allowed. + + WXWINDOWS LIBRARY LICENCE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public Licence as published by + the Free Software Foundation; either version 2 of the Licence, or (at + your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library + General Public Licence for more details. + + You should have received a copy of the GNU Library General Public Licence + along with this software, usually in a file named COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA. + + EXCEPTION NOTICE + + 1. As a special exception, the copyright holders of this library give + permission for additional uses of the text contained in this release of + the library as licenced under the wxWindows Library Licence, applying + either version 3.1 of the Licence, or (at your option) any later version of + the Licence as published by the copyright holders of version + 3.1 of the Licence document. + + 2. The exception is that you may use, copy, link, modify and distribute + under your own terms, binary object code versions of works based + on the Library. + + 3. If you copy code from files distributed under the terms of the GNU + General Public Licence or the GNU Library General Public Licence into a + copy of this library, as this licence permits, the exception does not + apply to the code that you add in this way. To avoid misleading anyone as + to the status of such modified files, you must delete this exception + notice from such code and/or adjust the licensing conditions notice + accordingly. + + 4. If you write modifications of your own for this library, it is your + choice whether to permit this exception to apply to your modifications. + If you do not wish that, you must delete the exception notice from such + code and/or adjust the licensing conditions notice accordingly. + + diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt new file mode 100644 index 0000000..684abba --- /dev/null +++ b/sample/CMakeLists.txt @@ -0,0 +1,9 @@ +# Author: Steven Lamerton +# Copyright: (c) 2013 Steven Lamerton +# Licence: wxWindows licence + +# Set up the exe +add_executable(simple WIN32 simple.cpp simple.h) +target_link_libraries(simple wvc ${wxWidgets_LIBRARIES} + debug ${CEF_LIBRARY_DEBUG} debug ${CEF_WRAPPER_LIBRARY_DEBUG} + optimized ${CEF_LIBRARY_RELEASE} optimized ${CEF_WRAPPER_LIBRARY_RELEASE}) diff --git a/sample/simple.cpp b/sample/simple.cpp new file mode 100644 index 0000000..d1817de --- /dev/null +++ b/sample/simple.cpp @@ -0,0 +1,29 @@ +///////////////////////////////////////////////////////////////////////////// +// Author: Steven Lamerton +// Copyright: (c) 2013 Steven Lamerton +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "simple.h" +#include "../webview_chromium.h" + +bool SimpleApp::OnInit() +{ + SimpleFrame *frame = new SimpleFrame(); + frame->Show(true); + + return true; +} + +SimpleFrame::SimpleFrame() : wxFrame(NULL, wxID_ANY, "wxWebViewChromium") +{ + wxWebView::RegisterFactory(wxWebViewBackendChromium, wxSharedPtr + (new wxWebViewFactoryChromium)); + wxWebView* webview = wxWebView::New(this, wxID_ANY, "http://www.whatismybrowser.com/", + wxDefaultPosition, wxDefaultSize, wxWebViewBackendChromium); +} diff --git a/sample/simple.h b/sample/simple.h new file mode 100644 index 0000000..6f5378f --- /dev/null +++ b/sample/simple.h @@ -0,0 +1,21 @@ +#ifndef _SIMPLE_H_ +#define _SIMPLE_H_ + +#include +#include + +class SimpleApp : public wxApp +{ +public: + virtual bool OnInit(); +}; + +class SimpleFrame : public wxFrame +{ +public: + SimpleFrame(); +}; + +IMPLEMENT_APP(SimpleApp) + +#endif diff --git a/webview_chromium.cpp b/webview_chromium.cpp new file mode 100644 index 0000000..3fda0a4 --- /dev/null +++ b/webview_chromium.cpp @@ -0,0 +1,806 @@ +///////////////////////////////////////////////////////////////////////////// +// Author: Steven Lamerton +// Copyright: (c) 2013 Steven Lamerton +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "webview_chromium.h" +#include +#include + +#ifdef __VISUALC__ +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +#include + +#if CEF_REVISION < 607 +#include +#else +#include +#include +#include +#include +#endif + +#ifdef __VISUALC__ +#pragma warning(pop) +#endif + +extern const char wxWebViewBackendChromium[] = "wxWebViewChromium"; + +// ClientHandler implementation. +class ClientHandler : public CefClient, + public CefDisplayHandler, + public CefDragHandler, + public CefFindHandler, + public CefFocusHandler, + public CefJSDialogHandler, + public CefKeyboardHandler, + public CefLifeSpanHandler, + public CefLoadHandler, + public CefMenuHandler, + public CefPrintHandler, + public CefRequestHandler, + public CefV8ContextHandler + +{ +public: + ClientHandler(wxWebViewChromium* webview) : m_webview(webview), + m_busyCount(0), + m_cancelLoad(false) {}; + virtual ~ClientHandler() {}; + + //CefClient methods + virtual CefRefPtr GetDisplayHandler() { return this; } + virtual CefRefPtr GetDragHandler() { return this; } + virtual CefRefPtr GetFindHandler() { return this; } + virtual CefRefPtr GetFocusHandler() { return this; } + virtual CefRefPtr GetJSDialogHandler() { return this; } + virtual CefRefPtr GetKeyboardHandler() { return this; } + virtual CefRefPtr GetLifeSpanHandler() { return this; } + virtual CefRefPtr GetLoadHandler() { return this; } + virtual CefRefPtr GetMenuHandler() { return this; } + virtual CefRefPtr GetPrintHandler() { return this; } + virtual CefRefPtr GetRequestHandler() { return this; } + virtual CefRefPtr GetV8ContextHandler() { return this; } + + //CefDisplayHandler methods + virtual void OnAddressChange(CefRefPtr, + CefRefPtr, + const CefString&) {} + virtual bool OnConsoleMessage(CefRefPtr, + const CefString&, + const CefString&, + int) { return false; } + virtual void OnContentsSizeChange(CefRefPtr, + CefRefPtr, int, + int) {} + virtual void OnNavStateChange(CefRefPtr, + bool, bool) {} + virtual void OnStatusMessage(CefRefPtr, + const CefString&, + CefDisplayHandler::StatusType) {} + virtual void OnTitleChange(CefRefPtr, + const CefString&); + virtual bool OnTooltip(CefRefPtr, CefString&) + { return false; } + + //CefDragHandler methods + virtual bool OnDragStart(CefRefPtr, + CefRefPtr, + DragOperationsMask) { return false; } + virtual bool OnDragEnter(CefRefPtr, + CefRefPtr, + DragOperationsMask) { return false; } + + //CefFindHandler methods + virtual void OnFindResult(CefRefPtr, int, + int, const CefRect&, + int, bool) {} + + //CefFocusHandler methods + virtual void OnFocusedNodeChanged(CefRefPtr, + CefRefPtr, + CefRefPtr) {} + virtual bool OnSetFocus(CefRefPtr, + CefFocusHandler::FocusSource) { return false; } + virtual void OnTakeFocus(CefRefPtr, bool) {} + + //CefJSDialogandler methods + virtual bool OnJSAlert(CefRefPtr, + CefRefPtr, + const CefString&) { return false; } + virtual bool OnJSConfirm(CefRefPtr, + CefRefPtr, + const CefString&, bool&) + { return false; } + virtual bool OnJSPrompt(CefRefPtr, + CefRefPtr, + const CefString&, + const CefString&, bool&, + CefString&) { return false; } + + //CefKeyboardHandler methods + virtual bool OnKeyEvent(CefRefPtr, + KeyEventType, int, int, + bool, bool) + { return false; } + + //CefLifeSpanHandler methods + virtual bool OnBeforePopup(CefRefPtr parentBrowser, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + const CefString& url, + CefRefPtr& client, + CefBrowserSettings& settings); + virtual void OnAfterCreated(CefRefPtr) {} + virtual bool DoClose(CefRefPtr) { return false; }; + virtual void OnBeforeClose(CefRefPtr) {} + + //CefLoadHandler methods + virtual void OnLoadStart(CefRefPtr browser, + CefRefPtr frame); + virtual void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode); + virtual bool OnLoadError(CefRefPtr browser, + CefRefPtr frame, ErrorCode errorCode, + const CefString& failedUrl, CefString& errorText); + + //CefMenuHandler methods + virtual void GetMenuLabel(CefRefPtr, + CefMenuHandler::MenuId, CefString&) + {} + virtual bool OnBeforeMenu(CefRefPtr< CefBrowser >, + const CefMenuInfo&) { return false; } + virtual bool OnMenuAction(CefRefPtr< CefBrowser >, + CefMenuHandler::MenuId) { return false; } + + //CefPrintHandler methods. + virtual bool GetPrintHeaderFooter(CefRefPtr, + CefRefPtr, + const CefPrintInfo&, + const CefString&, + const CefString&, int, + int, CefString&, + CefString&, CefString&, + CefString&, + CefString&, + CefString&) { return false; } + + virtual bool GetPrintOptions(CefRefPtr, + CefPrintOptions&) + { return false; } + + //CefRequestHandler methods + virtual bool OnBeforeBrowse(CefRefPtr, + CefRefPtr, + CefRefPtr, + CefRequestHandler::NavType, + bool); + + //CefV8ContextHandler methods + virtual void OnContextCreated(CefRefPtr, + CefRefPtr, + CefRefPtr) {} + + virtual void OnContextReleased(CefRefPtr, + CefRefPtr, + CefRefPtr) {} + + bool IsBusy() { return m_busyCount != 0; } + + IMPLEMENT_REFCOUNTING(ClientHandler); + +private: + wxWebViewChromium* m_webview; + long m_busyCount; + //Cancel the next load as the new windw has been vetoed + bool m_cancelLoad; +}; + +class CustomSchemeHandler : public CefSchemeHandler +{ +public: + CustomSchemeHandler(wxSharedPtr handler) : m_handler(handler) {} + + virtual bool ProcessRequest(CefRefPtr request, + CefRefPtr callback); + virtual void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl); + virtual void Cancel() {}; + virtual bool ReadResponse(void* data_out, int bytes_to_read, + int& bytes_read, + CefRefPtr callback); +private: + wxSharedPtr m_handler; + wxFSFile* m_file; + IMPLEMENT_REFCOUNTING(CustomSchemeHandler); +}; + +class CustomSchemeHandlerFactory : public CefSchemeHandlerFactory +{ +public: + CustomSchemeHandlerFactory(wxSharedPtr handler) : m_handler(handler) {} + + virtual CefRefPtr Create(CefRefPtr WXUNUSED(browser), + const CefString& WXUNUSED(scheme_name), + CefRefPtr WXUNUSED(request)) + { + return new CustomSchemeHandler(m_handler); + } + +private: + wxSharedPtr m_handler; + IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory); +}; + +wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewChromium, wxWebView); + +wxBEGIN_EVENT_TABLE(wxWebViewChromium, wxWebView) + EVT_IDLE(wxWebViewChromium::OnIdle) + EVT_SIZE(wxWebViewChromium::OnSize) +wxEND_EVENT_TABLE() + +bool wxWebViewChromium::Create(wxWindow* parent, + wxWindowID id, + const wxString& url, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if (!wxControl::Create(parent, id, pos, size, style, + wxDefaultValidator, name)) + { + return false; + } + + m_historyLoadingFromList = false; + m_historyEnabled = true; + m_historyPosition = -1; + + CefWindowInfo info; + CefBrowserSettings browsersettings; + CefSettings settings; + + CefInitialize(settings, CefRefPtr()); + + wxSize wxsize = GetSize(); + wxPoint wxpos = GetPosition(); + RECT rect; + rect.top = wxpos.x; + rect.bottom = wxsize.GetHeight(); + rect.left = wxpos.y; + rect.right = wxsize.GetWidth(); + + // Initialize window info to the defaults for a child window + info.SetAsChild(GetHWND(), rect); + + // Creat the new child browser window + m_browser = CefBrowser::CreateBrowserSync(info, new ClientHandler(this), url.ToStdString(), browsersettings); + return true; +} + +void wxWebViewChromium::OnIdle(wxIdleEvent &event) +{ + CefDoMessageLoopWork(); + event.Skip(); +} + +void wxWebViewChromium::OnSize(wxSizeEvent &WXUNUSED(event)) +{ + wxSize size = GetSize(); + wxPoint pos = GetPosition(); + RECT rect; + rect.top = pos.x; + rect.bottom = size.GetHeight(); + rect.left = pos.y; + rect.right = size.GetWidth(); + +#ifdef __WXMSW__ + HDWP hdwp = BeginDeferWindowPos(1); + hdwp = DeferWindowPos(hdwp, m_browser->GetWindowHandle(), NULL, rect.left, + rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER); + EndDeferWindowPos(hdwp); +#endif +} + +bool wxWebViewChromium::CanGoForward() const +{ + if(m_historyEnabled) + return m_historyPosition != static_cast(m_historyList.size()) - 1; + else + return false; +} + +bool wxWebViewChromium::CanGoBack() const +{ + if(m_historyEnabled) + return m_historyPosition > 0; + else + return false; +} + +void wxWebViewChromium::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; + } + wxASSERT_MSG(pos != static_cast(m_historyList.size()), + "invalid history item"); + m_historyLoadingFromList = true; + LoadURL(item->GetUrl()); + m_historyPosition = pos; +} + +wxVector > wxWebViewChromium::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 > wxWebViewChromium::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; +} + +void wxWebViewChromium::GoBack() +{ + LoadHistoryItem(m_historyList[m_historyPosition - 1]); +} + +void wxWebViewChromium::GoForward() +{ + LoadHistoryItem(m_historyList[m_historyPosition + 1]); +} + +void wxWebViewChromium::LoadURL(const wxString& url) +{ + m_browser->GetMainFrame()->LoadURL(url.ToStdString()); +} + +void wxWebViewChromium::ClearHistory() +{ + m_historyList.clear(); + m_historyPosition = -1; +} + +void wxWebViewChromium::EnableHistory(bool enable) +{ + m_historyEnabled = enable; +} + +void wxWebViewChromium::Stop() +{ + m_browser->StopLoad(); +} + +void wxWebViewChromium::Reload(wxWebViewReloadFlags flags) +{ + if(flags == wxWEB_VIEW_RELOAD_NO_CACHE) + { + m_browser->ReloadIgnoreCache(); + } + else + { + m_browser->Reload(); + } +} + +wxString wxWebViewChromium::GetPageSource() const +{ + return m_browser->GetMainFrame()->GetSource().ToString(); +} + +wxString wxWebViewChromium::GetPageText() const +{ + return m_browser->GetMainFrame()->GetText().ToString(); +} + +wxString wxWebViewChromium::GetCurrentURL() const +{ + return m_browser->GetMainFrame()->GetURL().ToString(); +} + +wxString wxWebViewChromium::GetCurrentTitle() const +{ + return m_title; +} + +void wxWebViewChromium::Print() +{ + m_browser->GetMainFrame()->Print(); +} + +void wxWebViewChromium::Cut() +{ + m_browser->GetMainFrame()->Cut(); +} + +void wxWebViewChromium::Copy() +{ + m_browser->GetMainFrame()->Copy(); +} + +void wxWebViewChromium::Paste() +{ + m_browser->GetMainFrame()->Paste(); +} + +void wxWebViewChromium::Undo() +{ + m_browser->GetMainFrame()->Undo(); +} + +void wxWebViewChromium::Redo() +{ + m_browser->GetMainFrame()->Redo(); +} + +void wxWebViewChromium::SelectAll() +{ + m_browser->GetMainFrame()->SelectAll(); +} + +void wxWebViewChromium::DeleteSelection() +{ + wxString jsdelete = "if (window.getSelection) { if (window.getSelection().deleteFromDocument) { window.getSelection().deleteFromDocument(); } }"; + RunScript(jsdelete); +} + +void wxWebViewChromium::ClearSelection() +{ + wxString jsclear = "if (window.getSelection) { if (window.getSelection().empty) { window.getSelection().empty(); } }"; + RunScript(jsclear); +} + +void wxWebViewChromium::RunScript(const wxString& javascript) +{ + m_browser->GetMainFrame()->ExecuteJavaScript(javascript.ToStdString(), "", 0); +} + +bool wxWebViewChromium::IsBusy() const +{ + return static_cast(m_browser->GetClient().get())->IsBusy(); +} + +void wxWebViewChromium::SetEditable(bool enable) +{ + wxString mode = enable ? "\"on\"" : "\"off\""; + RunScript("document.designMode = " + mode); +} + +void wxWebViewChromium::DoSetPage(const wxString& html, const wxString& baseUrl) +{ + m_browser->GetMainFrame()->LoadString(html.ToStdString(), baseUrl.ToStdString()); +} + +wxWebViewZoom wxWebViewChromium::GetZoom() const +{ + float zoom = m_browser->GetZoomLevel(); + // arbitrary way to map float zoom to our common zoom enum + if (zoom <= -0.75f) + { + return wxWEB_VIEW_ZOOM_TINY; + } + else if (zoom > -0.75 && zoom <= -0.25) + { + return wxWEB_VIEW_ZOOM_SMALL; + } + else if (zoom > -0.25 && zoom <= 0.25) + { + return wxWEB_VIEW_ZOOM_MEDIUM; + } + else if (zoom > 0.25 && zoom <= 0.75) + { + return wxWEB_VIEW_ZOOM_LARGE; + } + else if (zoom > 0.75) + { + return wxWEB_VIEW_ZOOM_LARGEST; + } + + // to shut up compilers, this can never be reached logically + wxASSERT(false); + return wxWEB_VIEW_ZOOM_MEDIUM; +} + + +void wxWebViewChromium::SetZoom(wxWebViewZoom zoom) +{ + // arbitrary way to map our common zoom enum to float zoom + switch (zoom) + { + case wxWEB_VIEW_ZOOM_TINY: + m_browser->SetZoomLevel(-1.0f); + break; + + case wxWEB_VIEW_ZOOM_SMALL: + m_browser->SetZoomLevel(-0.5f); + break; + + case wxWEB_VIEW_ZOOM_MEDIUM: + m_browser->SetZoomLevel(0.0f); + break; + + case wxWEB_VIEW_ZOOM_LARGE: + m_browser->SetZoomLevel(0.5f); + break; + + case wxWEB_VIEW_ZOOM_LARGEST: + m_browser->SetZoomLevel(1.0f); + break; + + default: + wxASSERT(false); + } +} + +void wxWebViewChromium::SetZoomType(wxWebViewZoomType type) +{ + // there is only one supported zoom type at the moment so this setter + // does nothing beyond checking sanity + wxASSERT(type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT); +} + +wxWebViewZoomType wxWebViewChromium::GetZoomType() const +{ + return wxWEB_VIEW_ZOOM_TYPE_LAYOUT; +} + +bool wxWebViewChromium::CanSetZoomType(wxWebViewZoomType type) const +{ + switch (type) + { + case wxWEB_VIEW_ZOOM_TYPE_LAYOUT: + return true; + + default: + return false; + } +} + +void wxWebViewChromium::RegisterHandler(wxSharedPtr handler) +{ + CefRegisterCustomScheme(handler->GetName().ToStdString(), true, false, false); + CefRegisterSchemeHandlerFactory(handler->GetName().ToStdString(), "", + new CustomSchemeHandlerFactory(handler)); +} + +void ClientHandler::OnTitleChange(CefRefPtr browser, const CefString& title) +{ + m_webview->m_title = title.ToString(); + wxString target = browser->GetMainFrame()->GetName().ToString(); + + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED, m_webview->GetId(), "", target); + event.SetString(title.ToString()); + event.SetEventObject(m_webview); + + m_webview->HandleWindowEvent(event); +} + +bool ClientHandler::OnBeforeBrowse(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr request, + CefRequestHandler::NavType WXUNUSED(navType), + bool WXUNUSED(isRedirect)) +{ + //If the new window event has been veted we shouldn't load the page + //This is cancelled here because it cannot be cancelled from OnBeforePopup + if(m_cancelLoad) + { + m_cancelLoad = false; + return true; + } + + wxString url = request->GetURL().ToString(); + wxString target = frame->GetName().ToString(); + + m_busyCount++; + + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING, m_webview->GetId(), url, target); + event.SetEventObject(m_webview); + + m_webview->HandleWindowEvent(event); + + if (!event.IsAllowed()) + { + m_busyCount--; + return true; + } + return false; +} + +void ClientHandler::OnLoadStart(CefRefPtr WXUNUSED(browser), CefRefPtr WXUNUSED(frame)) +{ + //We actually use OnBeforeBrowse as then we can veto +} + +void ClientHandler::OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int WXUNUSED(httpStatusCode)) +{ + m_busyCount--; + + wxString url = frame->GetURL().ToString(); + wxString target = frame->GetName().ToString(); + + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED, m_webview->GetId(), url, target); + event.SetEventObject(m_webview); + + m_webview->HandleWindowEvent(event); + + if(frame->IsMain()) + { + //As we are complete we also add to the history list, but not if the + //page is not the main page, ie it is a subframe + if(m_webview->m_historyEnabled && !m_webview->m_historyLoadingFromList) + { + //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_webview->m_historyPosition != static_cast(m_webview->m_historyList.size()) - 1) + { + m_webview->m_historyList.erase(m_webview->m_historyList.begin() + m_webview->m_historyPosition + 1, + m_webview->m_historyList.end()); + } + wxSharedPtr item(new wxWebViewHistoryItem(url, m_webview->GetCurrentTitle())); + m_webview->m_historyList.push_back(item); + m_webview->m_historyPosition++; + } + //Reset as we are done now + m_webview->m_historyLoadingFromList = false; + + wxWebViewEvent levent(wxEVT_COMMAND_WEB_VIEW_LOADED, m_webview->GetId(), url, target); + levent.SetEventObject(m_webview); + + m_webview->HandleWindowEvent(levent); + } +} + +bool ClientHandler::OnLoadError(CefRefPtr WXUNUSED(browser), CefRefPtr frame, ErrorCode errorCode, + const CefString& failedUrl, CefString& errorText) +{ + //We define a macro for convenience +#define ERROR_TYPE_CASE(error, wxtype) case(error): \ + type = wxtype;\ + break + + wxWebViewNavigationError type = wxWEB_NAV_ERR_OTHER; + switch (errorCode) + { + ERROR_TYPE_CASE(ERR_FAILED, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_ABORTED, wxWEB_NAV_ERR_USER_CANCELLED); + ERROR_TYPE_CASE(ERR_INVALID_ARGUMENT, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_INVALID_HANDLE, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_FILE_NOT_FOUND, wxWEB_NAV_ERR_NOT_FOUND); + ERROR_TYPE_CASE(ERR_TIMED_OUT, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_FILE_TOO_BIG, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_UNEXPECTED, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_ACCESS_DENIED, wxWEB_NAV_ERR_AUTH); + ERROR_TYPE_CASE(ERR_NOT_IMPLEMENTED, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_CONNECTION_CLOSED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_CONNECTION_RESET, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_CONNECTION_REFUSED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_CONNECTION_ABORTED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_CONNECTION_FAILED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_NAME_NOT_RESOLVED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_INTERNET_DISCONNECTED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_SSL_PROTOCOL_ERROR, wxWEB_NAV_ERR_SECURITY); + ERROR_TYPE_CASE(ERR_ADDRESS_INVALID, wxWEB_NAV_ERR_REQUEST); + ERROR_TYPE_CASE(ERR_ADDRESS_UNREACHABLE, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, wxWEB_NAV_ERR_AUTH); + ERROR_TYPE_CASE(ERR_TUNNEL_CONNECTION_FAILED, wxWEB_NAV_ERR_CONNECTION); + ERROR_TYPE_CASE(ERR_NO_SSL_VERSIONS_ENABLED, wxWEB_NAV_ERR_SECURITY); + ERROR_TYPE_CASE(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, wxWEB_NAV_ERR_SECURITY); + ERROR_TYPE_CASE(ERR_SSL_RENEGOTIATION_REQUESTED, wxWEB_NAV_ERR_REQUEST); + ERROR_TYPE_CASE(ERR_CERT_COMMON_NAME_INVALID, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_DATE_INVALID, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_AUTHORITY_INVALID, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_CONTAINS_ERRORS, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_NO_REVOCATION_MECHANISM, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_UNABLE_TO_CHECK_REVOCATION, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_REVOKED, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_INVALID, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_CERT_END, wxWEB_NAV_ERR_CERTIFICATE); + ERROR_TYPE_CASE(ERR_INVALID_URL, wxWEB_NAV_ERR_REQUEST); + ERROR_TYPE_CASE(ERR_DISALLOWED_URL_SCHEME, wxWEB_NAV_ERR_REQUEST); + ERROR_TYPE_CASE(ERR_UNKNOWN_URL_SCHEME, wxWEB_NAV_ERR_REQUEST); + ERROR_TYPE_CASE(ERR_TOO_MANY_REDIRECTS, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_UNSAFE_REDIRECT, wxWEB_NAV_ERR_SECURITY); + ERROR_TYPE_CASE(ERR_UNSAFE_PORT, wxWEB_NAV_ERR_SECURITY); + ERROR_TYPE_CASE(ERR_INVALID_RESPONSE, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_INVALID_CHUNKED_ENCODING, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_METHOD_NOT_SUPPORTED, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_UNEXPECTED_PROXY_AUTH, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_EMPTY_RESPONSE, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_RESPONSE_HEADERS_TOO_BIG, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_CACHE_MISS, wxWEB_NAV_ERR_OTHER); + ERROR_TYPE_CASE(ERR_INSECURE_RESPONSE, wxWEB_NAV_ERR_SECURITY); + } + + wxString url = failedUrl.ToString(); + wxString target = frame->GetName().ToString(); + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, m_webview->GetId(), url, target); + event.SetEventObject(m_webview); + event.SetInt(type); + event.SetString(errorText.ToString()); + + m_webview->HandleWindowEvent(event); + + return false; +} + +bool ClientHandler::OnBeforePopup(CefRefPtr WXUNUSED(parentBrowser), + const CefPopupFeatures& WXUNUSED(popupFeatures), + CefWindowInfo& WXUNUSED(windowInfo), + const CefString& url, + CefRefPtr& WXUNUSED(client), + CefBrowserSettings& WXUNUSED(settings)) +{ + wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW, m_webview->GetId(), url.ToString(), ""); + event.SetEventObject(m_webview); + m_webview->HandleWindowEvent(event); + + if(!event.IsAllowed()) + { + m_cancelLoad = true; + } + + //We return true because we do not want a popup to be shown + return true; +} + +bool CustomSchemeHandler::ProcessRequest(CefRefPtr request, + CefRefPtr callback) +{ + wxString url = request->GetURL().ToString(); + + m_file = m_handler->GetFile(url); + + if(m_file) + { + callback->HeadersAvailable(); + return true; + } + return false; +} + +void CustomSchemeHandler::GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& WXUNUSED(redirectUrl)) +{ + response->SetMimeType(m_file->GetMimeType().ToStdString()); + response->SetStatus(200); + + response_length = m_file->GetStream()->GetLength(); +} + +bool CustomSchemeHandler::ReadResponse(void* data_out, int bytes_to_read, + int& bytes_read, + CefRefPtr WXUNUSED(callback)) +{ + /*wxStreamError err = */m_file->GetStream()->Read(data_out, bytes_to_read).GetLastError(); + bytes_read = m_file->GetStream()->LastRead(); + + return true; +} diff --git a/webview_chromium.h b/webview_chromium.h new file mode 100644 index 0000000..1174fc5 --- /dev/null +++ b/webview_chromium.h @@ -0,0 +1,166 @@ +///////////////////////////////////////////////////////////////////////////// +// Author: Steven Lamerton +// Copyright: (c) 2013 Steven Lamerton +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_WEBVIEWCHROMIUM_H_ +#define _WX_WEBVIEWCHROMIUM_H_ + +#ifdef __VISUALC__ +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +#include + +#if CEF_REVISION < 607 +#include +#else +#include +#endif + +#ifdef __VISUALC__ +#pragma warning(pop) +#endif + +#include +#include +#include +#include +#include + +extern const char wxWebViewBackendChromium[]; + +class WXDLLIMPEXP_WEBVIEW wxWebViewChromium : public wxWebView +{ +public: + + wxWebViewChromium() {} + + wxWebViewChromium(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); + } + + ~wxWebViewChromium() {}; + + void OnIdle(wxIdleEvent &event); + void OnSize(wxSizeEvent &event); + + 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); + + virtual void LoadURL(const wxString& url); + virtual void LoadHistoryItem(wxSharedPtr item); + virtual wxVector > GetBackwardHistory(); + virtual wxVector > GetForwardHistory(); + + virtual bool CanGoForward() const; + virtual bool CanGoBack() const; + virtual void GoBack(); + virtual void GoForward(); + virtual void ClearHistory(); + virtual void EnableHistory(bool enable = true); + virtual void Stop(); + virtual void Reload(wxWebViewReloadFlags flags = wxWEB_VIEW_RELOAD_DEFAULT); + + virtual wxString GetPageSource() const; + virtual wxString GetPageText() const; + + virtual bool IsBusy() const; + virtual wxString GetCurrentURL() const; + virtual wxString GetCurrentTitle() const; + + virtual void SetZoomType(wxWebViewZoomType type); + virtual wxWebViewZoomType GetZoomType() const; + virtual bool CanSetZoomType(wxWebViewZoomType type) const; + + virtual void Print(); + + virtual wxWebViewZoom GetZoom() const; + virtual void SetZoom(wxWebViewZoom zoom); + + virtual void* GetNativeBackend() const { return m_browser; } + + virtual long Find(const wxString& text, int flags = wxWEB_VIEW_FIND_DEFAULT) { return wxNOT_FOUND; } + + //Clipboard functions + virtual bool CanCut() const { return true; } + virtual bool CanCopy() const { return true; } + virtual bool CanPaste() const { return true; } + virtual void Cut(); + virtual void Copy(); + virtual void Paste(); + + //Undo / redo functionality + virtual bool CanUndo() const { return true; } + virtual bool CanRedo() const { return true; } + virtual void Undo(); + virtual void Redo(); + + //Editing functions + virtual void SetEditable(bool enable = true); + virtual bool IsEditable() const { return false; } + + //Selection + virtual void SelectAll(); + virtual bool HasSelection() const { return false; } + virtual void DeleteSelection(); + virtual wxString GetSelectedText() const { return ""; } + virtual wxString GetSelectedSource() const { return ""; } + virtual void ClearSelection(); + + virtual void RunScript(const wxString& javascript); + + //Virtual Filesystem Support + virtual void RegisterHandler(wxSharedPtr handler); + +protected: + virtual void DoSetPage(const wxString& html, const wxString& baseUrl); + +private: + CefRefPtr m_browser; + + //History related variables, we currently use our own implementation + wxVector > m_historyList; + int m_historyPosition; + bool m_historyLoadingFromList; + bool m_historyEnabled; + + //We need to store the title ourselves + wxString m_title; + + //We also friend ClientHandler so it can access the history + friend class ClientHandler; + + wxDECLARE_DYNAMIC_CLASS(wxWebViewChromium); + wxDECLARE_EVENT_TABLE(); +}; + +class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryChromium : public wxWebViewFactory +{ +public: + virtual wxWebView* Create() { return new wxWebViewChromium; } + 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) + { return new wxWebViewChromium(parent, id, url, pos, size, style, name); } +}; + +#endif // _WX_WEBVIEWCHROMIUM_H_