显示标签为“插件”的博文。显示所有博文
显示标签为“插件”的博文。显示所有博文

2009年3月25日星期三

浏览器大战正当时

最近关于浏览器的新闻真可谓满天飞,这不IE8终于面世啦;Chrome1.0正式版也早已推出,Chrome社区正忙乎2.0及linux版本呢;Safari可也没闲着,才不久也来了个Safari4.0beta版,引得大众一番轰动;Firefox可也不断的忙乎着升级,从3.0一步一步升到3.0.7哪,以目前的势头可没暂停终止的迹象。。。

再说啦国内上网本可炒得不一乐乎,从供应商到硬件平台,甚至到用户的使用等等,可惜真正走到用户手中,或许还得要有些日子,其中一直让人好奇的是上网本究竟使用哪款浏览器内核,对用户而言仅仅上上网浏览浏览新闻、逛逛论坛、看看视频、参加参加网上社区就够了吗?有这样便宜的硬件平台及好用的浏览器吗?

如此林林总总让人目不暇接,于是在沉寂了一段时间之后,想借此机会总结总结自己的一些使用体会及对浏览器今后发展的一些看法。

一、各款浏览器大比拼
  • IE8
从IE8正式版本推出后的第一时间,就下载试用过它,经过一段时间的对比测试,第一时间使用的感受如下:
在浏览器大混战中IE8正奋力追赶,几乎没有独创或值得大说特说的新特性,几乎就是在模仿或抄袭其他浏览器受人欢迎的特性如多页签、多进程、web开发人员工具等;

IE8虽然在很多方面有所改进但仍然是IE系列浏览器,关键方面没有质的飞跃,好的方面有持续支持已有的框架、风格、设置、扩展等,令人诟病以久的W3C标准支持及推动仍举步艰难,这不ACID3测试还是保持在30分左右的水平呢?

经过一些测试发现其加载页面速度及占用资源方面,与Chrome相比仍然有一定的差距,总体而言Chrome要想超越IE系列浏览器关键要在扩展方式及应用方面向IE、Firefox学习,当然还要有用户推广方面更大的努力;

IE8虽然看起来步伐不是很快,但在其拥有庞大的用户基础之上进行稳步推进是非常值得肯定的,特别是它保持了对原有扩展的支持的基础之上,实现了多进程及安全方面的加强。从目前看来要想IE浏览器使用WebKit内核简直就是痴人说梦,忽悠忽悠而已,因为微软仍然对Web采取封闭而非开放合作的态度。。。
  • Chrome
Chrome浏览器自去年九月份推出以来就属当红炸鸡啦,赚足了眼球,当然Google及Chrome社区其实正不余遗力地加强Chrome浏览器的功能及满足用户的潜在需求及对广大网民的承诺,正与其一位开发人员所讲由于目前的浏览器太差,从而有想要开发浏览器的驱动力;

到目前为止其稳定性相比测试版本有了较大的提升,加载速度方面也算佼佼者啦,唯一的缺憾在于其扩展的支持,从其实现架构及WebKit内核来讲要达到类似IE ActiveX或Firefox Extension那样的方便也许难度不小;

令人值得称道的是其linux gtk版本或许不久就能面试啦,对linux用户来讲是一大福音;

  • Safari
Safari4.0beta版的发布有点出乎人们的意料,Apple在其网站Safari全新特色上对其特性进行过一番"吹嘘",通过仔细阅读其内容,发现Apple也似乎正努力的打造一款极具个性的Safari浏览器,其中从Chrome中学了不少东东如页签的位置、TopSite等,当然其中令人有趣的页签拖动还是独特的,还有类似的界面及操作风格延续了Apple的优良传统;

虽然其JavascriptCore内核没变,但起了个商业上的名称nitro,一时真让人莫名其妙,也许只要Apple自己知道改名的真正原因;

虽然其ACID3测试的得分在90分以上(Chrome80-90,Firefox70多一点),但其在Windows上的资源使用情况就没有宣称的那么好啦,特别是拥有Adobe flash的页面上;其架构上仍然没有使用多进程,与Firefox一样,但其消耗内存及CPU可比Firefox高的多,并且还不稳定,也许是Beta版的原因吧,看样其要想在Windows上分一杯羹难度不少;

那么Apple为什么还要"折腾"Safari哪?我想或许其算盘在Mac及iPhone上呢?Apple也许还担心哪天Chrome杀到Mac平台呢?要是现在不紧跟浏览器的发展,到那时Chrome壮大啦,自己又没有守住自己的领地哪滋味可就真不好受,再说Chrome使用的WebKit内核可是由Apple主导开发的呢?改个Javascript引擎的名字为Nitro,或许相比JavascriptCore、SFX起来,更好听,更像V8那样容易让人记住;

WebKit的发展来源于Apple,当然也离不开Apple,其对W3C标准的支持及扩展付出了极大的努力,这一点让人钦佩,特别是其对ACID3测试所作的努力及Javascript引擎实现方式的突破;

在这场浏览器大战中,没有Apple,没有WebKit,也就没有了大战的平台,虽然目前结果未知,但WebKit内核本身非常值得关注,也许WebKit内核的发展是大战成败的关键,有了Google、Apple、Adobe等的参与与使用,WebKit内核的市场份额经过大战之后肯定会得到大量的提升,其发展同样令人瞩目;

  • Firefox
Mozilla自从推出Firefox1.5,就逐步的从上一次失败的阴影中走出来,到了2008年推出Firefox3.0开始使用Gecko1.9,才让人真正的感觉到凤凰涅磐的滋味,那些家伙,狂热的技术追逐者,令世人刮目相看,其架构、其扩展性、其开放性、其开拓性,成为推动Web技术发展与应用的根本;

正可谓Firefox是这场浏览器大战的导火索,由一群对技术孜孜不倦的家伙发起对Web发展及应用的号角;这不其倡导的多页签、xul、xbl、npapi、cavas等,在Firefox上得到充分的应用与展现,有些方面IE、WebKit还在苦苦的追逐呢;网上有人评论Firefox离开了Google财务的支持,也许即将面临死亡,听起来有些骇然,从商业角度讲或许他是对的,但Mozilla社区对Web技术的开拓创新等却不会那么轻易的死掉,只要他们坚持这条道同时考虑考虑用户感受,先锋不会再次成为先烈,饿死的或许只会是那不思进取,抱残守缺的家伙。。。。

二、浏览器发展方向
浏览器的发展推动Web的发展与应用,同时Web的发展与应用促使浏览器更加的强壮,浏览器的发展离不开Web的发展,目前看来其发展方向应该在于:
  • 更加的标准化
也许IE被逼着卷入这场浏览器大战,不如说被逼着卷入标准化大战,Firefox、Chrome、Safari、Opera都自觉不自觉的坚持w3c标准,并且还不断的推动标准的发展,从目前的态势看Microsoft不得不应战,虽然极不情愿,也许大势所趋吧,识时务者为俊杰;

Firefox、WebKit正不遗余力的推动html5 video等标签、增加工作线程、跨域名XmlHttpRequest等,或许未来的标准就此产生;

  • 更加的开放
上面提及的几个浏览器大部分搭乘开源的顺风,实施开源,公开透明,行自由开放之风,这样Web的发展及应用或许更加的开放;

  • 更加的复杂
由于Web应用更加的复杂及多样性,对浏览器的要求及本地系统、硬件的要求越来越高,所以多进程的出现,从另一个侧面体现其复杂性及可靠性要求的提高。试想一个程序,它可使用来自世界各地形式各异的Web数据,同时尽可能的按照同样的方式展现给不同的用户,虽然有公共遵守的W3C标准,但要求其高效、可靠的完成,其实现本身的复杂性就可想而知了,如果Web数据进行更进一步的多样化,那其复杂度自然增加;

  • 小型设备化应用
由iPhone开启手机浏览互联网的新风,如火如荼的andriod、QtWebKit、Fennec、MiniOpera、UcWeb等正大力的拓展浏览器的嵌入式应用,上网本正是在这样的背景上进入人们的视眼,上网本还没火起来,曾经的维纳斯电视上网计划或许在不久的将来会真正的走进人们的客厅;这样看起来上面提到的浏览器大战似乎才刚刚开局呢。。。。


三、如何把握浏览器开发及商业应用
目前浏览器的开发主要体现在IE内核、Firefox Gecko内核、WebKit内核,从历史的角度看IE内核的扩展更加的容易,面对的PC用户庞大,但同样仅受限于windows平台使用;

针对Gecko内核,最近几年的extension快速扩展及应用普及加速了Firefox的发展与应用,并且得到一些开发者及网民的好评,同时其可应用于Windows、Mac、Linux平台,其扩展性令人赞叹;

而WebKit内核,发端应用于Mac平台Safari,名声大振于iPhone,Chrome的出现将其推到风口浪尖,其特性鲜明,虽然其移植性较好,可移植到不同平台,包括嵌入式应用,但其扩展性就没那么方便啦,有些平台对NPAPI插件的全方位支持也显得那么的难得,也许需要给他们一点时间吧,目前看来要想对其进行一定程度的开发难道还是不少。。。

从以前的历史经验中我们都知道浏览器这样一个软件,受到广大用户的青睐,可没有哪家大公司直接从中获得过与其实际地位相符的利润,包括免费捆绑销售的IE及Netscape等等,从这点看来与Office相比太令人惭愧啦,可见开发浏览器可不那么好赚钱,商业模式不是那么直接,那么写写扩展是否能获取一定回报哪,看看以前IE ActiveX的流行,或许能让我们打开一片联想的天地。

从更大的角度看,直接从浏览器本身来收取费用如Opera及以前的Netscape,是比较难的,关键得从应用服务来收费,如Firefox从内嵌Google搜索栏来获取收费,Adobe从嵌入的Flash插件来获取丰厚利润回报,但是一个好的扩展应用则需要对浏览器本身及其应用的充分理解。

也许上网本及各式各样的嵌入设备的出现再加上捆绑免费的浏览器,正是浏览器获取应用及回报的另一途径。

在浏览器扩展的同时及时提供优秀的Web应用或许是获取商业利润的又一方式,这或许是Google、IBM等大力推广云计算的良苦用心啦。

面对如此林林总总的方式,作为一个开源浏览器的爱好者,你找到了利用浏览器或其技术实现利润收入的方式了吗?也许大家还有更好的方式,不免大家一起分享分享。。。

2008年10月15日星期三

认识了解Gears

前一段时间对Google Chrome有过简单的认识与了解,在体验新鲜出炉的Google Chrome浏览器中提到Google的Google Chrome Comic,其中提出通过Gears来扩展Web应用,但究竟什么是Gears以及其如何来扩展浏览器等,一直令人好奇。通过了解Gears应该可以了解Google将来究竟主推怎样的方式来扩展Web应用,当然包括Chrome浏览器及Android等,因为个人一直认为Gecko内核对扩展的支持非常方便、灵活、实用(具体可参考与Gecko相关的文档),但对基于WebKit内核的扩展相对来说不是那么的方便与直接,为了满足探究感,让我们开始了解Gears之旅吧。

一、什么是Gears?
Gears is an open source project that enables more powerful web applications, by adding new features to web browsers.

目前主要提供一组JS API以供Web应用使用,对应Web开发者来说其类似于prototype、dojo、jquery等JS库,但其实现是通过扩展浏览器来实现(不仅仅包含js代码还包含二进制代码等)。

主要的API模块有:
  • A Database module (powered by SQLite) that can store data locally.
  • A WorkerPool module that provides parallel execution of JavaScript code.
  • A LocalServer module that caches and serves application resources (HTML, JavaScript, images, etc).
  • A Desktop module that lets web applications interact more naturally with the desktop.
  • A Geolocation module that lets web applications detect the geographical location of their users.

通过Google Gears可以了解Gears的发展及目前开发状态等,其中有些已实现或打算实现的API还是非常有意思的如Geolocation、Audio、Camera等,一旦这些API能完善好的话确实非常有利于Web应用的扩展,比如说录音、摄像等。

如果对扩展Web应用如开发RIA等有兴趣的话,可以好好考虑哪些应用或业务,可以或需要扩展到Web上来,通过了解Gears,说不定Gears能给您很大的启发。。。。

二、如何利用Gears?
利用Gears,首先需要用户安装Gears如对Firefox来讲就是一个extension,对Chrome、Safari来讲是一个符合NPAPI的插件,对IE来讲就是一个ActiveX;其次利用Gears API开发相关应用页面,以供最终用户使用。

也许对最终用户来讲稍嫌麻烦,需要额外安装程序,但如果Gears能象Flash一样实用、好用,那时就不再会觉得很麻烦啦。

对开发者来讲利用Gears相对就简单啦。在页面包含
<script src="gears_init.js"></script>
<script>
if (!window.google || !google.gears) {
location.href = "http://gears.google.com/?action=install&message=<your welcome message>" + "&return=<your website url>";
}
</script>
然后就可以使用其中的API啦。

具体可参考Gears Resources and Tools中的gears_init.js、samples及其他API等文档。


三、初步探究Gears基本实现原理
通过初步了解Get gears_init.js可以基本了解Gears提供对IE、Firefox、Chrome、Safari等支持,但其实现方式各有不同。

1、对各浏览器的支持
对Firefox来讲,Gears扩展了一个GearsFactory JS对象,可供JS脚本直接调用,从JS的角度看相对于给window对象新增了一个对象,就像原先的document、navigator对象一样使用,只不过其功能不同而已。

对IE来讲,Gears扩展了一个Gears.Factory ActiveX对象,可通过JS脚本new ActiveXObject('Gears.Factory');来直接调用,从JS的角度看可以象使用XMLHttpRequest对象一样使用Gears.Factory。

对Chrome、Safari来讲,就有点特殊啦,也有点诡异的感觉。需要在当前文档动态添加一个MIMEType为application/x-googlegears的Object插件对象,而这个Object对象就是对应的google.gears.factory对象。

从这里就可以看出WebKit对扩展JS的支持,从架构设计不是那么的直接,需要由NPAPI插件机制来中转实现;而Firefox、IE都从架构上提供了相应扩展机制来扩展,相当的直接明了及与浏览器本身的统一。

2、google.gears.factory对Firefox支持的实现
浅谈Gecko关键部分之六认识javascript实现及应用中我们可以了解到Gecko中XPCOM组件通过xpconnect及对DOMCLASSINFO的定义,就可轻松的将XPCOM组件Binding给JS使用,就像Gecko中对Components、Components.Interfaces、xmlhttprequest等的实现。

在Gears中就是使用了类似的方式来Binding一个GearsFactory组件给JS环境使用。其中实现了一个实现了GearsFactoryInterface接口的名称为GearsFactory,ContractId 为"@google.com/gears/factory;1"的组件,具体代码详见gears\factory\Factory_ff.cc,然后在gears\base\firefox\Module.cc中注册该组件时使用
catMgr->AddCategoryEntry(JAVASCRIPT_DOM_CLASS,
kGearsFactoryClassName,
kDomciExtensionContractId,
PR_TRUE, PR_TRUE, NULL);
将该组件声明为需要由xpconnect Binding给JS使用。一旦启用xpconnect,xpconnect就会作相应处理,具体可参考nsDOMClassInfo::RegisterExternalClasses()等方法。这样就完成JS GearsFactory对象的实现。

3、google.gears.factory对Safari支持的实现
浅谈WebKit之JavaScriptCore/V8篇中我们可以知道WebKit中将DOM实现Binding给Javascript实现往往通过generate-bindings.pl生成的代码来静态Binding,这种方式无法满足动态Binding的需求。但是从浅谈Gecko关键部分之九Plugin中我们了解到NPAPI插件接口提供了一组接口可以将插件的接口动态Binding给JS环境,同时可以让插件与JS之间相互调用。

而WebKit中实现了对NPAPI插件接口的支持,这样Gears中实现了一个mimetype为application/x-googlegears的插件,将该插件对象当作google.gears.factory JS对象来提供给页面使用。

具体可参考gears\base\npapi\Module.cc、Npp_bindings.cc,其中的NPP_New()方法应该是主要入口,同时设置该插件为windowless。至于如何将插件的方法动态Binding给JS使用,可具体参考Webkit中对NPN_CreateObject、NPClass的实现支持等。

4、google.gears.factory对IE支持的实现
按照创建ActiveX及BHO等接口方法来实现Gears.Factory ActiveX,进而将该对象赋值给google.gears.factory。具体关于ActiveX及BHO相关的知识参考Microsoft文档。

5、对其他API接口的实现
虽然google.gears.factory实现了create、getBuildInfo、version等接口,但对通过create创建出来的提供给开发人员用的localserver、geolocation、httprequest、audio等对象是如何实现的呢?

体现Gears强大及方便的地方就在这里。Gears提供了一组统一的类及接口实现可以方便将自定义的类及接口Binding给对应浏览器的JS实现。针对Firefox,它通过扩展SpiderMonkey的方式直接扩展JS实现;针对Safari,它还是使用NPAPI、NPObject的方式来扩展。

具体可以参考一下gears\base\common\Js_runner_np.cc、Js_runner_ff.cc、Js_runner_ie.cc等;

这一组统一扩展JS实现的类及接口有:ModuleImplBaseClass、ModuleWrapperBaseClass、DispatcherInterface、Dispatcher、MarshaledModule、ModuleEnvironment等,其作用就是按照统一的方式方便的将自定义的类及接口Binding给不同的浏览器实现。

如果对这方面有兴趣,可以对这些类及接口之间的关系及实现进一步研究,看Gears究竟是如何将C/C++类实现Binding给JS。其实这一点对JS来讲非常有意义,因为一旦可轻松方便的扩展JS,那么JS的应用就会进一步的扩大,就象python一样,python脚本可以方便扩充其模块,C/C++类库也可方便的扩充成python模块,从而让python几乎无所不能。


四、如何扩展Gears API?
在初步了解Gears实现原理之后,正与Gears CreatingNewModules所描述,我们也可以利用Gears来扩展自己的API,在了解其他API的实现基础上,其实扩展一个自己的Gears API难度似乎并不太大。。。

期望大家有时间可以加入到Google Gears中来一起拓展Web应用。。。

五、总结
通过对Gears的初步了解,觉得Gears对浏览器的扩展主要体现在对JS方面的扩展,相当于JS功能库的扩充,并且主要体现在非UI方面,虽然其中有部分UI方面的内容,但相当少;而Adobe推出的flash、Microsoft推出的Silverlight主要是按照插件的方式基于html标准的embed/object进行扩充,往往涉及到UI方面,并都有自身的特色如内嵌脚本语言、播放video/audio、网络处理等等;而Gecko所拥有的extension确可以是全方位的(包括UI、xpcom、插件等等)。

目前随着Ajax及RIA的推广,各式各样的JS库如prototype、dojo、jquery等也层出不穷,但是针对JS功能库方面的扩展还没有一个相对通用的国际标准,也许Gears正好抓住这样一个发展的趋势才采取这种通过扩展JS接口,为开发人员提供API的方式来扩展Web应用。

Gears API一方面迎合了RIA等方面的需求,另一方面也推动浏览器的扩展。但是它似乎抛弃了UI方面的扩展如使用Gecko的XUL、Microsoft XAML等的可能,也许flash对UI方面有太多的优势,同时html5中的video/audio逐步提上日程,做一个类似于Silverlight的插件意义不大,还不如在JS方面下足功夫,同时全面拥抱html(如gmail、gmap、gdoc等),也许这就是Google目前对扩展Web应用的一点看法吧。。。


六、参考资源
Gears Project
Wiki Gears(software)

2008年7月28日星期一

浅谈Gecko关键部分之九Plugin

Plugin作为一种对浏览器内核扩充的方式,为丰富浏览器应用提供了更加广阔的空间,如大家熟知的flash、java applet、window media player、vlc、adobe pdf等插件已经在人们的不知不觉中走到人们的生活当中,那么究竟什么是plugin?为firefox写的plugin能在其他浏览器中使用吗?如何为浏览器写plugin?浏览器实现plugin的机制及其基本原理如何?等等这些问题一直困扰在心头,现就这几方面来了解了解Gecko内核中的plugin实现等。

一、什么是plugin?
大家以前应该接触过一些关于plugin插件的概念,如eclipse就提供了很好的插件机制,以扩展ide的功能,apache也提供了丰富的插件机制,以丰富http server的处理请求。他们都有一个共同的特点就是以独立动态库的形式存在,动态库提供的输出接口应该满足主程序所规定的一些要求,以向主程序描述自身的特性及主要功能;而主程序也提供一组公共函数接口以供动态库调用,这样协同作业以完成任务。

在Gecko内核中plugin通过扩展html标签embed、object的MIMEtype类型的方式来拓展显示在一个页面中指定区域的内容。如大家熟知的application/x-shockwave-flash、application/x-java-applet、application/x-vlc-plugin等等,每一个plugin须说明自身所能支持的mime类型。一旦页面中遇到指定标签embed或object的mime类型,gecko内核就会搜索它目前所能支持的mime类型及对应的plugin,然后调用plugin中输出的接口由plugin来完成指定区域内的内容显示。

在Gecko内核中,就扩展的方向及方式的不同,plugin与xpcom拥有本质上的差别,plugin以扩展页面embed/object标签 mime类型的方式存在,往往与页面布局渲染相关,而xpcom是以扩展不同的组件种类,以实现不同内部功能的方式存在,它往往有更大的扩展空间包如字符串管理、线程管理、p2p传输管理等。他们的应用场景有本质上的差别,一般说来plugin相对内核而言更加独立如可以有独立的线程管理、内存管理、渲染方式等,而xpcom往往是内核中的一个组成部分。

Gecko内核plugin机制的实现接口Netscape Plugin Application Programming Interface
简称为NPAPI,它提供了相当完备的跨平台的接口框架,其中包括对Stream、Security、Scripting等方面的支持,目前包括Firefox、Opera、Safari、部分IE等浏览器都支持符合NPAPI接口标准的插件来扩展浏览器的功能。

二、如何编写plugin?
为了能编写plugin,首先需要了解其主要API,下面四个函数接口往往需要由plugin实现并export出去,可由外部即浏览器内核调用。
NPError WINAPI NP_Initialize(NPNetscapeFuncs* pFuncs);
当该plugin动态库第一次加载后浏览器内核会调用该方法,其中参数为当前内核提供给plugin调用的函数接口,plugin往往会将这些接口保存下来,以待以后使用;

NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pFuncs);
浏览器内核初始plugin动态库后,会调用该方法以获取该plugin实现的接口函数,内核会根据具体情况的不同来调用该plugin提供的不同接口函数;

NPError WINAPI NP_Shutdown();
当浏览器内核需要释放该plugin动态库时会调用该方法以告诉plugin其将会被释放;

char* NP_GetMIMEDescription(void);
浏览器内核通过该方法可获得该plugin支持的MIME类型,以便在解析页面embed/object标签时匹配其Type是否由哪个plugins来支持;

typedef struct _NPPluginFuncs {
uint16 size;
uint16 version;
NPP_NewUPP newp;
NPP_DestroyUPP destroy;
NPP_SetWindowUPP setwindow;
NPP_NewStreamUPP newstream;
NPP_DestroyStreamUPP destroystream;
NPP_StreamAsFileUPP asfile;
NPP_WriteReadyUPP writeready;
NPP_WriteUPP write;
NPP_PrintUPP print;
NPP_HandleEventUPP event;
NPP_URLNotifyUPP urlnotify;
JRIGlobalRef javaClass;
NPP_GetValueUPP getvalue;
NPP_SetValueUPP setvalue;
} NPPluginFuncs;

typedef struct _NPNetscapeFuncs {
uint16 size;
uint16 version;
NPN_GetURLUPP geturl;
NPN_PostURLUPP posturl;
NPN_RequestReadUPP requestread;
NPN_NewStreamUPP newstream;
NPN_WriteUPP write;
NPN_DestroyStreamUPP destroystream;
NPN_StatusUPP status;
NPN_UserAgentUPP uagent;
NPN_MemAllocUPP memalloc;
NPN_MemFreeUPP memfree;
NPN_MemFlushUPP memflush;
NPN_ReloadPluginsUPP reloadplugins;
NPN_GetJavaEnvUPP getJavaEnv;
NPN_GetJavaPeerUPP getJavaPeer;
NPN_GetURLNotifyUPP geturlnotify;
NPN_PostURLNotifyUPP posturlnotify;
NPN_GetValueUPP getvalue;
NPN_SetValueUPP setvalue;
NPN_InvalidateRectUPP invalidaterect;
NPN_InvalidateRegionUPP invalidateregion;
NPN_ForceRedrawUPP forceredraw;
} NPNetscapeFuncs;
NPPluginFuncs、 NPNetscapeFuncs结构中的函数接口分别由plugin和浏览器内核提供实现,而让对方调用。每个接口的具体含义及什么时候调用可参考下面提到的相关资源。

三、Gecko内核的plugin实现机制及基本原理
Gecko内核作为外部调用plugin的主程序,它不仅提供一组NPNetscapeFuncs函数接口给plugin调用,同时需要管理所有的plugin动态库、针对不同embed/object创建不同的plugininstance以及相关安全、创建窗口句柄、释放资源等。

在Gecko内核中提供了如下几个主要头文件、接口及类来完成相关任务。
\mozilla\modules\plugin\base\public\Npapi.h
\mozilla\modules\plugin\base\public\Npupp.h
\mozilla\modules\plugin\base\public\Npruntime.h
这几个头文件包含实现plugin所需要的函数接口、常量定义、数据结构定义等;

nsIPluginTag.idl
主要代表一个plugin动态库基本信息包括文件名、描述等;
nsIPluginTagInfo.idl/nsIPluginTagInfo2.idl
主要代表一个embed/object标签所描述的内容如MIME类型、参数、宽高等;
nsIPlugin.idl
主要描述一个plugin动态库所对应的initialize、shutdown、getMIMEDescription、getValue及创建plugin实例方法createPluginInstance,相当于plugin动态库加载后该plugin所提供的函数入口等;
nsIPluginInstance.idl
主要描述一个plugin动态库所实现的一个plugin实例所对应的函数接口,如initialize、start、stop、destroy、setWindow、newStream、getValue、handleEvent等;
nsIPluginHost.idl
主要描述如何装载plugin动态库、实例化EmbededPlugin、FullPagePlugin、检查指定MIME类型是否有对应plugin来实现等;

由类nsPluginHostImpl来代表"@mozilla.org/plugin/manager;1"、"@mozilla.org/plugin/host;1"来管理plugin等;它主要实现了接口nsIPluginHost、nsIPluginManager2等,提供了
void loadPlugins();
nsIPlugin getPluginFactory(in string aMimeType);
void instantiateEmbeddedPlugin(in string aMimeType, in nsIURI aURL, in nsIPluginInstanceOwner aOwner);
void setUpPluginInstance(in string aMimeType, in nsIURI aURL, in nsIPluginInstanceOwner aOwner);
void stopPluginInstance(in nsIPluginInstance aInstance);
等主要方法;

由类ns4xPlugini来实现nsIPlugin接口,其中维护了上面提到的函数接口
NPPluginFuncs fCallbacks;
PRLibrary* fLibrary;
NP_PLUGINSHUTDOWN fShutdownEntry;
/**
* The browser-side callbacks that a 4.x-style plugin calls.
*/
static NPNetscapeFuncs CALLBACKS;

在nsPluginHostImpl.cpp中通过static nsActivePluginList *gActivePluginList;来维护一组当前活动的plugin
class nsActivePluginList
{
public:
nsActivePlugin * mFirst;
nsActivePlugin * mLast;
PRInt32 mCount;
................................
};

struct nsActivePlugin
{
nsActivePlugin* mNext;
char* mURL;
nsIPluginInstancePeer* mPeer;
nsRefPtr mPluginTag;
nsIPluginInstance* mInstance;
PRTime mllStopTime;
PRPackedBool mStopped;
PRPackedBool mDefaultPlugin;
PRPackedBool mXPConnected;
//Array holding all opened stream listeners for this entry
nsCOMPtr mStreams;
.........................................
};

由nsPluginHostImpl、ns4xPlugin及nsActivePluginList等类能够维护好plugin动态库的加载、创建一个新plugin实例等,哪究竟是由谁来加载动态库、创建新的plugin实例呢?

作为一个html embed/object标签,其对应的元素为nsHTMLObjectElement,其继承自nsGenericHTMLFormElement、nsObjectLoadingContent、nsIDOMHTMLObjectElement,其中nsObjectLoadingContent提供了下面主要的方法
nsObjectLoadingContent::LoadObject(const nsAString& aURI,
PRBool aNotify, const nsCString& aTypeHint, PRBool aForceLoad)

nsresult nsObjectLoadingContent::TryInstantiate(const nsACString& aMIMEType,
nsIURI* aURI)

而nsHTMLObjectElement往往对应有nsObjectFrame;其中包含有 nsRefPtr mInstanceOwner;

而nsPluginInstanceOwner中含有如下元素:
nsPluginNativeWindow *mPluginWindow;
nsCOMPtr mInstance;
nsObjectFrame *mOwner;
nsCOMPtr mContent;
nsCString mDocumentBase;
char *mTagText;
nsCOMPtr mWidget;
nsCOMPtr mPluginTimer;
nsCOMPtr mPluginHost;

有了对基本的数据结构理解之后这样在parser html内容时,会根据embed/object标签创建nsHTMLObjectElement、nsObjectFrame、nsPluginInstanceOwner等实例,进而在nsHTMLObjectElement的LoadObject方法驱动下逐步的调用TryInstantiate、Instantiate、InstantiateEmbeddedPlugin、TrySetUpPluginInstance、Create4xPlugin等等,从而完成一个plugin实例的生成等。

至于其Scripting、Stream、security方面的支持须进一步参考nsIDOMClassInfo、nsGenericHtmlObjectSH及nsIPluginStreamListener等;

四、总结
通过初步了解plugin的实现机制后,然后自己动手参照Mozilla提供的plugin examples及相关API,完成一个基本的Plugin难度其实并不大,但是如想利用plugin技术实现如3D、Stream Media、叠加等方面的效果,须更进一步的了解3D、Stream Media等方面的内容。其实支持Gecko内核的Plugin相当多,如主流的播放器、flash、java applet、silverlight等等都有浏览器插件,再加上支持Gecko内核的plugin一般也支持Opera、Safari,这样如果我们掌握了NPAPI Plugin技术,那么我们就可以充分运用已有的plugin或自己动手创建一个好用的plugin,这样会大大的扩展浏览器的应用,让我们拭目以待吧。。。。。

五、参考资源
WIKI NPAPI
Mozilla projects -plugins
Mozilla developer center -plugins
Netscape Gecko Plugin API Reference
Mozilla Plugin Support on Microsoft Windows