#include "client.h" #include #include "include/base/cef_bind.h" #include "include/base/cef_callback.h" #include "include/cef_browser.h" #include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" WefClient::WefClient(std::shared_ptr state) : state_(state) {} WefClient::~WefClient() { if (state_->browser) { (*state_->browser)->GetHost()->CloseBrowser(true); } } ///////////////////////////////////////////////////////////////// // CefRenderHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnPopupShow(CefRefPtr browser, bool show) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_popup_show(userdata, show); }); } void WefClient::OnPopupSize(CefRefPtr browser, const CefRect& rect) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_popup_position(userdata, &rect); }); } void WefClient::OnPaint(CefRefPtr browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_paint(userdata, static_cast(type), &dirtyRects, buffer, static_cast(width), static_cast(height)); }); } void WefClient::OnImeCompositionRangeChanged(CefRefPtr browser, const CefRange& selected_range, const RectList& character_bounds) { DCHECK(CefCurrentlyOn(TID_UI)); 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))}; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_ime_composition_range_changed(userdata, &rect); }); } bool WefClient::OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, cef_cursor_type_t type, const CefCursorInfo& custom_cursor_info) { DCHECK(CefCurrentlyOn(TID_UI)); bool result = false; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { result = callbacks.on_cursor_changed( userdata, static_cast(type), type == CT_CUSTOM ? &custom_cursor_info : nullptr); }); return result; } ///////////////////////////////////////////////////////////////// // CefDisplayHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) { DCHECK(CefCurrentlyOn(TID_UI)); auto url_str = url.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_address_changed(userdata, new WefFrame{frame}, url_str.c_str()); }); } void WefClient::OnTitleChange(CefRefPtr browser, const CefString& title) { DCHECK(CefCurrentlyOn(TID_UI)); auto title_str = title.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_title_changed(userdata, title_str.c_str()); }); } void WefClient::OnFaviconURLChange(CefRefPtr browser, const std::vector& icon_urls) { DCHECK(CefCurrentlyOn(TID_UI)); 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(); }); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_favicon_url_change(userdata, cstr_urls.data(), static_cast(cstr_urls.size())); }); } bool WefClient::OnTooltip(CefRefPtr browser, CefString& text) { DCHECK(CefCurrentlyOn(TID_UI)); auto text_str = text.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_tooltip(userdata, text_str.c_str()); }); return true; } void WefClient::OnStatusMessage(CefRefPtr browser, const CefString& value) { DCHECK(CefCurrentlyOn(TID_UI)); auto text_str = value.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_status_message(userdata, text_str.c_str()); }); } bool WefClient::OnConsoleMessage(CefRefPtr browser, cef_log_severity_t level, const CefString& message, const CefString& source, int line) { DCHECK(CefCurrentlyOn(TID_UI)); auto message_str = message.ToString(); auto source_str = source.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_console_message(userdata, message_str.c_str(), static_cast(level), source_str.c_str(), line); }); return false; } void WefClient::OnLoadingProgressChange(CefRefPtr browser, double progress) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_loading_progress_changed(userdata, static_cast(progress)); }); } ///////////////////////////////////////////////////////////////// // CefLifeSpanHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnAfterCreated(CefRefPtr browser) { CefMessageRouterConfig config; message_router_ = CefMessageRouterBrowserSide::Create(config); message_router_->AddHandler(this, false); state_->browser = browser; state_->browser_state = BrowserState::Created; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_created(userdata); }); if (state_->browser_state == BrowserState::Closed) { CefPostTask(TID_UI, base::BindOnce(&CefBrowserHost::CloseBrowser, browser->GetHost(), false)); } } bool WefClient::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) { DCHECK(CefCurrentlyOn(TID_UI)); auto target_url_str = target_url.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_before_popup(userdata, target_url_str.c_str()); }); return true; } bool WefClient::DoClose(CefRefPtr browser) { return false; } void WefClient::OnBeforeClose(CefRefPtr browser) { DCHECK(CefCurrentlyOn(TID_UI)); message_router_->OnBeforeClose(browser); state_->browser_state = BrowserState::Closed; state_->browser = std::nullopt; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_closed(userdata); }); } ///////////////////////////////////////////////////////////////// // CefLoadHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnLoadingStateChange(CefRefPtr browser, bool isLoading, bool canGoBack, bool canGoForward) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_loading_state_changed(userdata, isLoading, canGoBack, canGoForward); }); } void WefClient::OnLoadStart(CefRefPtr browser, CefRefPtr frame, TransitionType transition_type) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_load_start(userdata, new WefFrame{frame}); }); } void WefClient::OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_load_end(userdata, new WefFrame{frame}); }); if (state_->browser) { (*state_->browser)->GetHost()->SetFocus(state_->focus); } } void WefClient::OnLoadError(CefRefPtr browser, CefRefPtr frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) { DCHECK(CefCurrentlyOn(TID_UI)); auto error_text_str = errorText.ToString(); auto failed_url_str = failedUrl.ToString(); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_load_error(userdata, new WefFrame{frame}, error_text_str.c_str(), failed_url_str.c_str()); }); } ///////////////////////////////////////////////////////////////// // CefDialogHandler methods ///////////////////////////////////////////////////////////////// bool WefClient::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) { DCHECK(CefCurrentlyOn(TID_UI)); 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); bool result = false; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { result = 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); }); return result; } ///////////////////////////////////////////////////////////////// // CefContextMenuHandler methods ///////////////////////////////////////////////////////////////// bool WefClient::RunContextMenu(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, CefRefPtr model, CefRefPtr callback) { DCHECK(CefCurrentlyOn(TID_UI)); 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()), }; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_context_menu(userdata, new WefFrame{frame}, ¶ms_); }); return true; } ///////////////////////////////////////////////////////////////// // CefFindHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnFindResult(CefRefPtr browser, int identifier, int count, const CefRect& selectionRect, int activeMatchOrdinal, bool finalUpdate) { DCHECK(CefCurrentlyOn(TID_UI)); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { callbacks.on_find_result(userdata, identifier, count, &selectionRect, activeMatchOrdinal, finalUpdate); }); } ///////////////////////////////////////////////////////////////// // CefJSDialogHandler methods ///////////////////////////////////////////////////////////////// bool WefClient::OnJSDialog(CefRefPtr browser, const CefString& origin_url, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr callback, bool& suppress_message) { DCHECK(CefCurrentlyOn(TID_UI)); auto message_text_str = message_text.ToString(); auto default_prompt_text_str = default_prompt_text.ToString(); CefRefPtr* callback_ptr = new CefRefPtr(callback); bool result = false; state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { result = callbacks.on_js_dialog( userdata, static_cast(dialog_type), message_text_str.c_str(), default_prompt_text_str.c_str(), callback_ptr); }); return result; } bool WefClient::OnBeforeUnloadDialog(CefRefPtr browser, const CefString& message_text, bool is_reload, CefRefPtr callback) { callback->Continue(true, ""); return true; } ///////////////////////////////////////////////////////////////// // CefRequestHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status, int error_code, const CefString& error_string) { message_router_->OnRenderProcessTerminated(browser); } bool WefClient::OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool user_gesture, bool is_redirect) { message_router_->OnBeforeBrowse(browser, frame); return false; } ///////////////////////////////////////////////////////////////// // CefFocusHandler methods ///////////////////////////////////////////////////////////////// void WefClient::OnTakeFocus(CefRefPtr browser, bool next) {} bool WefClient::OnSetFocus(CefRefPtr browser, FocusSource source) { return false; } ///////////////////////////////////////////////////////////////// // CefPermissionHandler methods ///////////////////////////////////////////////////////////////// bool WefClient::OnRequestMediaAccessPermission( CefRefPtr browser, CefRefPtr frame, const CefString& requesting_origin, uint32_t requested_permissions, CefRefPtr callback) { callback->Continue(CEF_MEDIA_PERMISSION_NONE); return true; } ///////////////////////////////////////////////////////////////// // CefMessageRouterBrowserSide::Handler methods ///////////////////////////////////////////////////////////////// bool WefClient::OnQuery( CefRefPtr browser, CefRefPtr frame, int64_t query_id, const CefString& request, bool persistent, CefRefPtr callback) { DCHECK(CefCurrentlyOn(TID_UI)); auto request_str = request.ToString(); CefRefPtr* callback_ptr = new CefRefPtr(callback); state_->callbacks_target.call( [&](const BrowserCallbacks& callbacks, void* userdata) { return callbacks.on_query(userdata, new WefFrame{frame}, request_str.c_str(), callback_ptr); }); return true; }