Webkit的各个部分,我自己简单的归纳了一下.
0.程序界面管理.
1.加载网页的总控制器,loader.
2.资源内容的获取和管理
3.html,css文档的解析.
4.html元素,Dom树,CSS样式相关的各个数据结构的创建和维护
5.布局和渲染
6.事件响应
7.javascript部分
8.插件的支持.
9.其它杂项.
由于网络已经存在不少分析文章,有一些质量很高,因此我不必再重复别人的内容,徒增对比学习缓慢及错误之羞愧.而且既然写出来就要对内容负责,涉及细节太多,webkit仅是我个人众多业余爱好之一,非工作内容,精力实在不够.
网络上的文章欠缺DOM树构建过程的分析,和layout的具体细节分析. 不过前者乏味冗长,后者基本遵循CSS box模型,也没太大意义去深究. 罗列内容,供日后参考.
一. webkitcore的外壳接口部分.
1.Page
Page类对应于一个网页的页面.比如它管理页面相关的如下数据结构,界面移植相关的client,RenderTheme,主Frame,
,Plugins, BackForwardList,settings,进度条,音频音量,查找并高亮字符串等等.
该类在外部移植代码中创建, 如Qt版本在QWebPagePrivate的构造函数中创建.
网络文章对Page的分析:
http://blog.youkuaiyun.com/dlmu2001/article/details/6213377
2.Frame
Frame类对于一个网页内的Frame或iframe;一个网页原生窗口对应一个Page,Page处理页面相关的各种内容,一个Page对应一个主Frame,根据是否有Frame或iframe,主Frame又有子frame, 每个frame对应一个FrameView, 一个Document类.
frame管理的数据略混乱.与page相比,主要偏向管理HTML对象.如 FrameView,FrameLoader,DOMWindow,Document,scriptcontroller ,SelectionController,VisibleSelection,EventHandler
该类对象在外部移植代码中创建,如Qt版本在QWebFrameData的构造函数中创建.
它管理frame相关的数据结构.它与一份html代码对应,同时也对应着一个FrameView.
网络文章对Frame的分析:
http://blog.youkuaiyun.com/dlmu2001/article/details/6164873
FrameView 继承于 ScrollView. 拥有一个平台相关的PlatformWidget指针,
在Qt中是Qwidget, win下是HWND.它主要是用来管理Frame的界面.不过貌似这个PlatformWidget并没有被使用.
一直是NULL值.即一个Frame不是一个原生的窗口.FrameView是在Frame的CrateView方法中创建的.
Chrome继承于HostWindow,它与ChromeClient通信,ChromeClientQt继承ChromeClient主要是用来管理
整个网页的窗口界面.ChromeClientQt是在QWebPagePrivate中创建,平台Widget指针由其传入.
每个移植一般要实现一些外壳类,如webview,webwidget,webpage,webframe之类的来封装相应的内容.
网络文章分析:
http://blog.youkuaiyun.com/dlmu2001/article/details/6208241
二. 加载控制器Loader.
Loader:
主要是FrameLoader和Loader.一个加载网页,一个加载资源.
webkit主页上的论述.
http://www.webkit.org/blog/1188/how-webkit-loads-a-web-page/
网络文章的分析.
http://www.jjos.org/%e8%bd%af%e4%bb%b6%e6%9e%b6%e6%9e%84/webkit-%e8%bd%af%e4%bb%b6%e6%9e%b6%e6%9e%84/2010/04/29/136_webkit.html
http://www.docin.com/p-35821198.html
FrameLoader:
http://blog.youkuaiyun.com/dlmu2001/article/details/6168545
Loader:
http://blog.youkuaiyun.com/dlmu2001/article/details/6363380
涉及到的类大致有这些.
FrameLoader,FrameLoaderClient,FrameLoaderClientQt, DocumentLoader,DocLoader,PolicyChecker, MainResourceLoader,ResourceHandle, ResourceLoader,ResourceHandlerClient, MainResourceLoader,
SubResourceLoader,SubResourceLoaderClient,CacheResourceRequest,CachedResourceLoader,MemoryCached,CachedResource,CachedResourceLoader,
CachedImage,CachedFont,CachedScript,CachedCSSStyleSheet,ReouceLoaderSchedule,CacheResourceShedule,
一个网页访问和加载的流程由FrameLoader 控制.
load过程的状态变迁:
policy ->(审查)-> provisional -> (主html获取完毕)-> Committed
外壳会调用FrameLoader::load( ResourceRequest ),中途会交给FrameLoaderClient::createDocumentLoader来创建DocumentLoader,然后FrameLoader::loadWithDocumentLoader(),PolicyChecker::checkNavigationPolicy,检查完毕后 ,继续continueLoadAfterNavigationPolicy ,进入provisional状态 ,执行provisionalLoadStarted() ,然后是根据是否要发送form 回调client的函数, 然后继续continueLoadAfterWillSubmitForm, 依次执行:
DocumentLoader::startLoadingMainResource
m_mainResourceLoader = MainResourceLoader::create(m_frame);
MainResourceLoader::loadNow(ResourceRequest& r) ;
m_handle = ResourceHandle::create(r, this, m_frame.get(), false, true);
再后续就进入了网络请求部分,大家可以自己查看调用堆栈.
会回调到ResourceLoader的didReceiveData再到FrameLoader的receiveData ,再到FrameLoader::commitProvisionalLoad再到FrameLoader::transitionToCommitted ,在此回调Client的transitionToCommittedForNewPage , 在Client中调用了frame::createView(); 之后还会再回调一些Client的函数,执行渲染显示.最后到此结束一次load.
其它资源的load:
图片,在解析图片元素的时候 如果遇到src属性时,执行newImage=document->docLoader()->requestImage(sourceURI(attr));
当下载完毕的时候会回调到RenderImage的ImageChanged完成图片更新.
css,解析到css元素的时候,StyleElement::process函数调用CSSParser::parseSheet()
MainResourceLoader会回调FrameLoader的ReceivedData()
然后调用HTMLTokenizer::write()
HTMLTokenizer完成了HTML文件的解析过程, 解析的同时创建了DOM/CSS等等数据结构.
解析的过程并不有趣,代码繁杂,也没太多高深技术.
可以参看下网络上的文章.
http://blog.youkuaiyun.com/dlmu2001/article/details/5998130
html 解析部分:
获取html数据后,传递给HTMLTokenizer::write();然后基本上就是这个类完成解析工作,
解析过程就是一个个的读取字符,进行状态变迁.HTMLTokenizer继承于Tokenizer, Tokenizer只是个接口.
HTMLTokenizer的write函数在解析到一个完整的token后会调用processToken,该函数调用
HtmlParserr::parseToken() 再调用GetNode通过HTMLElementFactory::createHTMLElement产生Node对象
然后调用insertNodeAfterLimitBlockDepth,该函数会调用insertNode(),insertNode函数中 :
Node* newNode = m_current->addChild(n);
也即ContainerNode的addChild方法;等等等方法,以及 Element::attach()方法,在这个方法中又创建了RenderObject.通过createRendererIfNeeded(); 可见是边解析边创建,解析了足够创建结点 就创建结点Element.能够创建RenderObject就创建.
解析没太特别的地方,倒是Node,Element,ContainerNode等类值得关注.
CSS的解析
使用了 lex和yyac ,Tokenizer.cpp被包含在CSSParser.cpp的最后.
CSSGrammar.cpp
具体的yacc语法定义在 CSSGrammar.y文件中,该文件包含在CSSGrammar.cpp中
而CSSParser负责相关的回调函数.CSSStyleRule代表一条css规则.
最后的内容都在m_parsedStyleObjects,m_parsedRuleLists中.
四. DOM树与Render树.
网络文章的论述.
http://www.jjos.org/%e4%ba%92%e8%81%94%e7%bd%91/%e6%b5%8f%e8%a7%88%e5%99%a8/2010/05/10/308_webkit-webkit-major-objects.html (其中最后那张图片非常直观和经典)
webkit主页上文章的翻译
http://www.webkit.org/blog/114/webcore-rendering-i-the-basics/
http://mogoweb.net/archives/45
webkit研究报告(该文章Dom部分不多,但RenderObject数据结构的描述非常的详尽)
http://www.docin.com/p-35821198.html
Document类
继承与ContainerNode 和 ScriptExecutionContext
在DOMImplementation::createDocument中创建
而此函数在
void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
或 PassRefPtr<Document> DOMParser::parseFromString(const String& str, const String& contentType)
中调用.
1.Tokenizer
2.DocLoader
3.各类URL
4.CSSStyleSheet
5.HistoryItem
等等一个网页的方方面面数据都在这里.
DOMWindow
供js调用的DOM接口.
五. 布局和渲染
layout和paint
webkit主页上的文章:
http://www.webkit.org/blog/114/webcore-rendering-i-the-basics/
layout的网络文章分析:
http://hi.baidu.com/liangyj/blog/item/edecdd333e57afff1a4cffcc.html
http://blog.chinaunix.net/space.php?uid=580722&do=blog&id=2090487
layout完成之后,RenderBox的渲染相关的成员就填写了正确的值:
比如:
IntRect m_frameRect;
int m_marginLeft;
int m_marginRight;
int m_marginTop;
int m_marginBottom;
paint:
根据css的要求设置相应的坐标,画刷,到最后提交给平台底层的绘图函数.
六. DOM事件处理.
网络文章分析:
http://www.starwd.com/?p=340
http://blogt.chinaunix.net/space.php?uid=20412483&do=blog&id=2994789
http://mobile.51cto.com/symbian-287629.htm
七. javascript
网络文章的分析:
http://www.osseye.com/?p=417
http://mogoweb.net/archives/194
http://ishare.iask.sina.com.cn/f/22019184.html
http://wenku.baidu.com/view/b7207e1fff00bed5b8f31d05.html
http://blog.youkuaiyun.com/bertzhang/article/details/6759055
http://wingolog.org/archives/2011/10/28/javascriptcore-the-webkit-js-implementation
http://wuhuizhong.iteye.com/blog/1107633
0. 外围和DOM绑定
scriptController,JSDOMWindowShell,Completion.
绑定webkitcore的方法和DOM对象到JSC见bindings目录以及脚本产生的generated目录中的文件
1. JSC的内部
(1) 解析和执行流程.
a. 解析.
jsc使用yacc来完成parse功能,利用yacc回调的函数,创建SourceElements结构.相关的数据结构参见Nodes.cpp, 然后SourceElements转化成ProgramNode,感觉2者意义上差别不大.然后创建一个ByteCodeGenerator对象,该对象调用大量emitcode函数,逻辑实现在 byteCodeGenerator.h,byteCodeGenerator.cpp, NodesCodegen.cpp中.最后产生的东西在CodeBlock的instruction中.
b. 执行.
入口:interpreter::execute(),根据是否启用JIT分别调用 jitcode()或 privateExecute.
如果启用JIT, jitcode调用JIT::compile->privatecompile(),调用了很多七七八八的函数,产生X86的机器代码,具体见Assembler相关类.最后的execute调用了JITStubs.cpp中的ctiTrampoline(),该函数为汇编代码,调整堆栈,然后开始执行.
如果不启用JIT, privateExecute()是长达3000行的巨大函数,重复及繁杂的完成了一个js解释器的完整逻辑,很强悍.哈哈.
(2) 内存管理.
jsc使用的是标记-清除式的GC.底层相关类,JSObject,JSCell和structure.
八. 插件的支持.网上文章:
(plugin部分的代码分析)
http://wenku.baidu.com/view/9dfee12b3169a4517723a3a7.html
http://blog.youkuaiyun.com/myaccella/article/details/7009086
九. 杂项.
安全(XSSAuditor).