libcef–框架架构中概念介绍–离屏渲染–发布任务–进程间通信 (IPC)–异步 JavaScript 绑定(五)

1.离屏渲染

  使用离屏渲染 CEF 不会创建本机浏览器窗口。相反,CEF 为主机应用程序提供无效区域和像素缓冲区,主机应用程序将鼠标、键盘和焦点事件通知 CEF。离屏渲染目前不支持加速合成,因此与窗口浏览器相比,性能可能会受到影响。屏幕外浏览器将收到与窗口浏览器相同的通知,包括上一节中描述的生命周期通知。要使用离屏渲染:

  • 实现CefRenderHandler接口。除非另有说明,否则所有方法都是必需的。
  • 在将 CefWindowInfo 结构传递给 CefBrowserHost::CreateBrowser() 之前调用 CefWindowInfo::SetAsWindowless()。如果没有父窗口传递给 SetAsWindowless,则上下文菜单等某些功能可能不可用。
  • CefRenderHandler::GetViewRect() 方法将被调用以检索所需的视图矩形。
  • 将调用 CefRenderHandler::OnPaint() 方法以提供无效区域和更新的像素缓冲区。cefclient 应用程序使用 OpenGL 绘制缓冲区,但您的应用程序可以使用您喜欢的任何技术。
  • 要调整浏览器的大小,请调用 CefBrowserHost::WasResized()。这将导致调用 GetViewRect() 以检索新大小,然后调用 OnPaint()。
  • 调用 CefBrowserHost::SendXXX() 方法来通知浏览器鼠标、键盘和焦点事件。
  • 调用 CefBrowserHost::CloseBrowser() 来销毁浏览器。

  使用“–off-screen-rendering-enabled”命令行标志运行cefclient作为一个工作示例。

2.发布任务

  可以使用 CefPostTask 系列方法在单个进程中的各个线程之间发布任务(完整列表请参见include/cef_task.h头文件)。该任务将在目标线程的消息循环上异步执行。

  CEF 提供 base::Bind 和 base::Callback 模板化回调类,用于将绑定方法、对象和参数传递给 CefPostTask。有关完整的 base::Bind 和 base::Callback 用法信息,请参阅include/base/cef_callback.h标头中的注释。的包括/包装/ cef_closure_task.h头提供助手用于将基::封闭到CefTask。例如:

// Include the necessary headers.
#include “include/base/cef_bind.h”
#include “include/wrapper/cef_closure_task.h”

// To execute a bound function:

// Define a function.
void MyFunc(int arg) { /* do something with |arg| on the UI thread */ }

// Post a task that will execute MyFunc on the UI thread and pass an |arg|
// value of 5.
CefPostTask(TID_UI, base::Bind(&MyFunc, 5));

// To execute a bound method:

// Define a class.
class MyClass : public CefBase
{
public:
    MyClass() {}
    void MyMethod(int arg) { /* do something with |arg| on the UI thread */ }
private:
    IMPLEMENT_REFCOUNTING(MyClass);
};

// Create an instance of MyClass.
CefRefPtr<MyClass> instance = new MyClass();

// Post a task that will execute MyClass::MyMethod on the UI thread and pass
// an |arg| value of 5. |instance| will be kept alive until after the task
// completes.
CefPostTask(TID_UI, base::Bind(&MyClass::MyMethod, instance, 5));

  如果宿主应用程序需要保持对运行循环的引用,它可以使用 CefTaskRunner 类。例如,要获取 UI 线程的任务运行程序:

CefRefPtr<CefTaskRunner> task_runner = CefTaskRunner::GetForThread(TID_UI);

3.进程间通信 (IPC)

  由于 CEF3 在多个进程中运行,因此有必要提供在这些进程之间进行通信的机制。CefBrowser 和 CefFrame 对象在浏览器和渲染进程中都存在。每个 CefBrowser 和 CefFrame 对象还有一个与之关联的唯一 ID 值,它将在进程边界的两侧匹配。

3.1 进程启动消息

  要在启动时为所有渲染进程提供相同的信息,请在浏览器进程中实现 CefBrowserProcessHandler::OnRenderProcessThreadCreated()。这将在渲染过程中将信息传递给 CefRenderProcessHandler::OnRenderThreadCreated()。

3.2 运行时处理消息

  在运行时可以使用 CefProcessMessage 类在进程之间传递消息。这些消息与特定的 CefBrowser 和 CefFrame 实例相关联,并使用 CefFrame::SendProcessMessage() 方法发送。进程消息应包含通过 CefProcessMessage::GetArgumentList() 所需的任何状态信息。

// Create the message object.
CefRefPtr<CefProcessMessage> msg= CefProcessMessage::Create("my_message");

// Retrieve the argument list object.
CefRefPtr<CefListValue> args = msg>GetArgumentList();

// Populate the argument values.
args->SetString(0, "my string");
args->SetInt(0, 10);

// Send the process message to the main frame in the render process.
// Use PID_BROWSER instead when sending a message to the browser process.
browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, msg);

  从浏览器进程发送到渲染进程的消息将到达 CefRenderProcessHandler::OnProcessMessageReceived()。从渲染进程发送到浏览器进程的消息将到达 CefClient::OnProcessMessageReceived()。

bool MyHandler::OnProcessMessageReceived(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefProcessId source_process,
    CefRefPtr<CefProcessMessage> message)
{
    // Check the message name.
    const std::string &message_name = message->GetName();
    if (message_name == "my_message")
    {
        // Handle the message here...
        return true;
    }
    return false;
}

4.异步 JavaScript 绑定

  JavaScript Integration在渲染进程中实现,但经常需要与浏览器进程通信。JavaScript API 本身应该被设计为使用闭包和promise异步工作。

4.1 通用消息路由器

  CEF 提供了一种通用实现,用于在渲染器进程中运行的 JavaScript 和在浏览器进程中运行的 C++ 之间路由异步消息。应用程序通过向路由器传递来自标准 CEF C++ 回调(OnBeforeBrowse、OnProcessMessageRecieved、OnContextCreated 等)的数据与路由器交互。渲染器端路由器支持通用 JavaScript 回调注册和执行,而浏览器端路由器通过一个或多个应用程序提供的 Handler 实例支持特定于应用程序的逻辑。有关演示 CefMessageRouter 用法的独立示例应用程序,请参阅message_router 示例。有关完整的使用文档,请参阅include/wrapper/cef_message_router.h。

4.2 自定义实现

  基于 CEF 的应用程序还可以提供它自己的异步 JavaScript 绑定的自定义实现。一个简单的实现可以如下工作:
1.渲染过程中的JavaScript绑定传入一个回调函数。

// In JavaScript register the callback function.
app.setMessageCallback('binding_test', function(name, args) {
  document.getElementById('result').value = "Response: "+args[0];
});

2.渲染进程保持对回调函数的引用。

// Map of message callbacks.
typedef std::map<std::pair<std::string, int>,
        std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >
        CallbackMap;
CallbackMap callback_map_;

// In the CefV8Handler::Execute implementation for “setMessageCallback”.
if (arguments.size() == 2 && arguments[0]->IsString() &&
        arguments[1]->IsFunction())
{
    std::string message_name = arguments[0]->GetStringValue();
    CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
    int browser_id = context->GetBrowser()->GetIdentifier();
    callback_map_.insert(
        std::make_pair(std::make_pair(message_name, browser_id),
                       std::make_pair(context, arguments[1])));
}

3.渲染进程向浏览器进程发送异步 IPC 消息,请求执行工作。
4.浏览器进程接收IPC消息并执行工作。
5.完成工作后,浏览器进程将带有结果的异步 IPC 消息发送回渲染进程。
6.render进程收到IPC消息,带着结果执行回调函数。

// Execute the registered JavaScript callback if any.
if (!callback_map_.empty())
{
    const CefString &message_name = message->GetName();
    CallbackMap::const_iterator it = callback_map_.find(
                                         std::make_pair(message_name.ToString(),
                                                 browser->GetIdentifier()));
    if (it != callback_map_.end())
    {
        // Keep a local reference to the objects. The callback may remove itself
        // from the callback map.
        CefRefPtr<CefV8Context> context = it->second.first;
        CefRefPtr<CefV8Value> callback = it->second.second;

        // Enter the context.
        context->Enter();

        CefV8ValueList arguments;

        // First argument is the message name.
        arguments.push_back(CefV8Value::CreateString(message_name));

        // Second argument is the list of message arguments.
        CefRefPtr<CefListValue> list = message->GetArgumentList();
        CefRefPtr<CefV8Value> args = CefV8Value::CreateArray(list->GetSize());
        SetList(list, args);  // Helper function to convert CefListValue to CefV8Value.
        arguments.push_back(args);

        // Execute the callback.
        CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(NULL, arguments);
        if (retval.get())
        {
            if (retval->IsBool())
                handled = retval->GetBoolValue();
        }

        // Exit the context.
        context->Exit();
    }
}

7.在 CefRenderProcessHandler::OnContextReleased() 中释放与上下文关联的任何 V8 引用。

void MyHandler::OnContextReleased(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame,
                                  CefRefPtr<CefV8Context> context)
{
    // Remove any JavaScript callbacks registered for the context that has been released.
    if (!callback_map_.empty())
    {
        CallbackMap::iterator it = callback_map_.begin();
        for (; it != callback_map_.end();)
        {
            if (it->second.first->IsSame(context))
                callback_map_.erase(it++);
            else
                ++it;
        }
    }
}

5.同步请求

  在极少数情况下,可能需要在浏览器和渲染进程之间实现同步通信。应尽可能避免这种情况,因为它会对渲染过程中的性能产生负面影响。但是,如果您必须进行同步通信,请考虑使用同步 XMLHttpRequests,它会在等待浏览器进程网络层中的处理时阻塞渲染进程。浏览器进程可以使用自定义方案处理程序或网络拦截来处理请求。有关详细信息,请参阅“网络层”部分。

  合理的脚本代码可以有效的提高工作效率,减少重复劳动。


  欢迎光临知了软件开发网络平台,本公司定制开发各类软件,主要方向为桌面专业软件开发、插件定制开发、微信小程序(各类小程序)、网站定制开发和App开发,桌面软件主要包括文字图形识别类软件,信息管理类软件,3D打印类软件,视频类软件以及其它涉及专业的各类图形图像处理软件。插件包含AE插件,AI插件,PS插件,PDF插件,3DMAX插件以及Word,Excel等Office插件开发。详情请咨询,微信QQ:312117271,手机:18928899728,邮箱: [email protected].
公司网址:http://www.zhiliaos.com

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>