#pragma once #include #include #include "browser_callbacks.h" #include "frame.h" #include "include/cef_browser.h" #include "include/cef_client.h" #include "include/wrapper/cef_message_router.h" #include "utils.h" struct WefBrowser; class WefClient : public CefClient, public CefRenderHandler, public CefDisplayHandler, public CefLifeSpanHandler, public CefLoadHandler, public CefDialogHandler, public CefFindHandler, public CefContextMenuHandler, public CefRequestHandler, public CefJSDialogHandler, public CefFocusHandler, public CefPermissionHandler, public CefMessageRouterBrowserSide::Handler { IMPLEMENT_REFCOUNTING(WefClient); private: WefBrowser* wef_browser_; int width_, height_; float device_scale_factor_; BrowserCallbacks callbacks_; void* userdata_; DestroyFn destroy_userdata_; CefRefPtr message_router_; public: WefClient(WefBrowser* wef_browser, float device_scale_factor, int width, int height, BrowserCallbacks callbacks, void* userdata, DestroyFn destroy_userdata); virtual ~WefClient(); bool setSize(int width, int height) { if (width_ == width && height_ == height) { return false; } width_ = width; height_ = height; return true; } ///////////////////////////////////////////////////////////////// // CefClient methods ///////////////////////////////////////////////////////////////// bool GetScreenInfo(CefRefPtr browser, CefScreenInfo& screen_info) override { screen_info.device_scale_factor = device_scale_factor_; return true; } void GetViewRect(CefRefPtr browser, CefRect& rect) override { rect.Set( 0, 0, static_cast(static_cast(width_) / device_scale_factor_), static_cast(static_cast(height_) / device_scale_factor_)); } CefRefPtr GetRenderHandler() override { return this; } CefRefPtr GetDisplayHandler() override { return this; } CefRefPtr GetLifeSpanHandler() override { return this; } CefRefPtr GetLoadHandler() override { return this; } CefRefPtr GetDialogHandler() override { return this; } CefRefPtr GetContextMenuHandler() override { return this; } CefRefPtr GetFindHandler() override { return this; } CefRefPtr GetJSDialogHandler() override { return this; } CefRefPtr GetFocusHandler() override { return this; } CefRefPtr GetPermissionHandler() override { return this; } bool OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) override { return message_router_->OnProcessMessageReceived(browser, frame, source_process, message); } ///////////////////////////////////////////////////////////////// // CefRenderHandler methods ///////////////////////////////////////////////////////////////// void OnPopupShow(CefRefPtr browser, bool show) override { callbacks_.on_popup_show(userdata_, show); } void OnPopupSize(CefRefPtr browser, const CefRect& rect) override { callbacks_.on_popup_position(userdata_, &rect); } void OnPaint(CefRefPtr browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) override { callbacks_.on_paint(userdata_, static_cast(type), &dirtyRects, buffer, static_cast(width), static_cast(height)); } void OnImeCompositionRangeChanged(CefRefPtr browser, const CefRange& selected_range, const RectList& character_bounds) override { int xmin = std::numeric_limits::max(); int ymin = std::numeric_limits::max(); int xmax = std::numeric_limits::min(); int ymax = std::numeric_limits::min(); for (const auto& r : character_bounds) { if (r.x < xmin) { xmin = r.x; } if (r.y < ymin) { ymin = r.y; } if (r.x + r.width > xmax) { xmax = r.x + r.width; } if (r.y + r.height > ymax) { ymax = r.y + r.height; } } CefRect rect{int(float(xmin)), int(float(ymin)), int(float(xmax - xmin)), int(float(ymax - ymin))}; callbacks_.on_ime_composition_range_changed(userdata_, &rect); } bool OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, cef_cursor_type_t type, const CefCursorInfo& custom_cursor_info) override { return callbacks_.on_cursor_changed( userdata_, static_cast(type), type == CT_CUSTOM ? &custom_cursor_info : nullptr); } ///////////////////////////////////////////////////////////////// // CefDisplayHandler methods ///////////////////////////////////////////////////////////////// void OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) override { auto url_str = url.ToString(); callbacks_.on_address_changed(userdata_, new WefFrame{frame}, url_str.c_str()); } void OnTitleChange(CefRefPtr browser, const CefString& title) override { auto title_str = title.ToString(); callbacks_.on_title_changed(userdata_, title_str.c_str()); } virtual void OnFaviconURLChange(CefRefPtr browser, const std::vector& icon_urls) { std::vector str_urls; std::transform(icon_urls.begin(), icon_urls.end(), std::back_inserter(str_urls), [](const CefString& url) { return url.ToString(); }); std::vector cstr_urls; std::transform(str_urls.begin(), str_urls.end(), std::back_inserter(cstr_urls), [](const std::string& url) { return url.c_str(); }); callbacks_.on_favicon_url_change(userdata_, cstr_urls.data(), static_cast(cstr_urls.size())); } bool OnTooltip(CefRefPtr browser, CefString& text) override { auto text_str = text.ToString(); callbacks_.on_tooltip(userdata_, text_str.c_str()); return false; } void OnStatusMessage(CefRefPtr browser, const CefString& value) override { auto text_str = value.ToString(); callbacks_.on_status_message(userdata_, text_str.c_str()); } bool OnConsoleMessage(CefRefPtr browser, cef_log_severity_t level, const CefString& message, const CefString& source, int line) override { auto message_str = message.ToString(); auto source_str = source.ToString(); callbacks_.on_console_message(userdata_, message_str.c_str(), static_cast(level), source_str.c_str(), line); return false; } void OnLoadingProgressChange(CefRefPtr browser, double progress) override { callbacks_.on_loading_progress_changed(userdata_, static_cast(progress)); } ///////////////////////////////////////////////////////////////// // CefLifeSpanHandler methods ///////////////////////////////////////////////////////////////// void OnAfterCreated(CefRefPtr browser) override; bool OnBeforePopup( CefRefPtr browser, CefRefPtr frame, int popup_id, 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, CefRefPtr& extra_info, bool* no_javascript_access) override { auto target_url_str = target_url.ToString(); callbacks_.on_before_popup(userdata_, target_url_str.c_str()); return true; } bool DoClose(CefRefPtr browser) override { return false; } void OnBeforeClose(CefRefPtr browser) override; ///////////////////////////////////////////////////////////////// // CefLoadHandler methods ///////////////////////////////////////////////////////////////// void OnLoadingStateChange(CefRefPtr browser, bool isLoading, bool canGoBack, bool canGoForward) override { callbacks_.on_loading_state_changed(userdata_, isLoading, canGoBack, canGoForward); } void OnLoadStart(CefRefPtr browser, CefRefPtr frame, TransitionType transition_type) override { callbacks_.on_load_start(userdata_, new WefFrame{frame}); } void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) override; void OnLoadError(CefRefPtr browser, CefRefPtr frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) override { auto error_text_str = errorText.ToString(); auto failed_url_str = failedUrl.ToString(); callbacks_.on_load_error(userdata_, new WefFrame{frame}, error_text_str.c_str(), failed_url_str.c_str()); } ///////////////////////////////////////////////////////////////// // CefDialogHandler methods ///////////////////////////////////////////////////////////////// bool OnFileDialog(CefRefPtr browser, FileDialogMode mode, const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, const std::vector& accept_extensions, const std::vector& accept_descriptions, CefRefPtr callback) override { auto title_str = title.ToString(); auto default_file_path_str = default_file_path.ToString(); auto accept_filters_str = join_strings(accept_filters, "@@@"); auto accept_extensions_str = join_strings(accept_extensions, "@@@"); auto accept_descriptions_str = join_strings(accept_descriptions, "@@@"); CefRefPtr* callback_ptr = new CefRefPtr(callback); return callbacks_.on_file_dialog( userdata_, static_cast(mode), title_str.c_str(), default_file_path_str.c_str(), accept_filters_str.c_str(), accept_extensions_str.c_str(), accept_descriptions_str.c_str(), callback_ptr); } ///////////////////////////////////////////////////////////////// // CefContextMenuHandler methods ///////////////////////////////////////////////////////////////// bool RunContextMenu(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, CefRefPtr model, CefRefPtr callback) override { auto link_url_str = params->GetLinkUrl().ToString(); auto unfiltered_link_url_str = params->GetUnfilteredLinkUrl().ToString(); auto source_url_str = params->GetSourceUrl().ToString(); auto title_text_str = params->GetTitleText().ToString(); auto page_url_str = params->GetPageUrl().ToString(); auto frame_url_str = params->GetFrameUrl().ToString(); auto selection_text_str = params->GetSelectionText().ToString(); _ContextMenuParams params_{ params->GetXCoord(), params->GetYCoord(), static_cast(params->GetTypeFlags()), !link_url_str.empty() ? link_url_str.c_str() : nullptr, !unfiltered_link_url_str.empty() ? unfiltered_link_url_str.c_str() : nullptr, !source_url_str.empty() ? source_url_str.c_str() : nullptr, params->HasImageContents(), !title_text_str.empty() ? title_text_str.c_str() : nullptr, page_url_str.c_str(), frame_url_str.c_str(), static_cast(params->GetMediaType()), static_cast(params->GetMediaStateFlags()), selection_text_str.c_str(), params->IsEditable(), static_cast(params->GetEditStateFlags()), }; callbacks_.on_context_menu(userdata_, new WefFrame{frame}, ¶ms_); return true; } ///////////////////////////////////////////////////////////////// // CefFindHandler methods ///////////////////////////////////////////////////////////////// void OnFindResult(CefRefPtr browser, int identifier, int count, const CefRect& selectionRect, int activeMatchOrdinal, bool finalUpdate) override { callbacks_.on_find_result(userdata_, identifier, count, &selectionRect, activeMatchOrdinal, finalUpdate); } ///////////////////////////////////////////////////////////////// // CefJSDialogHandler methods ///////////////////////////////////////////////////////////////// bool OnJSDialog(CefRefPtr browser, const CefString& origin_url, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr callback, bool& suppress_message) override { auto message_text_str = message_text.ToString(); auto default_prompt_text_str = default_prompt_text.ToString(); CefRefPtr* callback_ptr = new CefRefPtr(callback); return callbacks_.on_js_dialog( userdata_, static_cast(dialog_type), message_text_str.c_str(), default_prompt_text_str.c_str(), callback_ptr); } bool OnBeforeUnloadDialog(CefRefPtr browser, const CefString& message_text, bool is_reload, CefRefPtr callback) override { callback->Continue(true, ""); return true; } ///////////////////////////////////////////////////////////////// // CefRequestHandler methods ///////////////////////////////////////////////////////////////// void OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status, int error_code, const CefString& error_string) override { message_router_->OnRenderProcessTerminated(browser); } bool OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool user_gesture, bool is_redirect) override { message_router_->OnBeforeBrowse(browser, frame); return false; } ///////////////////////////////////////////////////////////////// // CefFocusHandler methods ///////////////////////////////////////////////////////////////// void OnTakeFocus(CefRefPtr browser, bool next) override {} bool OnSetFocus(CefRefPtr browser, FocusSource source) override { return false; } ///////////////////////////////////////////////////////////////// // CefPermissionHandler methods ///////////////////////////////////////////////////////////////// bool OnRequestMediaAccessPermission( CefRefPtr browser, CefRefPtr frame, const CefString& requesting_origin, uint32_t requested_permissions, CefRefPtr callback) override { callback->Continue(CEF_MEDIA_PERMISSION_NONE); return true; } ///////////////////////////////////////////////////////////////// // CefMessageRouterBrowserSide::Handler methods ///////////////////////////////////////////////////////////////// bool OnQuery(CefRefPtr browser, CefRefPtr frame, int64_t query_id, const CefString& request, bool persistent, CefRefPtr callback) override { auto request_str = request.ToString(); CefRefPtr* callback_ptr = new CefRefPtr(callback); callbacks_.on_query(userdata_, new WefFrame{frame}, request_str.c_str(), callback_ptr); return true; } };