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

2008年10月8日星期三

浅谈WebKit之Port篇

WebKit作为一个浏览器引擎,其相对于Gecko而言一个较大的特点就是便于移植,嵌入到其他程序中,目前大家已了解使用WebKit引擎的应用包括Safari、iPhone、Chrome、Android、Nokia S60 Browser及KDE QT4.4等,同时还有其他方面的移植如Gtk、wxWidget、3D等,可以说WebKit从架构上讲其Port移植方面的设计及应用,是非常优秀的。这一点相对于Gecko有相当大的优势,有时间可以参考一下浅谈Gecko关键部分之十二Embedding。为了更深入的了解WebKit,我们现在就从WebKit有关Ports方面入手,了解其有关Port方面的设计,从而了解究竟如何能移植WebKit到自己的应用中。

一、有关Port方面的概述
在通过了解浅谈WebKit之WebCore篇之后,应该说WebKitPort方面的内容是可以很广的,例如可将不同的图形库、网络库与WebCore集成,提供不同的Port接口供外部程序使用等,例如同样在windows平台上可以运行的Google Chrome和Safari就是针对WebKit的不同移植。

我们想了解有关Port方面的主要内容在于提供不同的Port接口供外部程序使用以及如何与外部程序交互,因为WebKit中的其它两部分WebCore、Javascript实现,从逻辑上讲是不直接提供接口给外部程序使用的。同时为了完成浏览器的核心功能,WebKit也需要从外部程序中通过Port接口的方式获取一些支持。

从这个角度讲WebKit作为一个相对独立的整体,它与外部程序之间的交互也就有一组相对固定的接口来定义及维护它们之间的关系,它们之间的关系与插件跟浏览器引擎之间的关系完全类似,接口相当一组协议,有的是由WebKit来实现,而供外部程序调用;有的的正好相反。

通过前面的了解我们知道WebKit的主要功能集中在分析Html、渲染布局Web内容以及Javascript实现方面等,而这些Web内容显示在哪个窗口及消息处理的启动循环等都需要由外部程序来提供。

二、初步分析已有WebKit Port移植实现
1、与WebCore交互接口的实现
在WebKit源代码目录结构中WebKit目录下分别包含gtk、mac、qt、win、wx目录,其分别对应不同的Port移植方式,在每一个目录下面都包括WebCoreSupport目录,而在不同的WebCoreSupport目录下分别包含有对类接口WebCore::ChromeClient、WebCore::ContextMenuClient、WebCore::DragClient、WebCore::EditorClient、WebCore::FrameLoaderClient、WebCore::InspectorClient等的实现,它们代表外部程序提供给WebKit内部使用的接口实现,其中WebCore::ChromeClient、WebCore::FrameLoaderClient非常重要。

初步了解其接口定义能基本了解其对应的含义,这些接口往往需要由Port移植部分来提供实现,往往由WebKit内部根据一定的条件来调用。下面初步来了解几个主要接口:

WebCore::ChromeClient接口:
//往往在运行window.open脚本时调用,以便由外部程序决定如何打开一个新页面如新建一个窗口、新建一个Tab页签等;
virtual WebCore::Page* createWindow(WebCore::Frame*, const WebCore::FrameLoadRequest&, const WebCore::WindowFeatures&);

//通知外部程序显示页面;
virtual void show();

virtual bool canRunModal();

//通知外部程序以Modal的方式显示页面;
virtual void runModal();

//通知外部程序显示JS警告提示窗口;
virtual void runJavaScriptAlert(WebCore::Frame*, const WebCore::String&);

//通知外部程序显示JS警告确认窗口;
virtual bool runJavaScriptConfirm(WebCore::Frame*, const WebCore::String&);

WebCore::FrameLoaderClient接口:
//检查是否拥有主页面窗口;
virtual bool hasWebView() const;
//检查是否拥有页面窗口;
virtual bool hasFrameView() const;

//通知外部程序有关http请求开始、结束、获取数据等,如通常浏览器状态栏显示的信息;
virtual void dispatchDidReceiveResponse(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceResponse&);
virtual void dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int lengthReceived);
virtual void dispatchDidFinishLoading(WebCore::DocumentLoader*, unsigned long identifier);
virtual void dispatchDidFailLoading(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceError&);

//通知外部程序WebKit内部主要事件处理,以便外部程序及时响应或创建维护数据等
virtual void dispatchDidHandleOnloadEvents();
virtual void dispatchDidReceiveServerRedirectForProvisionalLoad();
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate);
virtual void dispatchDidChangeLocationWithinPage();
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
virtual void dispatchDidReceiveTitle(const WebCore::String&);
virtual void dispatchDidCommitLoad();
virtual void dispatchDidFinishDocumentLoad();
virtual void dispatchDidFinishLoad();
virtual void dispatchDidFirstLayout();

//告诉外部程序需要提供切换到一个新页面状态。此时外部程序往往会新建FrameView,并将FrameView与Frame关联,设置原生窗口句柄及其消息处理机制等等;
virtual void transitionToCommittedForNewPage();

//告诉外部程序创建一个新的Frame,如遇到html中iframe标签时,需要外部程序创建一个新的Frame及原生窗口句柄等;
virtual PassRefPtr createFrame(const WebCore::KURL& url, const WebCore::String& name, WebCore::HTMLFrameOwnerElement* ownerElement,
const WebCore::String& referrer, bool allowsScrolling, int marginWidth, int marginHeight);

//告诉外部程序需要创建一个Plugin实例,从而创建其原生窗口等等;
virtual WebCore::Widget* createPlugin(const WebCore::IntSize&, WebCore::Element*, const WebCore::KURL&, const Vector&, const Vector&, const WebCore::String&, bool loadManually);

2、对WebCore中的page/loader等方面的类提供对应Port的实现支持
如EventHandlerWin.cpp、FrameLoaderWin.cpp、DocumentLoaderWin.cpp、DocumentLoaderWin.cpp、WidgetWin.cpp、KeyEventWin.cpp等

3、实现WebView及WebFrame等以便外部程序嵌入WebKit
不同的Port移植对WebView及WebFrame的定义及实现有所不同,但其与WebCore中的Page、Frame之间的关系大致与浅谈WebKit之WebCore篇图一描述相一致。

具体关于WebView、WebFrame的定义与实现,特别是初始化时的动作可根据不同的Port移植而有所不同,同时初始化时会将上面提到的WebCore Port接口实现告诉WebKit内部。主要示例代码如下:
static void webkit_web_view_init(WebKitWebView* webView)
{
WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
webView->priv = priv;
priv->corePage = new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient(webView), new WebKit::EditorClient(webView), new WebKit::DragClient, new WebKit::InspectorClient);
priv->mainFrame = WEBKIT_WEB_FRAME(webkit_web_frame_new(webView));
priv->lastPopupXPosition = priv->lastPopupYPosition = -1;
priv->editable = false;
................................

priv->webSettings = webkit_web_settings_new();
webkit_web_view_update_settings(webView);
..................................
}

WebKitWebFrame* webkit_web_frame_new(WebKitWebView* webView)
{
g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);

WebKitWebFrame* frame = WEBKIT_WEB_FRAME(g_object_new(WEBKIT_TYPE_WEB_FRAME, NULL));
WebKitWebFramePrivate* priv = frame->priv;
WebKitWebViewPrivate* viewPriv = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);

priv->webView = webView;
priv->client = new WebKit::FrameLoaderClient(frame);
priv->coreFrame = Frame::create(viewPriv->corePage, 0, priv->client).get();
priv->coreFrame->init();

return frame;
}

4、Chrome中对Port移植方面的实现
其基本上与其他Port移植类似,其主要代码在webkit\glue目录中,可重点关注带client_impl.cc后缀的文件、webview_impl.cc、webwidget_impl.cc等;但是其究竟如何创建原生windows窗口、如何创建Render进程、Render进程与创建的原生windows窗口的关系如何等需要更进一步深入研究Chrome,如果能从上面提到的Port部分入手也许很快就可得到答案,这一点以后有机会单独研究。

5、Android中对Port移植方面的实现
其实现有点特殊,
由于Andriod将WebKit以一个Java类接口的方式提供给Java环境使用(不像上面提到的Chrome、Safari等都是将WebKit以 一个C++动态或静态库的方式供C/C++外部程序调用),这样WebKit内部与外部即JavaVM的交互(如上面提到的ChromeClient、 FrameLoaderClient接口实现)需要一个Bridge类来协调处理,同时WebView、WebFrame接口绑定给JavaVM的jni接口实现也需要通过这个Bridge来支持协调处理。具体可详细参考android源码代码中WebCore\platform\android目录下的源文件。

6、通过进一步了解WebCore Port接口及其实现,可以加深这样一个认识:
如果
从MVC的角度来看整个基于WebKit的浏览器(当然不尽合理),WebKit的Port部分相当于V部分,它提供显示页面内容及其辅助信息(如提示状态)的场所(即原生窗口)以及控制该显示场所的状态变化及消息响应(如改变大小、鼠标移动等);而M部分往往由WebCore来实现,至于WebCore如何组织DOM则往往由htmlparser部分根据DOM定义来组织,如何在提供的显示场所显示Web内容则往往由WebCore中的layout部分来实现,其中充分利用了Css定义来布局显示该显示的内容;一旦涉及控制或动态处理往往由Port部分发起而由Javascript脚本来实现处理,其任务由JavascriptCore或V8来完成。

一般说来新打开一个页面,Port部分需要提供一个主显示场所(即原生窗口),如果页面中含有iframe标签,则需要在主显示场所内创建一个子显示场所,以显示iframe标签对应src的内容;如果页面中含有embed/object等插件标签同样往往也需要
在主显示场所内创建一个子显示场所(除非windowless),以交由插件实现在提供的显示场所中显示内容。

特别需要说明的是我们通常看到的页面表单元素input text field、textArea、button、radiobutton等往往不像window图形库中的按钮、菜单、输入框等会对应一个原生窗口,页面中的表单元素在一个显示场所(即原生窗口)中完全是利用Css等通过layout方式来达到我们所看到的类似原生按钮、输入框、列表框、滚动条等效果,其中特别是能准确定位元素大小、设置focus、光标显示、响应事件等,这充分的说明了浏览器引擎内部布局部分的威力所在。

从另外一个角度来看一个页面一般说来(除非遇到iframe或插件需要另外提供一块子画布)相当于一块画布,浏览器引擎能在其精确的位置绘制不同颜色的文字、图片、图标等,同时根据当前的鼠标及一个模拟的输入提示光标位置,接收键盘输入操作。页面中的绝大多数元素与原生的窗口元素几乎没有关联,完全通过组合、布局、准确定位来处理一切。。。

三、如何利用WebKit?
了解WebKit Port部分,对我们如何利用WebKit有非常现实的意义,目前已经将WebKit移植到多种平台如windows、qt、gtk、mac、wx、java、framebuffer等,甚至移植到python、ruby及3D等环境中去。通过借鉴或利用这些已有的WebKit Port实现,完全可以将WebKit发扬广大。

前一阶段正好得到一个网友抓取网页的需求,试想目前移植利用WebKit基本都用来显示页面,往往涉及图形显示方面,但随着ajax及动态页面的广泛使用,未来动态生成的页面越来越多,传统的搜索引擎仅仅抓取静态的页面内容显然是不够的,现代化的搜索引擎应该能抓取动态的页面内容,这样它从某种意义讲相当于一个能获取对应的动态页面但不真正显示出其内容的浏览器,这样一个搜索引擎不仅能分析DOM树,同时能运行Javascript脚本(如运行ajax),以真正完整获取页面内容,其实这样一个搜索引擎如果利用WebKit来实现的话,应该是个不错的选择,在我们了解WebKit Port部分之后,我们是否可以来模拟一个不真正具备图形显示方面的Port,进而充分利用WebKit中的WebCore及Javascript实现方面的功能呢?一点想法,今后有机会可以试试,或许Google、Yahoo的搜索引擎已经有了相关的实现,不知是否使用的就是WebKit?应该不会,有谁清楚的话,烦请通知一声。

但愿我们也能利用利用WebKit整出一个象模象样的东东如机顶盒浏览器、手机浏览器等等。。

四、参考资源
The WebKit Open Source Project
Google Chrome Home
Android - An Open Handset Alliance Project

2008年8月17日星期日

浅谈Gecko关键部分之十三Xulrunner

Gecko内核作为一个浏览器内核,为了能充分利用其已有的功能,Mozilla提供了一个可作为运行环境平台的Xulrunner,来扩展Gecko内核的应用。那么究竟什么是Xulrunner、如何实现一个Xulrunner应用程序、它和Firefox、ThunderBird等有什么区别、目前有哪些应用基于Xulrunner等等,通过下面的学习研究,希望能逐步的解答这些疑问。

一、什么是Xulrunner?
XULRunner is a Mozilla runtime package that can be used to bootstrap XUL+XPCOM applications that are as rich as Firefox and Thunderbird. It will provide mechanisms for installing, upgrading, and uninstalling these applications. XULRunner will also provide libxul, a solution which allows the embedding of Mozilla technologies in other projects and products.

其实质上是一个运行环境,类似于java虚拟机、Adobe AIR、Yahoo! Widget等,只不过它目前支持xul、xpcom、js、html等,而其他的运行环境大都有其对应的支持格式及实现方式等。有了Xulrunner,为开发Rich Internet application提供另一种实现方式。

Xulrunner基于Gecko内核,充分利用了其功能及实现方式,而Gecko内核的功能、性能及实现方式等在Firefox中得到了充分的体现与运用。这样Xulrunner应用程序基本上完全可以应用Firefox所拥有的功能。

二、如何实现一个Xulrunner应用程序
1、下载、安装Xulrunner;

2、创建应用目录结构,设置应用application.ini及chrome manifest;
application.ini内容大致如下:
[App]
Vendor=***
Name=Bamboo
Version=1.0
BuildID=2008052906
Copyright=Copyright (c) 1998 - 2008 mozilla.org
ID={ec6039f7-c60a-784f-9b0e-23b3a9e67323}
[Gecko]
MinVersion=1.9
MaxVersion=1.9
[XRE]
EnableProfileMigrator=1
EnableExtensionManager=1
[Crash Reporter]
Enabled=1
ServerURL=https://crash-reports.mozilla.com/submit

其中ID表示xulrunner应用的唯一ID,在编写extension时须指定该extension能够应用的目标程序,在其install.rdf的targetApplication项的ID中指定已知的应用ID(也即xulrunner应用在其application.ini中指定的ID)。如Firefox的应用ID为{ec8030f7-c20a-464f-9b0e-13a3a9e97384}。

3、创建xul、js文件;

4、设置应用选项;
在pref.js中指定Xulrunner应用程序启动的主窗口,如
pref("toolkit.defaultChromeURI", "chrome://myapp/content/main.xul");

5、运行Xulrunner应用程序;
.\xulrunner\xulrunner.exe application.ini

具体参考
Getting Started with XULRunner


三、Xulrunner和Firefox、ThunderBird等有什么区别?
Xulrunner作为一个运行环境,以供他人开发基于Xulrunner、基于Gecko内核的应用程序,从Gecko1.9以后,从严格的意义来讲,Firefox、ThunderBird等是基于Xulrunner而开发的,也是一个Xulrunner应用,只不过它得到Mozilla官方的支持,它是浏览器。

Mozilla在开发Firefox、Xulrunner、Gecko内核的过程中,不断的相互扩充,相互优化,相互促进,往往一个Firefox主要版本都对应一个Xulrunner版本,Xulrunner、Firefox对某一特性的支持程度有时有一些略微不一致,往往是由于对应版本未及时更新而造成的。

自Firefox3.0以来,通过firefox.exe -app application.ini的调用方式同样可以运行一个Xulrunner应用,只不过此时该Xulrunner应用的Gecko内核是当前Firefox对应Gecko内核。

到目前为止不同组织开发了许多基于Xulrunner的应用,如比较著名的有Songbird、Joost、Miro等等。

具体可参考
XULRunner Hall of Fame

四、开发Xulrunner应用程序与Embedding Gecko有什么不同?
以基于Xulrunner的方式开发应用,可以充分利用Gecko内核的所有功能(包括xul、xpcom、js等等),入手比较简单,对开发者而言,只须专注实现自身所关心的部分,但要想真正开发出好的应用,需要对Gecko内核的方方面面拥有较深入的理解,难度较大,虽然其符合许多W3C标准,但Gecko内核的各个方面都自成一个体系(特别是xpcom),与其他的库及开发平台的接口相对较少。同时Mozilla目前也推荐开发人员以运行平台的方式来利用Gecko内核。

通过Embedding Gecko的方式来利用Gecko内核,其实现方式和可利用的外部库等都比较灵活,不一定只限于与Gecko相关的实现方式或外部动态库,其往往将Gecko内核作为一个相对独立的外部库使用,但由于目前Gecko内核在Embedding方面的接口有限,不能让外部程序充分利用Gecko内核的功能,从而限制了外部程序对其利用,同时如只利用Gecko内核中浏览页面的部分功能,而需要嵌入整个Gecko内核,有点得不偿失。

究竟是使用Xulrunner的方式还是使用Embedding Gecko的方式来利用Gecko内核?
这就存在一个取舍的问题,如只须嵌入浏览页面的功能,嵌入IE内核或Webkit内核,肯定方便很多,嵌入Gecko内核,稍现复杂,但嵌入的功能都相对有限;想更进一步了解嵌入Gecko内核的内容,可参考浅谈Gecko关键部分之十二Embedding一节。

如使用Xulrunner的方式来利用Gecko内核,则须完全拥抱Xulrunner平台,可利用的功能丰富强大,需要学习研究的难度曲线较大,但是Mozilla毕竟是一个开源组织,其是否能提供一个高质量的可商用的运行环境,存在一定风险,有可能没有Microsoft、Adobe等商业公司提供的平台那样得到更广泛的支持。虽然如此,但其开放程度及对Web技术趋势的创新是独一无二的,再说目前其提供的文档越来越规范,应用越来越多。

五、总结
总的说来,如想真正深入的了解Web技术或浏览器,使用Xulrunner是个非常好的选择,但代价可能较高,如一旦真正掌握,则至少Web技术实力会很强;

如只是利用Web技术或浏览器,完全可抛开Gecko内核,利用IE内核或Webkit内核,来运用Web技术,但对Web技术的真正把握可能不是很深入;

作为一个开源爱好者,想更深入了解Web技术或浏览器,作手学习研究使用Firefox、Xulrunner等Gecko内核相关应用程序,是个不错的选择,因为它提供了很多非常不错的Web技术及工具如ajax、firebug、xul、venkman等;经过一定时间的运用,一定会收获颇多!

六、参考资源
Mozilla Developer center -XULRunner
Wiki XULRunner
What XULRunner Provides
XULRunner FAQ

2008年8月5日星期二

浅谈Gecko关键部分之十二Embedding

随着Gecko内核的广泛使用,人们会期望Gecko内核能作为一个相对独立的拥有能访问Web、解析Html、渲染页面等浏览器基本功能的动态库甚至作为一个ActiveX或GtkWidget以供其他程序将其嵌入,就像大家熟知的MyIE作为一个外壳程序将IE内核以ActiveX的方式嵌入到其中,这样外壳程序相对简单,往往基于应用层,而内核则专注于html、css、dom等浏览器核心部分的处理,一旦能将浏览器内核以相对固定相对简单的接口形式提供给外部程序使用,则会大大拓展其应用包括动态脚本语言如python、perl、ruby都可能将其应用其中,其他的外壳程序也会应运而生。其实IE内核及Safari内核Webkit都提供了相对简单固定的接口供外部调用,这样才有了MyIE及Safari。那么Gecko内核是否也有类似的接口,外部程序又是如何嵌入的,这些与IE内核及Webkit等有什么差别呢?

一、认识Embedding接口
Gecko内核作为相对独立的部分嵌入到外部程序中,在本质上外部程序与Gecko内核的关系其实很类似Plugin与Gecko内核的关系,外部程序与Gecko内核需要分别实现一些接口,各负其责,以供对方调用,这样两者相互结合实现所要的功能。不过Gecko内核官方目前提供给外部调用的接口封装得不是很简单,使用起来也不是非常的方便,但通过对GTKMozEmbed、winEmbed等的了解,Gecko内核部分往往通过nsWebBrowser来实现public nsIWebBrowser、nsIWebNavigation、
nsIWebBrowserSetup、nsIDocShellTreeItem、nsIBaseWindow、nsIWebBrowserPersist、nsIWebBrowserFocus、 nsIWebProgressListener等接口,以代表一个浏览器页面浏览实例;

而外壳程序部分需要实现nsIWebBrowserChrome、nsIEmbeddingSiteWindow、nsIWebProgressListener、nsISHistoryListener、nsIContextMenuListener等接口以代表一个浏览器页面浏览外壳,供Gecko内核调用。

其中nsWebBrowser初始化后通过setcontainerWindow来设置其nsIWebBrowserChrome containerWindow为其对应的外壳实现,然后通过InitWindow、Create等方法可真正创建一个浏览器页面浏览实例,而外壳实现通过设置其nsIWebBrowser webBrowser为前面初始化的nsWebBrowser实例,这样两者可互为引用,同时外壳部分可向nsWebBrowser添加一些如WebProgress、ContextMenu等listener,以供Gecko内核nsWebBrowser需要时调用通知。

另外外壳部分需要实现接口nsIWindowCreator,并通过调用window watch service的方法setWindowCreator来告诉window watch service由外壳部分来createChromeWindow,以保证内核在由页面脚本通过window.open来打开新窗口时统一由外壳部分来创建新开的窗口。

上面提到的是Gecko内核为了实现Embedding,需要由内核部分与外壳部分分别实现的基本接口及相关调用关系,其中Gecko内核还提供有诸如NS_InitEmbedding、NS_TermEmbedding等XPCOM方面的接口以供外壳部分充分利用Gecko内核提供的XPCOM强大组件管理等功能。

为了更方便外壳程序的调用,Gecko也提供了诸如GtkMozEmbed widget及MozApp、MozView、 MozViewListener等,其实质仍属于上面提到的外壳部分,只不过更加的方便用户使用罢了。

二、外部程序如何嵌入Gecko内核
为了能真正了解如何将目前的Gecko内核嵌入到外部程序中,最好还是先参考Roll your own browser - An embedding HowTo按照其提供的编译方式,了解TestGtkEmbed、mfcEmbed等实现。通过对这些实例的了解才能对嵌入Gecko内核有一定的了解。

外部程序嵌入Gecko内核的主要步骤如下:
1、通过NS_InitEmbedding初始化内核;
2、通过 do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv)创建mWebBrowser;
3、创建实现nsIWebBrowserChrome、nsIEmbeddingSiteWindow接口实例mpBrowserImpl;
4、创建绑定窗口
mpBrowserImpl->Init(mpBrowserFrameGlue, mWebBrowser);

mWebBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome*, mpBrowserImpl));

nsCOMPtrsetup(do_QueryInterface(mWebBrowser));
if (setup)
setup->SetProperty(nsIWebBrowserSetup::SETUP_IS_CHROME_WRAPPER,PR_TRUE);

rv = mBaseWindow->InitWindow(nsNativeWidget(m_hWnd), nsnull,0, 0, rcLocation.right - rcLocation.left, rcLocation.bottom - rcLocation.top);
rv = mBaseWindow->Create();

5、添加监听
void mWebBrowser->AddWebBrowserListener(weakling, NS_GET_IID(nsIWebProgressListener));

6、设定WindowCreator、preference及promptservice等;

7、装载页面mWebNav=nsCOMPtrsetup(do_QueryInterface(mWebBrowser));
if(mWebNav)
mWebNav->loadURI();

8、通过NS_TermEmbedding卸载内核,退出程序;

三、
与IE内核、Webkit等嵌入方面的差别
同样作为浏览器内核,其实有很多文章就Gecko内核、IE内核、Webkit等多方面进行过比较如Comparison of layout engines。但就嵌入易用方面来讲,它们之间差别还是蛮大的,个人认为IE内核充分利用windows com技术,作为一个独立的ActiveX,其拥有很好接口封装,对windows用户来讲,大大提高了其易用性复用性;

Webkit内核本身一开始就专注于浏览器内核部分如KHTML、KJS,其提供给windows、gtk、mac等方面的接口也相对完毕;

Gecko内核往往不仅仅专注于浏览器内核如HTML、Javascript等方面,同时它还提供了XPCOM、XUL,从大的方面看,嵌入Gecko内核访问通用的html类的Web网站,只利用了其中一部分功能,其XUL、XPCOM等功能几乎可以不用,这样一来也是一种浪费,所以目前Embedding方面的接口,既要考虑到XPCOM方面,又要考虑到用户嵌入内核的易用性,显然没有IE内核及Webkit内核,简单明了,要想嵌入Gecko内核,需要对其进行深入的了解,这样反而降低了嵌入的意义。

顺便提一下,Avant/Orca Browser创始人宣称花了3年多的时间才将Gecko内核研究透彻,弄出个基于Gecko内核的浏览器Orca Browser,但其利用方式,不是基于Embedding的,而是基于Xulrunner的,这样既迎合了Gecko本身,同时能充分利用其强大功能,可谓一举两得,但是要想用好它,可要花上3、5年功夫不可。

四、总结
其实目前通过Embedding的方式使用Gecko内核的还不是很多,使用起来也比较困难,需要较深入的了解XPCOM等内核知识,比较好的实例也就只有上面提到的TestGtkEmbed、mfcEmbed等,可喜的是Mozilla最近似乎想重新加强其对Embedding方面的支持。详见Embedding/NewApiChris Blizzard's blog

另外Second life提供了一组接口以更加方便嵌入Gecko内核。详见uBrowser and LLMozLib

四、参考资源
Mozilla project Embedding Mozilla
Mozilla developer center-Embedding Mozilla

Mozilla Embedding FAQ
Gecko Embedding Basics
Mozilla embedding APIs overview