ARChon 分析之六:native-client 的加载、显示与事件传递浅析

版权声明:转载请邮件联系我([email protected]),以取得授权,谢谢! https://blog.csdn.net/yeshennet/article/details/84678138

新手教程/基础概念,请先移步看这篇文章

这篇文章聚焦两个问题:

  • html/js代码如何加载nacl中的程序?
  • nacl与chrome.app.window是如何沟通的?(渲染与鼠标事件传递)

如何加载

PNaCl

GoogleChrome 现在是支持直接用 PNaCl 的,要使用的话怎么做呢?

增加一个类似这样的dom节点:

<embed name="nacl_module" id="nacl_module" width="100%" height="100%" 
path src="//storage.googleapis.com/gonacl/demos/publish/236779/voronoi/voronoi.nmf" 
type="application/x-pnacl">

可以看到,nacl做作为一种新的类型( application/x-pnacl )被Chrome浏览器协议接受.js 可以通过 PPB_Messaging 向dom节点发信息。

NaCl

NaCl 和 PNaCl 不同的一个点是换了一个type ,新的type是 application/x-pnacl 原生部分的代码还是遵循同样的原则,需要一个 .nmf 的配置文件。配置在 embed 节点的 src 中。

那么什么是 nmf 呢?

参考:Native Client Manifest (nmf) Format

每个Native Client应用程序都有一个JSON格式的 NaCl Manifest File( nmf )。 nmf告诉浏览器下载和加载Native Client应用程序文件和库的位置。 该文件还可以包含配置选项。

{
  "program": {
    // Required: at least one entry
    // Add one of these for each architecture supported by the application.
    "x86-32": { "url": "lib32/runnable-ld.so" },
    "x86-64": { "url": "lib64/runnable-ld.so" }
  },
  // discussed in next section
  "files": {
    "main.nexe": {
      "x86-32": { "url": "url_to_x86_32_nexe" },
      "x86-64": { "url": "url_to_x86_64_nexe" }
    },
    // ...
  }
}

files字段指定Native Client应用程序要使用的文件资源字典。files清单字段对于动态链接的可执行files很重要,这些可执行文件必须在PPAPI初始化之前加载文件。 files字典应包括主动态程序及其动态库。 应该有一个与每个动态库对应的文件条目。 每个文件条目都是受支持体系结构的字典,以及可以找到该体系结构的相应Native Client共享对象(.so)的URL。

由于program用于引用glibc的NaCl端口附带的动态链接器,因此主程序在files字典中指定。 主程序在files字典的"main.nexe"字段下指定。

渲染显示 与 鼠标事件输入

参考 example 中的代码,看到nacl中有几个头文件:ppapi/cpp/graphics_2d.hppapi/cpp/graphics_2d.hppapi/lib/gles2 可以看到它已经支持了GLES2.0了。

这部分的信息,example/AI/Graphics_2d 做了展示。查看它的代码.

它构建了一个 pp:Module 对象,这个对象集成创建了 pp:Instance 的实例。

class Graphics2DModule : public pp::Module {
 public:
  Graphics2DModule() : pp::Module() {}
  virtual ~Graphics2DModule() {}

  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new Graphics2DInstance(instance);
  }
};

namespace pp {
Module* CreateModule() { return new Graphics2DModule(); }
}  // namespace pp

查了一下文档,发现pp::Instance 能力很强大,看接口,设计者应该是把它封装为能够 处理输入输出事件画版

pp::Instance有几个重要的钩子:

BindGraphics //Graphics2D Graphics3D Compositor

此设备的内容将显示在网页上的实例区域中。 设备必须是2D或3D设备。

您可以传递一个is_null() (默认构造的) Graphics2D作为设备参数来取消绑定给定实例中的所有设备。 然后该实例将显示为透明。 重新绑定相同的设备将返回true并且不执行任何操作。

任何以前绑定的设备都将被释放。 绑定设备已绑定到另一个实例时绑定设备是错误的。 如果要在实例之间移动设备,首先将其与旧实例取消绑定,然后将其重新绑定到新实例。

绑定设备将使网页的该部分无效,以将新设备的内容刷新到屏幕。

DidChangeFocus

当实例获得或失去焦点时,会调用DidChangeFocus() 。

拥有焦点意味着键盘事件将被发送到实例。 实例的默认条件是它不具有焦点。

焦点标志考虑了浏览器选项卡和窗口焦点以及页面上插件元素的焦点。 为了被视为具有焦点,浏览器窗口必须位于最顶层,必须在窗口中选择选项卡,并且实例必须是页面上的焦点元素。

注意:仅当您处理click事件时,实例上的单击才会获得焦点。 从HandleInputEvent中的PPP_InputEvent返回true (或使用未过滤的事件)以表示已处理click事件。 否则,浏览器将冒泡事件并将焦点放在页面上实际最终消耗它的元素上。 如果您没有获得焦点,请检查以确保您是通过RequestInputEvents() (which implicitly marks all input events as consumed) or via RequestFilteringInputEvents()请求它们,并从事件处理程序返回true。

HandleInputEvent (const pp::InputEvent &event)

默认实现不执行任何操作并返回false。

要接收输入事件,必须通过调用RequestInputEvents()或RequestFilteringInputEvents()来注册它们。 默认情况下,不会传递任何事件。

如果事件已处理,则不会将其转发给任何默认处理程序。 如果未处理,则可以将其分派给默认处理程序。 因此,实例必须准确响应事件传播是否应该继续。

事件传播也控制焦点。 如果您处理类似鼠标事件的事件,通常会为实例提供焦点。 从过滤的事件处理程序返回false或不注册事件类型意味着点击将被提供给页面的下半部分,并且您的实例将不会获得焦点。 这允许实例部分透明,其中透明区域的点击将表现为对基础页面的点击。

通常,您应该尝试保持输入事件处理的简短。 特别是对于过滤的输入事件,可能会阻止浏览器或页面等待您的响应。

此函数的调用者将在此调用期间保持对输入事件资源的引用。 除非您参考资源以便以后保留它,否则您不需要释放它。

注意:如果您没有收到输入事件,请确保通过调用RequestInputEvents或RequestFilteringInputEvents注册所需的事件类。 如果您仍然没有收到键盘输入事件,请确保您为鼠标事件返回true(或使用非过滤事件处理程序)。 否则,实例将无法获得焦点,并且不会发送键盘事件。

有关详细信息,请参阅RequestInputEvents和RequestFilteringInputEvents 。

HandleMessage

HandleMessage()是一个函数,当在JavaScript的实例的DOM元素上调用PostMessage()时,浏览器会调用该函数。

请注意,JavaScript接口中的PostMessage()是异步的,这意味着当HandleMessage()处理消息时,不会阻止JavaScript执行。

转换JavaScript数组时,将忽略名称不是数组索引的任何对象属性。 传递数组和对象时,将转换和传输整个参考图。 如果参考图表有周期,则不会发送消息,并且会将错误记录到控制台。

PostMessage

PostMessage()异步调用给定实例的DOM元素上的消息事件的任何侦听器。
处理消息时,对PostMessage()的调用不会阻止。

 {.html}

 <body>
   <object id="plugin"
           type="application/x-ppapi-postMessage-example"/>
   <script type="text/javascript">
     var plugin = document.getElementById('plugin');
     plugin.addEventListener("message",
                             function(message) { alert(message.data); },
                             false);
   </script>
</body>

然后该实例调用PostMessage() ,如下所示:

PostMessage(pp::Var("Hello world!"));

浏览器会弹出一个警告“Hello world!”
传递数组或字典PP_Var ,将转换并传输整个参考图。 如果参考图表有周期,则不会发送消息,并且会将错误记录到控制台。

JavaScript代码中的消息事件监听器将接收符合HTML 5 MessageEvent接口的对象。 具体来说,message的值将作为收到的MessageEvent名为data的属性包含MessageEvent 。
此消息传递系统类似于用于侦听来自Web Workers的消息的系统。 有关详细信息,请参阅http://www.whatwg.org/specs/web-workers/current-work/ 。

猜你喜欢

转载自blog.csdn.net/yeshennet/article/details/84678138
今日推荐