最近做了cef的离屏渲染,从未接触cef到做完这个功能,将近2周时间,遇到的坑mark一下,防止后人踩坑
有关cef的搭建可以看我这篇帖子: windows下CEF3 搭建
注意:离屏渲染对编程人员的GDI的基础颇有要求,如果你不熟悉GDI等需要去补习一下此类知识点,网上能找到离屏渲染的能用的资料很少,你也可以问我要一份写好的
官网的例子渲染使用OpenGL,我是用GDI实现,倒并不是觉得官方的不行,只是官方的写的看起来费劲,毕竟老外的编程思维真是很难看懂,就干脆自己实现了一份
离屏渲染的性能还是没有原窗口的好,所以万不得已还是别用这个方式,在编写渲染代码的时候,也要注意性能上的优化否则你的画面会变的卡卡的,尤其是如果你还需要视频播放的时候
1.CreateMutexA 不兼容,如果你用CreateMutexA 来确保防止重复运行的话还是另想办法吧,因为CEF是多进程,如果你非得用他来防止多开的话,可以在CefInitialize 执行之后在去使用它
2.编译的时候不要选择 use_sanbox(如果你需要用到他就勾选 否则会出很多编译错误)
3.cef是多进程的,browser跟render 之间不能用传统的C++的方式传递变量,要使用他内部的通讯方式
4.如果使用离屏渲染,GetViewRect 这个方法返回的rect很重要,如果返回的rect跟实际不一致会导致渲染失败,他的症状表现为启动后有进程但无法看到界面,所以遇到此类问题可以先去看看是否是这个原因导致
5.cef跟windowsx.h 头文件是不兼容的,避开他使用,如果必须用到windowsx.h里的东西,那就自己拿出来定义后使用 (目前只能这样没有办法 等后面看看cef官方是否会兼容这个头文件)
6.离屏渲染需要自己实现gdi画图,官方例子是使用OpenGL,不管用哪一种,需要对view跟pop都进行渲染以及擦掉渲染,cef有2类窗口,一类是主窗口view,另一个是pop弹窗,网页的下拉框也属于弹窗的一种,他弹出后的窗口也需要对他捕获渲染,要分开处理,否则会出现弹出的窗口不显示的情况,另外等他弹出窗口关闭后,还需要进行渲染擦除,不然会有残留(离屏渲染是真的麻烦)
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) OVERRIDE;
PaintElementType type 可以用来区分当前执行渲染的是哪一类窗口
然后你还需要实现这2个虚函数
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) OVERRIDE
在OnPopupShow中可以判断当前的弹窗的状态,用来选择是擦去渲染还是执行渲染弹出
在OnPopupSize中可以获取到弹出层的尺寸,可以联合OnPopupShow一起判断,其实在OnPaint中多少也能预知,因为离屏渲染大部分窗口都是不可调整,所以基本上尺寸如果变动就属于弹窗的一种了
7.如果他提示跨域拦截,要解决CEF的跨域问题,在 OnBeforeCommandLineProcessing 里增加一下代码
virtual void OnBeforeCommandLineProcessing(
const CefString& process_type,
CefRefPtr<CefCommandLine> command_line)
{
command_line->AppendSwitch("--disable-web-security");
command_line->AppendSwitch("--disable-site-isolation-trials");
}
友情提示:OnBeforeCommandLineProcessing 属于CefApp,就是你最后要放到CefExecuteProcess 这里去当入参的这个类
8.cef中开启调试器的代码:
CefWindowInfo windowInfo;
CefBrowserSettings settings;
windowInfo.SetAsPopup(NULL, "DevTools");
m_browser->GetHost()->ShowDevTools(windowInfo, this, settings, CefPoint());
ps:直接拷贝我的代码,自己改下对象指针
9.屏蔽cef的自身右键菜单,代码如下
//屏蔽自身cef的菜单
void Client::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model)
{
CEF_REQUIRE_UI_THREAD();
if ((params->GetTypeFlags() & (CM_TYPEFLAG_PAGE | CM_TYPEFLAG_FRAME)) != 0)
{
if (model->GetCount() > 0)
{
model->Clear();
}
}
}
本来还想写下cef跟js的交互,但是发现好麻烦,东西蛮多。懒得整理了就酱了
CEF中的坑很多,各位慢慢踩,嘿嘿