WebKit三件套(3):WebKit之Port篇
了解其有关Port方面的设计,从而了解究竟如何能移植WebKit到自己的应用中。
WebKitPort方面的内容是可以很广的,例如可将不同的图形库、网络库与WebCore集成,提供不同的Port接口供外部程序使用等,例如同样在windows平台上可以运行的Google Chrome和Safari就是针对WebKit的不同移植。
我们想了解有关Port方面的主要内容在于提供不同的Port接口供外部程序使用以及如何与外部程序交互,因为WebKit中的其它两部分WebCore、Javascript实现,从逻辑上讲是不直接提供接口给外部程序使用的。同时为了完成浏览器的核心功能,WebKit也需要从外部程序中通过Port接口的方式获取一些支持。
从这个角度讲WebKit作为一个相对独立的整体,它与外部程序之间的交互也就有一组相对固定的接口来定义及维护它们之间的关系,它们之间的关系与插件跟浏览器引擎之间的关系完全类似,接口相当一组协议,有的是由WebKit来实现,而供外部程序调用;有的的正好相反。
通过前面的了解我们知道WebKit的主要功能集中在分析Html、渲染布局Web内容以及Javascript实现方面等,而这些Web内容显示在哪个窗口及消息处理的启动循环等都需要由外部程序来提供。
初步分析已有WebKit Port移植实现
与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);
对WebCore中的page/loader等方面的类提供对应Port的实现支持
如EventHandlerWin.cpp、FrameLoaderWin.cpp、DocumentLoaderWin.cpp、DocumentLoaderWin.cpp、WidgetWin.cpp、KeyEventWin.cpp等
实现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;
}
Chrome中对Port移植方面的实现
其基本上与其他Port移植类似,其主要代码在webkit\glue目录中,可重点关注带client_impl.cc后缀的文件、webview_impl.cc、webwidget_impl.cc等;但是其究竟如何创建原生windows窗口、如何创建Render进程、Render进程与创建的原生windows窗口的关系如何等需要更进一步深入研究Chrome,如果能从上面提到的Port部分入手也许很快就可得到答案,这一点以后有机会单独研究。
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目录下的源文件。
通过进一步了解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整出一个象模象样的东东如机顶盒浏览器、手机浏览器等等。。
参考资源
原文:http://ourpgh.blogspot.com/2008/10/webkitport.html
转载本站文章《WebKit三件套(3):WebKit之Port篇》,
请注明出处:https://www.zhoulujun.cn/html/webfront/browser/webkit/2021_0422_8632.html
WebKit三件套(3):WebKit之Port篇的更多相关文章
- [WebKit内核] JavaScriptCore深度解析--基础篇(一)字节码生成及语法树的构建
看到HorkeyChen写的文章<[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现>,写的很好,深受启发.想补充一些Horkey没有写到的 ...
- 【文智背后的奥秘】系列篇——分布式爬虫之WebKit
版权声明:本文由文智原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/139 来源:腾云阁 https://www.qclou ...
- 让那些为Webkit优化的网站也能适配IE10
特别声明:此篇文章由David根据Charles Morris的英文文章原名<Adapting your WebKit-optimized site for Internet Explorer ...
- Win7 & VS2013 编译 WebKit 总结
[转载请注明Moon出品: http://blog.csdn.net/lzl124631x] 距离上次编译WebKit(实际日期是2012年10月)已经过去一年多了, 这期间有很多人问我编译相关的 ...
- 让那些为Webkit优化的网站也能适配IE10(转载)
转载地址:http://www.w3cplus.com/css3/adapting-your-webkit-optimized-site-for-internet-explorer-10.html 特 ...
- [转]开发者需要了解的WebKit(mark)
以下内容转自:http://www.infoq.com/cn/articles/webkit-for-developers -------------------------------------- ...
- 八大Webkit内核浏览器
列举出时下最流行的Webkit内核浏览器,所以我们并不会做出评测和对比.PS:本文列举的浏览器有一部分为IE+Webkit双核浏览器,如果您对其他IE内核浏览器很感兴趣<抛弃数据!用体验和感觉告 ...
- 探索WebKit内核(一)------ 菜鸟起步
为什么搞WebKit 如今研究WebKit的人越来越多,俺不能免俗,也增加当中.WebKit的火爆也是得益于浏览器和WebOS的混战,随着Palm WebOS, Chrome OS, Firefox ...
- 开发者应当了解的WebKit知识
开发者应当了解的WebKit知识 对一些开发者而言,WebKit就是一个黑盒子.丢进去HTML.CSS.JS等一连串的东西,而WebKit就能变魔术一般显示出一个很棒的网页出来.实际上,正我的同事Il ...
- 探索WebKit核心(一)------ 新秀开始
为什么WebKit 现在,研究人员WebKit越来越多的人,我不能逃脱,其中还增加.WebKit也多亏了流行的浏览器和WebOS乱斗.随着Palm WebOS, Chrome OS, Firefox ...
随机推荐
- 《HelloGitHub》第 91 期
兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...
- UIPath流程控制
应当仔细地观察,为的是理解:应当努力地理解,为的是行动. UIPath程序中流程控制主要包括条件语句.循环语句以及中断语句.下面我们一一学习这些语句在RPA流程设计中的使用. 1. 条件判断 if ...
- 快速上手Prompt,让你的LLMs更智能
前言 在当前社会中,随着AIGC的盛行,使用好prompt可以让自己更上一层楼.今天,我将通过星火大模型重新认识prompt设计,并与大家分享一些使用技巧. 如果你想体验星火大模型的强大魅力,请登录h ...
- WPF应用开发之附件管理
在我们之前的开发框架中,往往都是为了方便,对附件的管理都会进行一些简单的封装,目的是为了方便快速的使用,并达到统一界面的效果,本篇随笔介绍我们基于SqlSugar开发框架的WPF应用端,对于附件展示和 ...
- Go笔记(1)-变量的详细用法
变量 (1)变量的定义 Go语言是静态类型的语言,所有类型都需要明确的定义. var是声明变量的关键字 使用格式:var 变量名 变量类型 变量命名规范:遵循驼峰格式,首个单词小写,每个新单词的首字母 ...
- hexo+icarus博客搭建
展示效果:米七小站 环境准备 安装nodejs.git.hexo Hexo官网文档 Hexo初始化项目 $ hexo init myblog $ cd myblog $ yarn 查看效果 $ hex ...
- SpringBoot实战项目:蚂蚁爱购(从零开发)
简介 这是从零开发的SpringBoot实战项目,名字叫蚂蚁爱购. 从零开发项目,视频加文档,十天彻底掌握开发SpringBoot项目. 教程路线是:搭建环境=> 安装软件=> 创建项 ...
- Winform 好看控件库推荐:MaterialSkin.2
MaterialSkin.2 控件包是在 MaterialSkin 及基础上二次开发而来的,在原控件基础上修复了一些Bug,丰富了主题以及动画效果,效果非常好. MaterialSkin.2 现在处于 ...
- docker开启或关闭<开机自启容器>
启动容器时设置 docker run --restart=always 启动完成也可以修改 docker update --restart=always <容器ID> 想取消容器自启 do ...
- Scrapy框架爬取HTTP/2网站
scrapy本身是自带支持HTTP2的爬取: https://docs.scrapy.org/en/latest/topics/settings.html?highlight=H2DownloadHa ...