Qt+Cef3离屏渲染(一)

离屏渲染(Off-Screen Rendering)

在离屏渲染模式下,CEF不会创建原生浏览器窗口。CEF为宿主程序提供无效的区域和像素缓存区,而宿主程序负责通知鼠标键盘以及焦点事件给CEF。离屏渲染目前不支持混合加速,所以性能上可能无法和非离屏渲染相比。离屏浏览器将收到和窗口浏览器同样的事件通知,

下面介绍如何使用离屏渲染:

实现CefRenderHandler接口。除非特别说明,所有的方法都需要覆写。
调用CefWindowInfo::SetAsOffScreen(),将CefWindowInfo传递给CefBrowserHost::CreateBrowser()之前还可以选择设置CefWindowInfo::SetTransparentPainting()。

如果没有父窗口被传递给SetAsOffScreen,则有些类似上下文菜单这样的功能将不可用。

CefRenderHandler::GetViewRect方法将被调用以获得所需要的可视区域。
CefRenderHandler::OnPaint() 方法将被调用以提供无效区域(脏区域)以及更新过的像素缓存。

cefclient程序里使用OpenGL绘制缓存,但你可以使用任何别的绘制技术。

可以调用CefBrowserHost::WasResized()方法改变浏览器大小。这将导致对GetViewRect()方法的调用,以获取新的浏览器大小,然后调用OnPaint()重新绘制。

调用CefBrowserHost::SendXXX()方法通知浏览器的鼠标、键盘和焦点事件。

调用CefBrowserHost::CloseBrowser()销毁浏览器。

使用命令行参数–off-screen-rendering-enabled运行cefclient,可以测试离屏渲染的效果。

这段话是来自:https://github.com/fanfeilong/cefutil/blob/master/doc/CEF%20General%20Usage-zh-cn.md#off-screen-rendering

离屏渲染可以Qt背景透明下的显示问题,比如做一些异形窗口。

我们从一个简单的例子来实现Qt中的Cef3的离屏渲染。上面的步骤看起来有点复杂,但我们从实际的例子入手,一步步完善,就简单了。

第一步:

在CefSettings中的windowless_rendering_enabled设置为true

settings.windowless_rendering_enabled = true;

第二步:

继承CefRenderHandler,并且实现它全部接口(也就是纯虚函数),和重新部分virtual函数(是部分,可以不用全部实现,这个看你的功能需求)

  // Called to retrieve the view rectangle which is relative to screen
  // coordinates. This method must always provide a non-empty rectangle.
  ///
  /*--cef()--*/
  virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;

  // Called when an element should be painted. Pixel values passed to this
  // method are scaled relative to view coordinates based on the value of
  // CefScreenInfo.device_scale_factor returned from GetScreenInfo. |type|
  // indicates whether the element is the view or the popup widget. |buffer|
  // contains the pixel data for the whole image. |dirtyRects| contains the set
  // of rectangles in pixel coordinates that need to be repainted. |buffer| will
  // be |width|*|height|*4 bytes in size and represents a BGRA image with an
  // upper-left origin. This method is only called when
  // CefWindowInfo::shared_texture_enabled is set to false.
  ///
  /*--cef()--*/
  virtual void OnPaint(CefRefPtr<CefBrowser> browser,
                       PaintElementType type,
                       const RectList& dirtyRects,
                       const void* buffer,
                       int width,
                       int height) = 0;

解释一下:

  virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;

这个纯虚函数就是获取浏览器的矩形范围,想象一下,如果你想将浏览器放在某个QWidget,或者子控件上,那么这里的rect就应该返回该QWidget的矩形区域。在实际中,这个rect设置为(0, 0, width, height)。
看这里的rect的引用,其实就是要对这个rect进行赋值,剩下的就交给Cef自己去做了。

第二个函数:

 virtual void OnPaint(CefRefPtr<CefBrowser> browser,
                       PaintElementType type,
                       const RectList& dirtyRects,
                       const void* buffer,
                       int width,
                       int height) = 0;

这个就比较关键了
它就是将获取的每一帧图片的数据存放在buffer指针指向内存中,width和height是这张图片的宽和高。

这个type,根据源码其实就是

typedef enum {
   
  PET_VIEW = 0,
  PET_POPUP,
} cef_paint_element_type_t;

这个枚举,这个可以先不用去管它,后面再深入了解它就行,知道有这么个参数就行。

第三步:
将第二步中OnPaint中获取的图像数据,贴到QWidget所在的矩形位置上。

通过事件,将刚刚获取的图像,以QImage对象的方式,发送给窗口,在paintEvent中将这个QImage贴到界面上(调用QPainter的drawImage)

第四步:
在窗口的resizeEvent事件中调用
调用CefBrowserHost的WasResized()方法,这样窗口大小变化的时候,离屏渲染出来的图像大小也会变化,我们看到的就是“浏览器”随着窗口的尺寸变化而变化。

以上就是我自己摸索出来的最简单的离屏渲染的几个步骤,接下来的几篇博客,我会逐步添加一些响应事件,让离屏渲染的功能更加完善。万丈高楼平地起,我们一步步来。

我们从代码开始:
main.cpp中

#include "cefosrwidget.h"
#include "simple_app.h"
#include "simple_handler.h"

#include <QApplication>

void QCefInitSettings(CefSettings & settings)
{
   
   //std::string cache_path = AppGetWorkingDirectory().toStdString() + "/.cache";//缓存地址
   // CefString(&settings.cache_path) = CefString(cache_path);
    settings.multi_threaded_message_loop = true;//多线程消息循环
    settings.log_severity = LOGSEVERITY_DISABLE;//日志

    settings.windowless_rendering_enabled = true;

    settings.no_sandbox = false;//沙盒
}

int QCefInit(int& argc, char** argv)
{
   
    HINSTANCE hInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));

    CefMainArgs mainArgs(hInstance);
    CefRefPtr<SimpleApp> app(new SimpleApp); //CefApp实现,用于处理进程相关的回调。

    int exit_code = CefExecuteProcess(mainArgs, app.get(), nullptr);
    if (exit_code >= 0) {
   
        return exit_code;
    }

    CefSettings settings;
    QCefInitSettings(settings);
    CefInitialize(mainArgs, settings, app, nullptr);

    return -1;
}

void CefQuit()
{
   
    CefShutdown();
}

int main(int argc, char *argv[])
{
   
    QApplication a(argc, argv);
    int result = QCefInit(argc, argv);
    if (result >= 0) {
   
        return result;
    }

    CefOSRWidget widget;
    widget.show();

    a.exec();
    CefQuit();

    return 0;
}

simple_app.h

// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_

#include "include/cef_app.h"

// Implement application-level callbacks for the browser process.
class SimpleApp : public CefApp, public CefBrowserProcessHandler {
   
 public:
  SimpleApp();

  // CefApp methods:
  virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
      OVERRIDE {
   
    return this;
  }

  // CefBrowserProcessHandler methods:
  virtual void OnContextInitialized() OVERRIDE;

 private:
  // Include the default reference counting implementation.
  IMPLEMENT_REFCOUNTING(SimpleApp);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_

simple_app.cc

// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "simple_app.h"

#include <string>

#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
#include "simple_handler.h"

namespace {
   

// When using the Views framework this object provides the delegate
// implementation for the CefWindow that hosts the Views-based browser.
class SimpleWindowDelegate : public CefWindowDelegate {
   
 
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值