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

  • Chromium的Process Models
  • Chromium的Multi-process Architecture
  • Chromium的Plugin Architecture
  • Pepper plugin implementation

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

  • Important concepts for working with PPAPI
  • GettingStarted, Writing a simple plugin

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

好啦,现在对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) ;

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

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

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

const void* PPP_GetInterface(const char* interface_name);

当浏览器要为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);
};

如你所见,它就像一个类,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;
}

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

static PPP_Instance instance_interface = {&Instance_DidCreate,&Instance_DidDestroy,&Instance_DidChangeView,&Instance_DidChangeFocus,&Instance_HandleDocumentLoad
};

如你所见,它是一个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);

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

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

如你所见,这是一个接受一个字符串参数返回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;
}

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


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

相关文章参考:

  • CEF Windows开发环境搭建
  • CEF加载PPAPI插件
  • VS2013编译最简单的PPAPI插件

理解PPAPI的设计相关推荐

  1. 透彻理解Spring事务设计思想之手写实现

    2019独角兽企业重金招聘Python工程师标准>>> 前言 事务,是描述一组操作的抽象,比如对数据库的一组操作,要么全部成功,要么全部失败.事务具有4个特性:Atomicity(原 ...

  2. 【手写系列】透彻理解Spring事务设计思想之手写实现

    事务,是描述一组操作的抽象,比如对数据库的一组操作,要么全部成功,要么全部失败.事务具有4个特性:Atomicity(原子性),Consistency(一致性),Isolation(隔离性),Dura ...

  3. 今晚直播 | 高效视频理解模型的设计及ICCV比赛冠军方案解读

    「PW Live」是 PaperWeekly 的学术直播间,旨在帮助更多的青年学者宣传其最新科研成果.我们一直认为,单向地输出知识并不是一个最好的方式,而有效地反馈和交流可能会让知识的传播更加有意义, ...

  4. 直播预告 | 高效视频理解模型的设计及ICCV比赛冠军方案解读

    「PW Live」是 PaperWeekly 的学术直播间,旨在帮助更多的青年学者宣传其最新科研成果.我们一直认为,单向地输出知识并不是一个最好的方式,而有效地反馈和交流可能会让知识的传播更加有意义, ...

  5. 《深入理解Kafka:核心设计与实践原理》笔误及改进记录

    2019年2月下旬笔者的有一本新书--<深入理解Kafka:核心设计与实践原理>上架,延续上一本<RabbitMQ实战指南>的惯例,本篇博文用来记录现在发现的一些笔误,一是给购 ...

  6. 软件实训之深刻理解原型图设计的核心

    软件实训之深刻理解原型图设计的核心 内容关键词:  原型图设计 知识来源: 网络资源汇总整理.张森鹏讲课视频汇总整理 课程: 软件项目实训   授课老师:张森鹏(新浪ID:sunlifestyle,中 ...

  7. 《深入理解Android内核设计思想(第2版)(上下册)》之Android源码下载及编译

    本文摘自人民邮电出版社异步社区<深入理解Android内核设计思想(第2版)(上下册)> 购书地址:http://item.jd.com/12212640.html 试读地址:http:/ ...

  8. 细读《深入理解 Android 内核设计思想》(四)Binder 机制 [中]

    对冗余挑拣重点,对重点深入补充,输出结构清晰的精简版 智能指针 binder 驱动中的结构体 ProcessState IPCThreadState BpBinder BinderProxy Serv ...

  9. 细读《深入理解 Android 内核设计思想》(三)Binder 机制 [上]

    对冗余挑拣重点,对重点深入补充,输出结构清晰的精简版 1.必备知识 设备驱动 文件描述符 页框 2.Binder 概述 3.binder 驱动 binder_open binder_mmap bind ...

  10. 《深入理解Android内核设计思想(第2版)(上下册)》之Android源码下载及编译...

    本文摘自人民邮电出版社异步社区<深入理解Android内核设计思想(第2版)(上下册)> 购书地址:item.jd.com/12212640.ht- 试读地址:www.epubit.com ...

最新文章

  1. 2021年春季学期-信号与系统-第十五次作业参考答案
  2. leetcode算法题--划分为k个相等的子集★
  3. Python基础练习题,你会吗?
  4. java阻塞锁_java – 阻止锁与非阻塞锁
  5. 2003单网卡实现***,nat共享网络
  6. XMPP作为一个工具的意义
  7. 离散数学-欧拉图和哈密顿图
  8. linux系统能看抖音吗,在Linux系统下用XDroid来安装和运行抖音Android APP应用
  9. python苹果手机照片导入电脑_拯救你的16GB iPhone利用Seafile创建私有云将照片同步到PC上...
  10. Appium学习笔记16-按下、抬起、等待、移动、点击
  11. 微信外部链接无法使用浏览器打开 微信链接打不开的解决方案
  12. 科目二学车经验(手动挡C1)
  13. 传热学相关的无量纲数的物理意义
  14. 2018中文EI收录情况
  15. c语言函数指针的多种赋值方法
  16. Vuze(AKA Azureus) 4.5 发布
  17. asp微信登陆源码,实现asp网站授权微信登录(获取用户信息,微信名头像openid等)
  18. 2020华为勇敢星实习面经
  19. 驱动lvds双8位时钟_烧写液晶屏驱动软件识别
  20. 9.22 C语言自学笔记

热门文章

  1. 遗传算法实例(matlab编程实现)
  2. 北大核心期刊计算机排名,属于计算机技术类的北大核心期刊有哪些
  3. 打造地图拼接利器(一)前言
  4. 图的邻接矩阵求图的出度,入度,可达矩阵,判断强连通,弱连通,单向连通(C++,vs2017)
  5. 计算机职业核心素养,计算机专业人才核心素养研究-计算机专业论文-计算机论文(10页)-原创力文档...
  6. 网站采集软件,全自动网站文章采集器,一键网页数据抓取
  7. 利用DynamipsGUI制作BSCI课程实验拓扑
  8. 木马免杀实践-golang
  9. 惠普1020打印机查看已打印页数
  10. 网页游戏开发语言AS3(ActiveScript3.0)