cef离屏渲染(osr)初识
业务需要,客户端的webview需要使用使用osr,透明绘制,才能实现一些业务,于是有了这个经历,如果你是新手,不妨看看。
环境配置
先下一个cef官方的demo,如果找不到请:点它
我下载的是这个
我的环境是win+vs2019所以我需要生成一个vs工程,
这是我解压后的目录,一看显然可以用cmake生成vs工程
于是
如图,我是vs2019,下载是32位的,如此选择操作;于是工程就有了
打开工程:
ceflient是一个五脏俱全的例子,所以选择它作为启动项,编译运行起来就是这个样子了:
看到是网页加载失败,因为他默认是谷歌的地址,被墙挡住了,所以就失败,换成百度的看看:修改这里
如图是在cefclient_win.cc里面。
于是成功的出来了出来了百度的首页
离屏模式
1,官方的例子肯定不是离屏模式(osr),需要操作一下;
只需要在启动时候加上 --off-screen-rendering-enabled
启动参数,那么他就是离屏模式启动了或者我们在初始化cef的时候:
// Create the main message loop object.
scoped_ptr<MainMessageLoop> message_loop;
if (settings.multi_threaded_message_loop)
message_loop.reset(new MainMessageLoopMultithreadedWin);
else if (settings.external_message_pump)
message_loop = MainMessageLoopExternalPump::Create();
else
message_loop.reset(new MainMessageLoopStd);
// Initialize CEF.
settings.windowless_rendering_enabled = true;
context->Initialize(main_args, settings, app, sandbox_info);
settings.windowless_rendering_enabled = true;设置成true,同样的效果。
2,离屏以后肉眼发现了个问题
网页边上出现了一条线,看着很恶心,开始还一度怀疑是不是,网页绘制出来的。最后发现,是官方ceflient例子,创建的渲染窗口是一个有边框的窗口,改下这里就可以了
void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!hwnd_ && !render_handler_.get());
DCHECK(parent_hwnd);
DCHECK(!::IsRectEmpty(&rect));
HINSTANCE hInst = ::GetModuleHandle(NULL);
const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
const HBRUSH background_brush = CreateSolidBrush(
RGB(CefColorGetR(background_color), CefColorGetG(background_color),
CefColorGetB(background_color)));
RegisterOsrClass(hInst, background_brush);
DWORD ex_style = 0;
if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
// Don't activate the browser window on creation.
ex_style |= WS_EX_NOACTIVATE;
}
// Create the native window with a border so it's easier to visually identify
// OSR windows.
//他这里加了这个边框的属性WS_BORDER 把他去掉
//hwnd_ = ::CreateWindowEx(
// ex_style, kWndClass, 0,
// WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
// rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
// parent_hwnd, 0, hInst, 0);
//CHECK(hwnd_);
hwnd_ = ::CreateWindowEx(
ex_style, kWndClass, 0,
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
parent_hwnd, 0, hInst, 0);
CHECK(hwnd_);
client_rect_ = rect;
// Associate |this| with the window.
SetUserDataPtr(hwnd_, this);
#if defined(CEF_USE_ATL)
accessibility_root_ = nullptr;
// Create/register the drag&drop handler.
drop_target_ = DropTargetWin::Create(this, hwnd_);
HRESULT register_res = RegisterDragDrop(hwnd_, drop_target_);
DCHECK_EQ(register_res, S_OK);
#endif
ime_handler_.reset(new OsrImeHandlerWin(hwnd_));
// Enable Touch Events if requested
if (client::MainContext::Get()->TouchEventsEnabled())
RegisterTouchWindow(hwnd_, 0);
// Notify the window owner.
NotifyNativeWindowCreated(hwnd_);
}
编译看下:
就没有了
透明绘制
如何启动透明绘制呢,也是启动的时候加上这俩参数--no-proxy-server --transparent-painting-enabled
就可以了;但是却发现背景变成这样的了:
这显然是不对头的,首先我怀疑是不是cef绘制给到数据就是这样的:于是找到继承这个类CefRenderHandler
对象,找到改方法
oid ClientHandlerOsr::OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->OnPaint(browser, type, dirtyRects, buffer, width, height);
}
这里保存图片验证下看看:最后发现,出来的图片背景不是五彩缤纷的。
那么最后只能是,渲染到窗口这个过程,出的幺蛾子,最后发现
void OsrRenderer::Render() {
if (view_width_ == 0 || view_height_ == 0)
return;
DCHECK(initialized_);
struct {
float tu, tv;
float x, y, z;
} static vertices[] = {{0.0f, 1.0f, -1.0f, -1.0f, 0.0f},
{1.0f, 1.0f, 1.0f, -1.0f, 0.0f},
{1.0f, 0.0f, 1.0f, 1.0f, 0.0f},
{0.0f, 0.0f, -1.0f, 1.0f, 0.0f}};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
VERIFY_NO_ERROR;
glMatrixMode(GL_MODELVIEW);
VERIFY_NO_ERROR;
glLoadIdentity();
VERIFY_NO_ERROR;
// Match GL units to screen coordinates.
glViewport(0, 0, view_width_, view_height_);
VERIFY_NO_ERROR;
glMatrixMode(GL_PROJECTION);
VERIFY_NO_ERROR;
glLoadIdentity();
VERIFY_NO_ERROR;
// Draw the background gradient.
glPushAttrib(GL_ALL_ATTRIB_BITS);
VERIFY_NO_ERROR;
// Don't check for errors until glEnd().
glBegin(GL_QUADS);
glColor4f(1.0, 0.0, 0.0, 1.0); // red
glVertex2f(-1.0, -1.0);
glVertex2f(1.0, -1.0);
glColor4f(0.0, 0.0, 1.0, 1.0); // blue
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
VERIFY_NO_ERROR;
glPopAttrib();
VERIFY_NO_ERROR;
// Rotate the view based on the mouse spin.
if (spin_x_ != 0) {
glRotatef(-spin_x_, 1.0f, 0.0f, 0.0f);
VERIFY_NO_ERROR;
}
if (spin_y_ != 0) {
glRotatef(-spin_y_, 0.0f, 1.0f, 0.0f);
VERIFY_NO_ERROR;
}
if (IsTransparent()) {
// Alpha blending style. Texture values have premultiplied alpha.
//就真的是这里搞出来的
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
VERIFY_NO_ERROR;
// Enable alpha blending.
glEnable(GL_BLEND);
VERIFY_NO_ERROR;
}
// Enable 2D textures.
glEnable(GL_TEXTURE_2D);
VERIFY_NO_ERROR;
// Draw the facets with the texture.
DCHECK_NE(texture_id_, 0U);
VERIFY_NO_ERROR;
glBindTexture(GL_TEXTURE_2D, texture_id_);
VERIFY_NO_ERROR;
glInterleavedArrays(GL_T2F_V3F, 0, vertices);
VERIFY_NO_ERROR;
glDrawArrays(GL_QUADS, 0, 4);
VERIFY_NO_ERROR;
// Disable 2D textures.
glDisable(GL_TEXTURE_2D);
VERIFY_NO_ERROR;
if (IsTransparent()) {
// Disable alpha blending.
glDisable(GL_BLEND);
VERIFY_NO_ERROR;
}
// Draw a rectangle around the update region.
if (settings_.show_update_rect && !update_rect_.IsEmpty()) {
int left = update_rect_.x;
int right = update_rect_.x + update_rect_.width;
int top = update_rect_.y;
int bottom = update_rect_.y + update_rect_.height;
#if defined(OS_LINUX)
// Shrink the box so that top & right sides are drawn.
top += 1;
right -= 1;
#else
// Shrink the box so that left & bottom sides are drawn.
left += 1;
bottom -= 1;
#endif
glPushAttrib(GL_ALL_ATTRIB_BITS);
VERIFY_NO_ERROR
glMatrixMode(GL_PROJECTION);
VERIFY_NO_ERROR;
glPushMatrix();
VERIFY_NO_ERROR;
glLoadIdentity();
VERIFY_NO_ERROR;
glOrtho(0, view_width_, view_height_, 0, 0, 1);
VERIFY_NO_ERROR;
glLineWidth(1);
VERIFY_NO_ERROR;
glColor3f(1.0f, 0.0f, 0.0f);
VERIFY_NO_ERROR;
// Don't check for errors until glEnd().
glBegin(GL_LINE_STRIP);
glVertex2i(left, top);
glVertex2i(right, top);
glVertex2i(right, bottom);
glVertex2i(left, bottom);
glVertex2i(left, top);
glEnd();
VERIFY_NO_ERROR;
glPopMatrix();
VERIFY_NO_ERROR;
glPopAttrib();
VERIFY_NO_ERROR;
}
}
于是我把这里改成这样
if (IsTransparent()) {
// Alpha blending style. Texture values have premultiplied alpha.
//如下修改
glBlendFunc(GL_ONE, GL_ZERO);
VERIFY_NO_ERROR;
// Enable alpha blending.
glEnable(GL_BLEND);
VERIFY_NO_ERROR;
}
最后就变成这样了:
为啥是黑色的,因为这个窗口时透明背景,透下到窗口背景它就是这色的。