理解PPAPI的设计

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                       

要理解PPAPI插件的设计,先仔细阅读下面这些文章:

理解了架构设计,再看代码层面的文档:

有的链接需要翻墙,天朝的局域网,我爱死你了。

好啦,现在对PPAPI应该有基本的理解了。接下来我从代码角度来理解一下。

Module、Instance、Interface

HTML页面可以通过embed标签来嵌入一个插件,HTML页面被加载时,解析到embed标签,就会根据type属性定位我们注册的PPAPI插件,加载对应的插件库(DLL)。

当PPAPI的库文件(DLL)被加载到浏览器进程中时,一个Module就产生了。在代码中,通过PP_Module(定义在pp_module.h中)来表示,用于标识一个Module的PP_Module类型实际上是一个int32。Module的标识符通过PPP_InitializeModule函数传入。PPP_InitializeModule函数的原型如下:

int32_t PPP_InitializeModule(PP_Module module, PPB_GetInterface get_browser_interface) ;
   
   
  • 1

第一个参数就是浏览器分配给你的插件库文件的标识符(handle),一般你需要保存它,后续的有些API会用到。

扫描二维码关注公众号,回复: 4955479 查看本文章

所以,一个Module,仅仅标识了library。要想在浏览器上显示点什么,还需要从这个Module里创建一个实例,这个实例代表了我们可以看见并与之交互的网页对象。一个插件实例对象又有两个层面的属性,一个就是标示符,通过PP_Instance(32位整型)来表示;另外一个是用来操作实例对象的接口,用PPP_Instance表示(聚合了各种函数指针的结构体)。

PPAPI的plugin会导出PPP_GetInterface函数,其原型如下:

const void* PPP_GetInterface(const char* interface_name);
   
   
  • 1

当浏览器要为HTML页面创建插件实例时,会先调用PPP_GetInterface函数获取一个实例模板指针(可以理解为PPP_Instance的实例,类似一个类,实际上是一个定义了函数指针成员的结构体)。

PPP_GetInterface函数接受一个字符串名字,返回void*,浏览器拿到万能的void*后会根据名字转换为具体的PPP_instance接口,在后续使用中就通过PPP_instance接口来与插件实例交互(比如具体的创建、销毁等动作)。

简单的理解,就是PPP_GetInterface会返回能创建Instance的接口PPP_Instance,浏览器调用PPP_Instance来创建实例并与实例交互。

PPP_instance接口声明如下:

struct PPP_Instance_1_1 {  PP_Bool (*DidCreate)(PP_Instance instance,                       uint32_t argc,                       const char* argn[],                       const char* argv[]);  void (*DidDestroy)(PP_Instance instance);  void (*DidChangeView)(PP_Instance instance, PP_Resource view);  void (*DidChangeFocus)(PP_Instance instance, PP_Bool has_focus);  PP_Bool (*HandleDocumentLoad)(PP_Instance instance, PP_Resource url_loader);};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如你所见,它就像一个类,DidCreate是构造函数指针,DidDestroy是析构函数指针。创建插件实例对象时,DidCreate会被调用,其第一个参数instance,就是浏览器分配给这个插件实例对象的句柄(32位整数),通常我们可以保存起来供后续的调用使用。具体的说明,可以看ppp_instance.h。

之前在VS2013编译最简单的PPAPI插件中我们编译了stub插件,它的PPP_GetInterface函数返回NULL,所以,其实浏览器可以加载stub库文件,生成Module,但无法创建Instance。

要想实作一个有用的PPAPI plugin,必须在PPP_GetInterface中返回真实的PPP_instance接口。下面是graphics_2d_example.c里的PPP_GetInterface函数实现:

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)    return &instance_interface;  return NULL;}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

它返回的instance_interface,是这么定义的:

static PPP_Instance instance_interface = {  &Instance_DidCreate,  &Instance_DidDestroy,  &Instance_DidChangeView,  &Instance_DidChangeFocus,  &Instance_HandleDocumentLoad};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如你所见,它是一个PPP_Instance,在定义时进行了初始化,把文件内实现的几个函数,赋值给了结构体的5个函数指针。

浏览器接口PPB_GetInterface

PPAPI插件要与浏览器交互,也得先有渠道来获取浏览器的功能接口。浏览器提供了很多功能接口,比如PPB_INSTANCE_INTERFACE,PPB_IMAGEDATA_INTERFACE,PPB_GRAPHICS_2D_INTERFACE等。

这些宏都是字符串,浏览器提供的接口名字宏,以PPB_开头,插件提供的,以PPP_开头。

插件被加载时,模块初始化函数PPP_InitializeModule会被调用,其原型如下:

int32_t PPP_InitializeModule(PP_Module module_id,                                   PPB_GetInterface get_browser_interface);
   
   
  • 1
  • 2

注意第二个参数,get_browser_interface,它的类型是PPB_GetInterface,是一个函数指针,定义如下:

typedef const void* (*PPB_GetInterface)(const char* interface_name);
   
   
  • 1

如你所见,这是一个接受一个字符串参数返回void*的函数指针。插件可以在PPP_InitializeModule被调用时保存第一个参数,用它来获取浏览器提供的各种接口。根据接口名字,把返回的void*强制转换为对应的接口来使用。参看graphics_2d_example.c里的实现:

PP_EXPORT int32_t PPP_InitializeModule(PP_Module module,                                   PPB_GetInterface get_browser_interface) {  g_get_browser_interface = get_browser_interface;  g_core_interface = (const PPB_Core*)      get_browser_interface(PPB_CORE_INTERFACE);  g_instance_interface = (const PPB_Instance*)      get_browser_interface(PPB_INSTANCE_INTERFACE);  g_image_data_interface = (const PPB_ImageData*)      get_browser_interface(PPB_IMAGEDATA_INTERFACE);  g_graphics_2d_interface = (const PPB_Graphics2D*)      get_browser_interface(PPB_GRAPHICS_2D_INTERFACE);  g_view_interface = (const PPB_View*)      get_browser_interface(PPB_VIEW_INTERFACE);  if (!g_core_interface || !g_instance_interface || g_image_data_interface ||  !g_graphics_2d_interface || !g_view_interface)    return -1;  return PP_OK;}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

当我们拿到了浏览器暴露的各种接口,就可以做想干的事情了。


对于PPAPI插件的设计,先理解到这里,下次我们看插件的加载与使用流程、如何绘图、如何处理交互。

相关文章参考:

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述

猜你喜欢

转载自blog.csdn.net/jfdfhh/article/details/84195657