/** @file cef_control_base.h * @brief 封装Cef浏览器对象为duilib控件基类 * @copyright (c) 2016, NetEase Inc. All rights reserved * @author Redrain * @date 2019/3/20 */ #pragma once #include "include/cef_base.h" #include "cef_control_event.h" #include "cef_control/app/cef_js_bridge.h" #include "cef_control/handler/browser_handler.h" namespace nim_comp { using namespace ui; class CefControlBase : public Control, public nim_comp::BrowserHandler::HandlerDelegate { public: CefControlBase(void); virtual ~CefControlBase(void); public: /** * @brief 加载一个地址 * @param[in] url 网站地址 * @return 无 */ void LoadURL(const CefString& url); /** * @brief 给指定地址添加一个字符串资源 * @param[in] stringW 字符串资源 * @param[in] url 网址 * @return 无 */ void LoadString(const CefString& stringW, const CefString& url); /** * @brief 后退 * @return 无 */ void GoBack(); /** * @brief 前进 * @return 无 */ void GoForward(); /** * @brief 判断是否可以后退 * @return 返回 true 表示可以,false 表示不可以 */ bool CanGoBack(); /** * @brief 判断是否可以前进 * @return 返回 true 表示可以,false 表示不可以 */ bool CanGoForward(); /** * @brief 刷新 * @return 无 */ void Refresh(); /** * @brief 停止加载 * @return 无 */ void StopLoad(); /** * @brief 是否加载中 * @return 返回 true 表示加载中,否则为 false */ bool IsLoading(); /** * @brief 开始一个下载任务 * @param[in] url 要下载的文件地址 * @return 无 */ void StartDownload(const CefString& url); /** * @brief 设置页面缩放比例 * @param[in] zoom_level 比例值 * @return 无 */ void SetZoomLevel(float zoom_level); /** * @brief 获取浏览器对象所属的窗体句柄 * @return 窗口句柄 */ HWND GetCefHandle() const; /** * @brief 获取页面 URL * @return 返回 URL 地址 */ CefString GetURL(); /** * @brief 获取 UTF8 格式 URL * @return 返回 URL 地址 */ std::string GetUTF8URL(); /** * @brief 获取网址 # 号前的地址 * @param[in] url 要获取的完整地址 * @return 返回截取后的地址 */ CefString GetMainURL(const CefString& url); /** * @brief 注册一个 C++ 方法提供前端调用 * @param[in] function_name 方法名称 * @param[in] function 方法函数体 * @param[in] global_function 是否是一个全局方法 * @return 返回 true 表示注册成功,false 可能已经注册 */ bool RegisterCppFunc(const std::wstring& function_name, nim_comp::CppFunction function, bool global_function = false); /** * @brief 反注册一个 C++ 方法 * @param[in] function_name 方法名称 * @return 无 */ void UnRegisterCppFunc(const std::wstring& function_name); /** * @brief 调用一个前端已经注册好的方法 * @param[in] js_function_name 前端提供的方法名 * @param[in] params 传递 JSON 字符串格式的参数 * @param[in] callback 前端执行完成后的回调函数 * @param[in] frame_name 要调用哪个名称 frame 下的方法,默认使用主 frame * @return 返回 true 表示成功调用,false 表示调用失败,方法可能不存在 */ bool CallJSFunction(const std::wstring& js_function_name, const std::wstring& params, nim_comp::CallJsFunctionCallback callback, const std::wstring& frame_name = L""); /** * @brief 调用一个前端已经注册好的方法 * @param[in] js_function_name 前端提供的方法名 * @param[in] params 传递 JSON 字符串格式的参数 * @param[in] callback 前端执行完成后的回调函数 * @param[in] frame_id 要调用哪个 ID frame 下的方法,默认使用主 frame * @return 返回 true 表示成功调用,false 表示调用失败,方法可能不存在 */ bool CallJSFunction(const std::wstring& js_function_name, const std::wstring& params, nim_comp::CallJsFunctionCallback callback, int frame_id); /** * @brief 修复浏览器 * @return 无 */ virtual void RepairBrowser(); /** * @brief 打开开发者工具 * @param[in] view 一个 CefControl 控件实例(仅在CefControl类里需要传入) * @return 成功返回 true,失败返回 false */ virtual bool AttachDevTools(Control* view) = 0; /** * @brief 关闭开发者工具 * @return 无 */ virtual void DettachDevTools(); /** * @brief 判断是否打开开发者工具 * @return 返回 true 表示已经绑定,false 为未绑定 */ virtual bool IsAttachedDevTools() const { return devtool_attached_; } protected: virtual void ReCreateBrowser() = 0; public: /** * @brief 绑定一个回调函数用于监听右键菜单弹出 * @param[in] callback 一个回调函数,参考 OnBeforeMenuEvent 声明 * @return 无 */ void AttachBeforeContextMenu(const OnBeforeMenuEvent& callback){ cb_before_menu_ = callback; } /** * @brief 绑定一个回调函数用于监听选择了哪个右键菜单 * @param[in] callback 一个回调函数,参考 OnMenuCommandEvent 声明 * @return 无 */ void AttachMenuCommand(const OnMenuCommandEvent& callback){ cb_menu_command_ = callback; } /** * @brief 绑定一个回调函数用于监听页面 Title 改变 * @param[in] callback 一个回调函数,参考 OnTitleChangeEvent 声明 * @return 无 */ void AttachTitleChange(const OnTitleChangeEvent& callback){ cb_title_change_ = callback; } /** * @brief 绑定一个回调函数用于监听页面中 frame URL 地址改变 * @param[in] callback 一个回调函数,参考 OnUrlChangeEvent 声明 * @return 无 */ void AttachUrlChange(const OnUrlChangeEvent& callback){ cb_url_change_ = callback; } /** * @brief 绑定一个回调函数用于监听主页面 URL 地址改变 * @param[in] callback 一个回调函数,参考 OnMainURLChengeEvent 声明 * @return 无 */ void AttachMainURLChange(OnMainURLChengeEvent cb){ cb_main_url_change_ = cb; } /** * @brief 绑定一个回调函数用于监听页面资源全部加载完毕 * @param[in] callback 一个回调函数,参考 OnBeforeResourceLoadEvent 声明 * @return 无 */ void AttachBeforeNavigate(const OnBeforeResourceLoadEvent& callback){ cb_before_resource_load_ = callback; } /** * @brief 绑定一个回调函数用于监听一个弹出窗口弹出的通知 * @param[in] callback 一个回调函数,参考 OnLinkClickEvent 声明 * @return 无 */ void AttachLinkClick(const OnLinkClickEvent& callback){ cb_link_click_ = callback; } /** * @brief 绑定一个回调函数用于监听页面加载状态改变 * @param[in] callback 一个回调函数,参考 OnLoadingStateChangeEvent 声明 * @return 无 */ void AttachLoadingStateChange(const OnLoadingStateChangeEvent& callback){ cb_loadstate_change_ = callback; } /** * @brief 绑定一个回调函数用于监听页面开始加载通知 * @param[in] callback 一个回调函数,参考 OnLoadStartEvent 声明 * @return 无 */ void AttachLoadStart(const OnLoadStartEvent& callback){ cb_load_start_ = callback; } /** * @brief 绑定一个回调函数用于监听页面加载完毕通知 * @param[in] callback 一个回调函数,参考 OnLoadEndEvent 声明 * @return 无 */ void AttachLoadEnd(const OnLoadEndEvent& callback){ cb_load_end_ = callback; } /** * @brief 绑定一个回调函数用于监听界面加载错误通知 * @param[in] callback 一个回调函数,参考 OnLoadErrorEvent 声明 * @return 无 */ void AttachLoadError(const OnLoadErrorEvent& callback){ cb_load_error_ = callback; } /** * @brief 绑定一个回调函数用于监听开发者工具状态改变通知 * @param[in] callback 一个回调函数,参考 OnDevToolAttachedStateChangeEvent 声明 * @return 无 */ void AttachDevToolAttachedStateChange(const OnDevToolAttachedStateChangeEvent& callback){ cb_devtool_visible_change_ = callback; }; /** * @brief 绑定一个回调函数用于监听一个新的浏览器实例创建完毕通知 * @param[in] callback 一个回调函数,参考 OnAfterCreatedEvent 声明 * @return 无 */ void AttachAfterCreated(const OnAfterCreatedEvent& callback){ cb_after_created_ = callback; } /** * @brief 绑定一个回调函数用于监听一个浏览器实例关闭前的通知 * @param[in] callback 一个回调函数,参考 OnBeforeCloseEvent 声明 * @return 无 */ void AttachBeforeCLose(const OnBeforeCloseEvent& callback) { cb_before_close_ = callback; } /** * @brief 绑定一个回调函数用于监听一个浏览器实例加载通知 * @param[in] callback 一个回调函数,参考 OnBeforeBrowserEvent 声明 * @return 无 */ void AttachBeforeBrowser(const OnBeforeBrowserEvent& callback) { cb_before_browser_ = callback; } /** * @brief 绑定一个回调函数用于监听一个未知的 Protocol * @param[in] callback 一个回调函数,参考 OnProtocolExecutionEvent 声明 * @return 无 */ void AttachProtocolExecution(const OnProtocolExecutionEvent& callback) { cb_protocol_execution_ = callback; } /** * @brief 绑定一个回调函数用于监听一个下载任务开始之前的通知 * @param[in] callback 一个回调函数,参考 OnBeforeDownloadEvent 声明 * @return 无 */ void AttachBeforeDownload(const OnBeforeDownloadEvent& callback) { cb_before_download_ = callback; } /** * @brief 绑定一个回调函数用于监听下载过程中任务的状态改变通知 * @param[in] callback 一个回调函数,参考 OnDownloadUpdatedEvent 声明 * @return 无 */ void AttachDownloadUpdated(const OnDownloadUpdatedEvent& callback) { cb_download_updated_ = callback; } /** * @brief 绑定一个回调函数用于监听一个从对话框中打开文件的通知 * @param[in] callback 一个回调函数,参考 OnFileDialogEvent 声明 * @return 无 */ void AttachFileDialog(const OnFileDialogEvent& callback) { cb_file_dialog_ = callback; } private: // 处理BrowserHandler的HandlerDelegate委托接口 // 当浏览器渲染数据变化时,会触发此接口,此时把渲染数据保存到内存dc // 并且通知窗体刷新控件,在控件的Paint函数里把内存dc的位图画到窗体上 // 由此实现离屏渲染数据画到窗体上 virtual void OnPaint(CefRefPtr browser, CefRenderHandler::PaintElementType type, const CefRenderHandler::RectList& dirtyRects, const std::string* buffer, int width, int height) OVERRIDE; virtual void OnPopupShow(CefRefPtr browser, bool show) OVERRIDE; virtual void OnPopupSize(CefRefPtr browser, const CefRect& rect) OVERRIDE; virtual void UpdateWindowPos() OVERRIDE; virtual void OnBeforeContextMenu(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, CefRefPtr model) OVERRIDE; virtual bool OnContextMenuCommand(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, int command_id, CefContextMenuHandler::EventFlags event_flags) OVERRIDE; virtual void OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) OVERRIDE; virtual void OnTitleChange(CefRefPtr browser, const CefString& title) OVERRIDE; virtual void OnLoadingStateChange(CefRefPtr browser, bool isLoading, bool canGoBack, bool canGoForward) OVERRIDE; virtual void OnLoadStart(CefRefPtr browser, CefRefPtr frame) OVERRIDE; virtual void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) OVERRIDE; virtual void OnLoadError(CefRefPtr browser, CefRefPtr frame, CefLoadHandler::ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE; // 在非UI线程中被调用 virtual bool OnBeforePopup(CefRefPtr browser, CefRefPtr frame, const CefString& target_url, const CefString& target_frame_name, CefLifeSpanHandler::WindowOpenDisposition target_disposition, bool user_gesture, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr& client, CefBrowserSettings& settings, bool* no_javascript_access) OVERRIDE; virtual bool OnAfterCreated(CefRefPtr browser) OVERRIDE; virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE; // 在非UI线程中被调用 virtual bool OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool is_redirect) OVERRIDE; virtual void OnProtocolExecution(CefRefPtr browser, const CefString& url, bool& allow_os_execution) OVERRIDE; // 在非UI线程中被调用 virtual CefRequestHandler::ReturnValue OnBeforeResourceLoad( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr callback) OVERRIDE; virtual void OnRenderProcessTerminated(CefRefPtr browser, CefRequestHandler::TerminationStatus status) OVERRIDE; // 下载文件相关 virtual void OnBeforeDownload(CefRefPtr browser, CefRefPtr download_item, const CefString& suggested_name, CefRefPtr callback) OVERRIDE; virtual void OnDownloadUpdated( CefRefPtr browser, CefRefPtr download_item, CefRefPtr callback) OVERRIDE; // 打开文件相关 virtual bool OnFileDialog( CefRefPtr browser, CefDialogHandler::FileDialogMode mode, const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, int selected_accept_filter, CefRefPtr callback) OVERRIDE; virtual bool OnExecuteCppFunc(const CefString& function_name, const CefString& params, int js_callback_id, CefRefPtr browser) OVERRIDE; virtual bool OnExecuteCppCallbackFunc(int cpp_callback_id, const CefString& json_string) OVERRIDE; protected: CefRefPtr browser_handler_ = nullptr; std::shared_ptr js_bridge_; CefString url_; bool devtool_attached_; OnBeforeMenuEvent cb_before_menu_ = nullptr; OnMenuCommandEvent cb_menu_command_ = nullptr; OnTitleChangeEvent cb_title_change_ = nullptr; OnBeforeResourceLoadEvent cb_before_resource_load_ = nullptr; OnUrlChangeEvent cb_url_change_ = nullptr; OnMainURLChengeEvent cb_main_url_change_ = nullptr; OnLinkClickEvent cb_link_click_ = nullptr; OnLoadingStateChangeEvent cb_loadstate_change_ = nullptr; OnLoadStartEvent cb_load_start_ = nullptr; OnLoadEndEvent cb_load_end_ = nullptr; OnLoadErrorEvent cb_load_error_ = nullptr; OnAfterCreatedEvent cb_after_created_ = nullptr; OnBeforeCloseEvent cb_before_close_ = nullptr; OnBeforeBrowserEvent cb_before_browser_ = nullptr; OnProtocolExecutionEvent cb_protocol_execution_ = nullptr; OnBeforeDownloadEvent cb_before_download_ = nullptr; OnDownloadUpdatedEvent cb_download_updated_ = nullptr; OnFileDialogEvent cb_file_dialog_ = nullptr; OnDevToolAttachedStateChangeEvent cb_devtool_visible_change_ = nullptr; int js_callback_thread_id_ = -1; // 保存接收到 JS 调用 CPP 函数的代码所属线程,以后触发 JS 回调时把回调转到那个线程 }; }