477 lines
14 KiB
C++
477 lines
14 KiB
C++
#include "stdafx.h"
|
||
#include "browser_handler.h"
|
||
#include "include/cef_frame.h"
|
||
#include "cef_control/manager/cef_manager.h"
|
||
#include "cef_control/util/util.h"
|
||
#include "cef_control/app/ipc_string_define.h"
|
||
#include "cef_control/app/cef_js_bridge.h"
|
||
|
||
namespace nim_comp
|
||
{
|
||
BrowserHandler::BrowserHandler()
|
||
{
|
||
handle_delegate_ = NULL;
|
||
is_focus_oneditable_field_ = false;
|
||
ZeroMemory(&rect_cef_control_, sizeof(RECT));
|
||
}
|
||
|
||
void BrowserHandler::SetViewRect(RECT rc)
|
||
{
|
||
if (!CefCurrentlyOn(TID_UI)) {
|
||
// 把操作跳转到Cef线程执行
|
||
CefPostTask(TID_UI, base::Bind(&BrowserHandler::SetViewRect, this, rc));
|
||
return;
|
||
}
|
||
|
||
rect_cef_control_ = rc;
|
||
// 调用WasResized接口,调用后,BrowserHandler会调用GetViewRect接口来获取浏览器对象新的位置
|
||
if (browser_.get() && browser_->GetHost().get())
|
||
browser_->GetHost()->WasResized();
|
||
}
|
||
|
||
CefRefPtr<CefBrowserHost> BrowserHandler::GetBrowserHost()
|
||
{
|
||
if (browser_.get())
|
||
{
|
||
return browser_->GetHost();
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
UnregisterCallback BrowserHandler::AddAfterCreateTask(const StdClosure& cb)
|
||
{
|
||
return task_list_after_created_.AddCallback(cb);
|
||
}
|
||
|
||
void BrowserHandler::CloseAllBrowser()
|
||
{
|
||
class CloseAllBrowserTask : public CefTask
|
||
{
|
||
IMPLEMENT_REFCOUNTING(CloseAllBrowserTask);
|
||
public:
|
||
CloseAllBrowserTask(const std::vector<CefRefPtr<CefBrowser>>& browser_list)
|
||
{
|
||
browser_list_.assign(browser_list.begin(), browser_list.end());
|
||
}
|
||
public:
|
||
void Execute()
|
||
{
|
||
for (auto it : browser_list_)
|
||
{
|
||
if (it != nullptr)
|
||
it->GetHost()->CloseBrowser(true);
|
||
}
|
||
}
|
||
private:
|
||
std::vector<CefRefPtr<CefBrowser>> browser_list_;
|
||
};
|
||
CefPostTask(TID_UI, new CloseAllBrowserTask(browser_list_));
|
||
}
|
||
|
||
bool BrowserHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)
|
||
{
|
||
// 处理render进程发来的消息
|
||
std::string message_name = message->GetName();
|
||
if (message_name == kFocusedNodeChangedMessage)
|
||
{
|
||
is_focus_oneditable_field_ = message->GetArgumentList()->GetBool(0);
|
||
return true;
|
||
}
|
||
else if (message_name == kCallCppFunctionMessage)
|
||
{
|
||
CefString fun_name = message->GetArgumentList()->GetString(0);
|
||
CefString param = message->GetArgumentList()->GetString(1);
|
||
int js_callback_id = message->GetArgumentList()->GetInt(2);
|
||
|
||
if (handle_delegate_)
|
||
handle_delegate_->OnExecuteCppFunc(fun_name, param, js_callback_id, browser);
|
||
|
||
return true;
|
||
}
|
||
else if (message_name == kExecuteCppCallbackMessage)
|
||
{
|
||
CefString param = message->GetArgumentList()->GetString(0);
|
||
int callback_id = message->GetArgumentList()->GetInt(1);
|
||
|
||
if (handle_delegate_)
|
||
handle_delegate_->OnExecuteCppCallbackFunc(callback_id, param);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#pragma region CefLifeSpanHandler
|
||
// CefLifeSpanHandler methods
|
||
bool BrowserHandler::OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||
CefRefPtr<CefFrame> frame,
|
||
const CefString& target_url,
|
||
const CefString& target_frame_name,
|
||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||
bool user_gesture,
|
||
const CefPopupFeatures& popupFeatures,
|
||
CefWindowInfo& windowInfo,
|
||
CefRefPtr<CefClient>& client,
|
||
CefBrowserSettings& settings,
|
||
bool* no_javascript_access)
|
||
{
|
||
// 让新的链接在原浏览器对象中打开
|
||
if (browser_.get() && !target_url.empty())
|
||
{
|
||
if (handle_delegate_)
|
||
{
|
||
// 返回true则继续在控件内打开新链接,false则禁止访问
|
||
bool bRet = handle_delegate_->OnBeforePopup(browser, frame, target_url, target_frame_name, target_disposition, user_gesture, popupFeatures, windowInfo, client, settings, no_javascript_access);
|
||
if (bRet)
|
||
browser_->GetMainFrame()->LoadURL(target_url);
|
||
}
|
||
else
|
||
browser_->GetMainFrame()->LoadURL(target_url);
|
||
}
|
||
|
||
// 禁止弹出popup窗口
|
||
return true;
|
||
}
|
||
|
||
void BrowserHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
|
||
{
|
||
REQUIRE_UI_THREAD();
|
||
nbase::ThreadManager::PostTask(kThreadUI, ToWeakCallback([this, browser](){
|
||
browser_list_.emplace_back(browser);
|
||
if (browser_ != nullptr)
|
||
browser_->GetHost()->WasHidden(true);
|
||
browser_ = browser;
|
||
CefManager::GetInstance()->AddBrowserCount();
|
||
|
||
if (handle_delegate_)
|
||
{
|
||
handle_delegate_->OnAfterCreated(browser);
|
||
}
|
||
|
||
// 有窗模式下,浏览器创建完毕后,让上层更新一下自己的位置;因为在异步状态下,上层更新位置时可能Cef窗口还没有创建出来
|
||
if (!CefManager::GetInstance()->IsEnableOffsetRender() && handle_delegate_)
|
||
{
|
||
handle_delegate_->UpdateWindowPos();
|
||
}
|
||
|
||
task_list_after_created_();
|
||
task_list_after_created_.Clear();
|
||
}));
|
||
|
||
}
|
||
|
||
bool BrowserHandler::DoClose(CefRefPtr<CefBrowser> browser)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
void BrowserHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
|
||
{
|
||
REQUIRE_UI_THREAD();
|
||
nbase::ThreadManager::PostTask(kThreadUI, ToWeakCallback([this, browser](){
|
||
CefManager::GetInstance()->SubBrowserCount();
|
||
auto it = std::find_if(browser_list_.begin(), browser_list_.end(), [&](const CefRefPtr<CefBrowser>& item){
|
||
return item->IsSame(browser);
|
||
});
|
||
if (it != browser_list_.end())
|
||
{
|
||
auto closed_browser = *it;
|
||
browser_list_.erase(it);
|
||
if (closed_browser->IsSame(browser_))
|
||
{
|
||
browser_ = browser_list_.size() > 0 ? *browser_list_.rbegin() : nullptr;
|
||
if (browser_ != nullptr)
|
||
{
|
||
browser_->GetHost()->WasHidden(false);
|
||
browser_->Reload();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (handle_delegate_)
|
||
{
|
||
handle_delegate_->OnBeforeClose(browser);
|
||
}
|
||
}));
|
||
}
|
||
#pragma endregion
|
||
|
||
#pragma region CefRenderHandler
|
||
// CefRenderHandler methods
|
||
bool BrowserHandler::GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect)
|
||
{
|
||
RECT window_rect = { 0 };
|
||
HWND root_window = GetAncestor(hwnd_, GA_ROOT);
|
||
if (::GetWindowRect(root_window, &window_rect))
|
||
{
|
||
rect = CefRect(window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool BrowserHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect)
|
||
{
|
||
if (handle_delegate_)
|
||
{
|
||
rect.x = 0;
|
||
rect.y = 0;
|
||
rect.width = rect_cef_control_.right - rect_cef_control_.left;
|
||
rect.height = rect_cef_control_.bottom - rect_cef_control_.top;
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
RECT clientRect;
|
||
if (!::GetClientRect(hwnd_, &clientRect))
|
||
return false;
|
||
rect.x = rect.y = 0;
|
||
rect.width = clientRect.right;
|
||
rect.height = clientRect.bottom;
|
||
return true;
|
||
}
|
||
|
||
}
|
||
|
||
bool BrowserHandler::GetScreenPoint(CefRefPtr<CefBrowser> browser, int viewX, int viewY, int& screenX, int& screenY)
|
||
{
|
||
if (!::IsWindow(hwnd_))
|
||
return false;
|
||
|
||
// Convert the point from view coordinates to actual screen coordinates.
|
||
POINT screen_pt = { viewX, viewY };
|
||
ClientToScreen(hwnd_, &screen_pt);
|
||
screenX = screen_pt.x;
|
||
screenY = screen_pt.y;
|
||
return true;
|
||
}
|
||
|
||
void BrowserHandler::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show)
|
||
{
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnPopupShow, handle_delegate_, browser, show));
|
||
}
|
||
|
||
void BrowserHandler::OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect)
|
||
{
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnPopupSize, handle_delegate_, browser, rect));
|
||
}
|
||
|
||
void BrowserHandler::OnPaint(CefRefPtr<CefBrowser> browser,
|
||
PaintElementType type,
|
||
const RectList& dirtyRects,
|
||
const void* buffer,
|
||
int width,
|
||
int height)
|
||
{
|
||
if (handle_delegate_)
|
||
{
|
||
// 多线程消息循环模式中,OnPaint在Cef的线程被触发,这时把数据保存到paint_buffer_中,跳转到UI线程执行渲染操作。
|
||
// 这里不对paint_buffer_加锁,即使两个线程操作paint_buffer_发生竞争,也只是让某一次渲染效果有瑕疵,不会崩溃,这个瑕疵是可以接受的
|
||
int buffer_length = width * height * 4;
|
||
if (buffer_length > (int)paint_buffer_.size())
|
||
paint_buffer_.resize(buffer_length + 1);
|
||
memcpy(&paint_buffer_[0], (char*)buffer, width * height * 4);
|
||
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnPaint, handle_delegate_, browser, type, dirtyRects, &paint_buffer_, width, height));
|
||
}
|
||
}
|
||
|
||
void BrowserHandler::OnCursorChange(CefRefPtr<CefBrowser> browser, CefCursorHandle cursor, CursorType type, const CefCursorInfo& custom_cursor_info)
|
||
{
|
||
SetClassLongPtr(hwnd_, GCLP_HCURSOR, static_cast<LONG>(reinterpret_cast<LONG_PTR>(cursor)));
|
||
SetCursor(cursor);
|
||
}
|
||
#pragma endregion
|
||
|
||
#pragma region CefContextMenuHandler
|
||
// CefContextMenuHandler methods
|
||
void BrowserHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
|
||
CefRefPtr<CefFrame> frame,
|
||
CefRefPtr<CefContextMenuParams> params,
|
||
CefRefPtr<CefMenuModel> model)
|
||
{
|
||
REQUIRE_UI_THREAD();
|
||
|
||
if (handle_delegate_)
|
||
{
|
||
handle_delegate_->OnBeforeContextMenu(browser, frame, params, model);
|
||
}
|
||
else
|
||
{
|
||
// Customize the context menu...
|
||
if ((params->GetTypeFlags() & (CM_TYPEFLAG_PAGE | CM_TYPEFLAG_FRAME)) != 0)
|
||
{
|
||
if (model->GetCount() > 0)
|
||
{
|
||
// 禁止右键菜单
|
||
model->Clear();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
bool BrowserHandler::RunContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model, CefRefPtr<CefRunContextMenuCallback> callback)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
bool BrowserHandler::OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags)
|
||
{
|
||
if (handle_delegate_)
|
||
return handle_delegate_->OnContextMenuCommand(browser, frame, params, command_id, event_flags);
|
||
else
|
||
return false;
|
||
}
|
||
|
||
void BrowserHandler::OnContextMenuDismissed(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame)
|
||
{
|
||
|
||
}
|
||
|
||
#pragma endregion
|
||
|
||
#pragma region CefDisplayHandler
|
||
|
||
// CefDisplayHandler methods
|
||
void BrowserHandler::OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url)
|
||
{
|
||
// Update the URL in the address bar...
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnAddressChange, handle_delegate_, browser, frame, url));
|
||
}
|
||
|
||
void BrowserHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title)
|
||
{
|
||
// Update the browser window title...
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnTitleChange, handle_delegate_, browser, title));
|
||
}
|
||
|
||
bool BrowserHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser, const CefString& message, const CefString& source, int line)
|
||
{
|
||
// Log a console message...
|
||
return true;
|
||
}
|
||
#pragma endregion
|
||
|
||
// CefLoadHandler methods
|
||
void BrowserHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser, bool isLoading, bool canGoBack, bool canGoForward)
|
||
{
|
||
// Update UI for browser state...
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnLoadingStateChange, handle_delegate_, browser, isLoading, canGoBack, canGoForward));
|
||
}
|
||
|
||
void BrowserHandler::OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame)
|
||
{
|
||
// A frame has started loading content...
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnLoadStart, handle_delegate_, browser, frame));
|
||
}
|
||
|
||
void BrowserHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode)
|
||
{
|
||
// A frame has finished loading content...
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnLoadEnd, handle_delegate_, browser, frame, httpStatusCode));
|
||
}
|
||
|
||
void BrowserHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl)
|
||
{
|
||
// A frame has failed to load content...
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnLoadError, handle_delegate_, browser, frame, errorCode, errorText, failedUrl));
|
||
}
|
||
|
||
bool BrowserHandler::OnJSDialog(CefRefPtr<CefBrowser> browser, const CefString& origin_url, const CefString& accept_lang, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr<CefJSDialogCallback> callback, bool& suppress_message)
|
||
{
|
||
// release时阻止弹出js对话框
|
||
#ifndef _DEBUG
|
||
suppress_message = true;
|
||
#endif
|
||
|
||
return false;
|
||
}
|
||
|
||
// CefRequestHandler methods
|
||
bool BrowserHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool is_redirect)
|
||
{
|
||
if (handle_delegate_)
|
||
return handle_delegate_->OnBeforeBrowse(browser, frame, request, is_redirect);
|
||
|
||
return false;
|
||
}
|
||
|
||
void BrowserHandler::OnProtocolExecution(CefRefPtr<CefBrowser> browser, const CefString& url, bool& allow_os_execution)
|
||
{
|
||
if (handle_delegate_)
|
||
handle_delegate_->OnProtocolExecution(browser, url, allow_os_execution);
|
||
}
|
||
|
||
CefRequestHandler::ReturnValue BrowserHandler::OnBeforeResourceLoad(
|
||
CefRefPtr<CefBrowser> browser,
|
||
CefRefPtr<CefFrame> frame,
|
||
CefRefPtr<CefRequest> request,
|
||
CefRefPtr<CefRequestCallback> callback)
|
||
{
|
||
if (handle_delegate_)
|
||
return handle_delegate_->OnBeforeResourceLoad(browser, frame, request, callback);
|
||
|
||
return RV_CONTINUE;
|
||
}
|
||
|
||
void BrowserHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, TerminationStatus status)
|
||
{
|
||
if (handle_delegate_)
|
||
nbase::ThreadManager::PostTask(kThreadUI, nbase::Bind(&HandlerDelegate::OnRenderProcessTerminated, handle_delegate_, browser, status));
|
||
|
||
}
|
||
|
||
bool BrowserHandler::OnQuotaRequest(CefRefPtr<CefBrowser> browser,
|
||
const CefString& origin_url,
|
||
int64 new_size,
|
||
CefRefPtr<CefRequestCallback> callback)
|
||
{
|
||
static const int64 max_size = 1024 * 1024 * 20; // 20mb.
|
||
|
||
// Grant the quota request if the size is reasonable.
|
||
callback->Continue(new_size <= max_size);
|
||
return true;
|
||
}
|
||
|
||
void BrowserHandler::OnBeforeDownload(
|
||
CefRefPtr<CefBrowser> browser,
|
||
CefRefPtr<CefDownloadItem> download_item,
|
||
const CefString& suggested_name,
|
||
CefRefPtr<CefBeforeDownloadCallback> callback)
|
||
{
|
||
if (handle_delegate_)
|
||
handle_delegate_->OnBeforeDownload(browser, download_item, suggested_name, callback);
|
||
}
|
||
|
||
void BrowserHandler::OnDownloadUpdated(
|
||
CefRefPtr<CefBrowser> browser,
|
||
CefRefPtr<CefDownloadItem> download_item,
|
||
CefRefPtr<CefDownloadItemCallback> callback)
|
||
{
|
||
if (handle_delegate_)
|
||
handle_delegate_->OnDownloadUpdated(browser, download_item, callback);
|
||
}
|
||
|
||
bool BrowserHandler::OnFileDialog(
|
||
CefRefPtr<CefBrowser> browser,
|
||
FileDialogMode mode,
|
||
const CefString& title,
|
||
const CefString& default_file_path,
|
||
const std::vector<CefString>& accept_filters,
|
||
int selected_accept_filter,
|
||
CefRefPtr<CefFileDialogCallback> callback)
|
||
{
|
||
if (handle_delegate_)
|
||
return handle_delegate_->OnFileDialog(browser, mode, title, default_file_path, accept_filters, selected_accept_filter, callback);
|
||
else
|
||
return false;
|
||
}
|
||
|
||
} |