webkit技术详解.docx_第1页
webkit技术详解.docx_第2页
webkit技术详解.docx_第3页
webkit技术详解.docx_第4页
webkit技术详解.docx_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

由于工作需要,最近在准备一个介绍webkit的PPT文档, 我个人断断续续学习webkit的代码也有一年多了,其间也阅读了网上的一些webkit相关技术文章,但中文的资料很少,大部分都是english的,有些E文资料还需要翻墙。平常由于自已记性不好,去年看过的一些模块今年再去翻时,竟然没一点印象了,悲剧。所以,借此机会,把自已对webkit的理解先做下笔记,以便于以后需要时可以方便查阅。需要说明的是,笔记记录的有我个人的理解,也有网上摘录的片段和图片,不一定正确,也会比较凌乱,希望看到的朋友及时指正,共同进步。一 Webkit的由来1 十几年前的故事1994年,Netscape浏览器曾占据整个浏览器市场的90%,风头无二(也很嚣张)。但随着微软推出win95后,把IE 1.0做为win95的插件发布,开始挑战Netscape的霸主地位,到发布IE 4.x,短短三年时间,打败Netscape。 这里面虽然说有与windows集成的原因,但从本身的功能上来讲, IE从速度和对标准的支持上来讲,已真正打败了Netscape。此阶段的浏览器可称为第一代浏览器。它的主要特点是单窗口型式。竞争的最主要是访问速度、兼容性。原因:90年代都大多是用modem拨号上网,56K/S。2Webkit出生Apple公司在它的Mac OS X里,集成了基于KHTML 改进型的 WebKit 引擎的浏览器,命名为:Safari,当年苹果比较了 Gecko 和 KHTML 后,之所以选择了后者,就因为它拥有清晰的源码结构、极快的渲染速度。(KHTML是由KDE 小组开发的)随后, apple将它开源。至此,第二代浏览器,基本上是三分天下: Trident: IE系列, 以Trident 作为内核引擎; Gecko: Firefox 是基于 Gecko 开发; WebKit: Safari, Google Chrome, 搜狗双核浏览器(集成IE和chrome), QQ浏览器5。 WebKit 内核在手机上的应用也十分广泛,例如 Google 的手机 Gphone、 Apple 的 iPhone, Nokias Series 60 browser 等所使用的 Browser 内核引擎,都是基于 WebKit。总结:webkit是什么? 答:Webkit是一套浏览器排版代码, 已开源,主要由apple公司在维护。强调: webkit仅仅是一套排版引擎,举个例子说明下: google的chrome是一个浏览器对吧, 那chrome主要包含以下模块: 外壳UI(多标签,菜单,状态栏,网址输入栏等),读取网络数据的模块,排版解析模块,JS解析引擎。外壳UI是google自已写的,js引擎是google写的V8, 读取网络数据模块用的winhttp,只有排版引擎用的webkit。 不知道我说清楚了没,呵呵。WebKit is an open source Web content engine for browsers and other applications. We value real-world web compatibility, standards compliance, stability, performance, security, portability, usability, and relative ease of understanding and modifying the code (hackability).二 Webkit编译环境Webkit的官网:/说明:下面的几种编译方法,越往下面看越简单噢。1. Webkit提供以下几种主要的编译环境1). Max os X(Xcode Tools package)2). Windows (Visual Studio)最为常用,毕竟用winxp系统的还是多数3).QT4).GTK具体的环境搭建见:/building/tools.html2. WebKit winxp下编译小结网上很多人抱怨webkit总是编译不过,确实, webkit没有提供一个下载代码后,直接可以用VS工具编译的方法, 因为它用到了gcc编译环境,在windows下编译的话,需要安装cygwin才行,由于它的编译脚本用的perl,又需要安装perl的环境。总之比较麻烦。 这也是因为网上的文章,有介绍QT安装环境的,有的是介绍官方webkit的安装环境的,还有的是介绍safari的, 所以在网上查阅文档时一定要找到你相对应的才行。重点要注意的地方:1. 下载Cygwin,一定要下载webkit提供的版本。2. 用vs2005的话,一定要打SP1.3. QuickTime SDK和directX SDK必不可少。4.启动Cygwin ,安装官网方法,执行./WebkitTools/Scripts/build-webkit脚本。3. 较简单的编译安装QT webkit直接在QT的官网下载如:qt-sdk-win-opensource-2009.04.exe(该版本是我09年下半年使用的,官网上应该早有新版本了)不需要cygwin, 不需要quickTime,只需要执行下面几个步骤:1、下载安装Visual.S.2005,或2008;2、将qt-sdk-win-opensource-2009.04.exe解压到某个目录下;以D:qt4.5.0为例3、配置环境变量:在“我的电脑”“属性”-“高级”-环境变量-*的用户变量-新建,添加一个变量名为QTDIR 变量值为D:qt4.5.0qt-win-opensource-src-4.5.0PATH变量值为D:qt4.5.0qt-win-opensource-src-4.5.0bin添加新的环境变量,名字为QMAKESPEC,值为win32-msvc2005.4、编译源代码通过开始菜单 - Microsoft Visual Studio 2005 - Visual Studio Tools, 运行命令行.到qt源码的目录下,运行命令:configure.exe -webkit编译过程中,会问一个问题:是否接受GPL协议,选y.经过一段时间以后,qmake被编译出来了.接着编译一大堆代码,简单的敲入nmake即可.5、编译应用程序qmakenmake就会在该应用程序下,就会在debug目录下生成可以执行文件。不过我个人不太喜欢QT,只是安装了跑一跑,QT的安装环境包含了webkit的源代码, 同时它自带了一个简单的Browser项目(如下):编译运行。在Visual Studio中设置browser工程为主工程,然后编译。可以顺利编译完成,下面是运行后的效果图。 4. 最最简单的webkit学习环境-ISee5. Isee是一位中国人移植的webkit, 在winxp下用vs2008直接编译即可调试,用于学习最好,强烈支持,也是一位同事推荐给我的,后面的代码走读主要基于该环境。6. Isee还可以直接移植到wince平台运行噢。7. 官网:/p/iseebrowser/备注:原作者已经不再维护了。所以webkit内核的版本号有点老。8. webkit在vs2008中编译见 : /blog/static/4534773920091016115533158/三 Webkit整体介绍1. Webkit的结构图(以ISee架构举例):cairo 一个2D绘图库casqt Unicode处理用的库,从QT中抽取部分代码形成的expat一个XML SAX解析器的库freetype矢量字库接口库,用于存取ttf矢量字体文件libcurl一个开源的url库,支持HTTP、FTP等协议Libjpeg,libpng图像解码库libxml基于DOM树的XML解析器libxsltXML transform engine pthreadPthread库, port of the POSIX thread library sqlite3一个小型的数据库,据称在型入式平台是存取速度最快的数据库。开源, 编译后就一个400K的 sqlite.dll。 移植非常方便,纯C写的。wceshunt一个用于Windows CE平台下的C常用函数封装库ZlibZlib库。用于解压缩。2. Webkit 源代码由三大模块组成:1). WebCore,2). WebKit,3). JavaScriptCore。WebCore:排版引擎核心,WebCore包含主要以下模块:Loader, Parser(DOM,Render), Layout,Paint。WebKit:移植层,主要包含: GUI,File System, Thread,Text,图片编解码等与平台相关的函数。JavaScriptCore:JS虚拟机,相对独立,主要用于操作DOM, DOM是W3C定义的规范,主要用于定义外部可以操作的浏览器内核的接口,而webcore必须实现DOM规范。(具体的DOM规范可以查w3c.)3. WebKit分模块介绍(这里简单列出,后面再具体介绍)Webkit平台相关1) CURL网络库2) libPng, LibJpeg图形处理相关3) sqlite小型关系数据库WebCore核心 1) Loader加载资源及Cache 实现(Curl)2) DOM : HTML词法分析与语法分析3) DOM : DOM节点与Render节点创建,形成DOM树4) Render:Render树介绍,RenderBox5) Layout:排版介绍6) Css Parser模块7) Binding-DOM与JavascriptCore绑定的功能 JavascriptCore-javascript引擎 1) API-基本javascript功能 2) Binding与其它功能绑定的功能,如:DOM,C,JNI 3) DerviedSource自动产生的代码 4) PCRE-Perl-Compatible Regular Expressions 5) KJS-Javascript Kernel 4. 页面的整个处理流程(简单介绍,详细流程在后面笔记中)1. 用户输入网址后,FrameLoader:load函数会接收到URL。2. 把URL 请求传给CURL库。3. CURL发出http请求,得到数据后,传给Loader,开始解析。4. 通过Dom Builder按W3C的html规范生成Dom树5. 如果有javascript,JSEngine就通过ECMA-262标准完善Dom树6. 在生成DOM树的同时, 同步生成Render树。7. 解析完后, 调用Layout排版8. Paint出来Webkit-libCurl库介绍前面有说道webkit仅仅是一个页面排版的引擎,所以,对webkit来说,网页数据(html文件,图片,.css,.js文件)的请求与接收都是通过第三方的库:libCurl来处理。打开webkit开发工程(.sln)即可以看到,libcurl可以被静态或动态链接到主工程中。Libcurl就是指的curl,只是在webkit工程中,不作为单独的进程存在,而是被编译成动态库。 webkit主要用到curl的以下功能:1) Http协议。包含:Get, put, Post, Cookie管理。2) https协议。3) 本地文件缓存。(前进,后退管理)Webkit具体调用了哪些curl接口,详见后面Loader模块介绍章节。这里简单列举:1) curl_global_init(CURL_GLOBAL_ALL);2) curl_multi_init()3) curl_share_init()4) curl_share_setopt()5) curl_easy_getinfo()6) curl_multi_fdset()7) curl_multi_perform()8) curl_multi_info_read()9) curl_multi_cleanup()10) curl_share_cleanup()11) curl_global_cleanup();可以看到,由于webkit要支持同时请求多个http数据,所以用到的是curl的multi接口。在介绍Loader之前,先介绍一下libcurl,打下基础。以下附一篇libcurl的介绍:一、 概念1. 为什么要使用libcurl1) 作为http的客户端,可以直接用socket连接服务器,然后对到的数据进行http解析,但要分析协议头,实现代理这样太麻烦了。2) libcurl是一个开源的客户端url传输库,支持FTP,FTPS,TFTP,HTTP,HTTPS,GOPHER,TELNET,DICT,FILE和LDAP,支持Windows,Unix,Linux等平台,简单易用,且库文件占用空间不到200K2. get和post方式客户端在http连接时向服务提交数据的方式分为get和post两种1) Get方式将所要传输的数据附在网址后面,然后一起送达服务器,它的优点是效率比较高;缺点是安全性差、数据不超过1024个字符、必须是7位的ASCII编码;查询时经常用此方法。2) Post通过Http post处理发送数据,它的优点是安全性较强、支持数据量大、支持字符多;缺点是效率相对低;编辑修改时多使用此方法。3. cookie与session1) cookiecookie是发送到客户浏览器的文本串句柄,并保存在客户机硬盘上,可以用来在某个Web站点会话之间持久地保持数据。cookie在客户端。2) sessionsession是访问者从到达某个特定主页到离开为止的那段时间。每一访问者都会单独获得一个session,实现站点多个用户之间在所有页面中共享信息。session在服务器上。3) libcurl中使用cookie保存cookie, 使之后的链接与此链接使用相同的cookiea) 在关闭链接的时候把cookie写入指定的文件curl_easy_setopt(curl, CURLOPT_COOKIEJAR, /tmp/cookie.txt);b) 取用现在有的cookie,而不重新得到cookiecurl_easy_setopt(curl, CURLOPT_COOKIEFILE, /tmp/cookie.txt);b) http与https的区别1) Http是明文发送,任何人都可以拦截并读取内容2) Https是加密传输协议,用它传输的内容都是加密过的,https是http的扩展,其安全基础是SSL协议c) base64编码1) 为什么要使用base64编码如果要传一段包含特殊字符比较多的数据,直接上传就需要处理转意符之类的很多问题,用base64编码,它可以把数据转成可读的字串,base64由a-z, A-Z, +/总计64个字符组成。2) 传送base64编码的注意事项由于base64的组成部分有加号,而加号是url中的转意字符,所以无论是get方式还是post,传到服务器的过程中,都会把加号转成空格,所以在传base64之前需要把base64编码后的加号替换成”%2B”,这样就可以正常发送了。二、 例程d) 代码#include #include bool getUrl(char *filename) CURL *curl; CURLcode res; FILE *fp; if (fp = fopen(filename, w) = NULL) / 返回结果用文件存储 return false; struct curl_slist *headers = NULL; headers = curl_slist_append(headers, Accept: Agent-007); curl = curl_easy_init(); / 初始化 if (curl) curl_easy_setopt(curl, CURLOPT_PROXY, 01:8080);/ 代理 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);/ 改协议头 curl_easy_setopt(curl, CURLOPT_URL, /search?hl=en&q=xieyan0811&btnG=Google+Search&aq=f&oq=xieyan081); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); res = curl_easy_perform(curl); / 执行 curl_slist_free_all(headers); curl_easy_cleanup(curl); fclose(fp); return true;bool postUrl(char *filename) CURL *curl; CURLcode res; FILE *fp; if (fp = fopen(filename, w) = NULL) return false; curl = curl_easy_init(); if (curl) curl_easy_setopt(curl, CURLOPT_COOKIEFILE, /tmp/cookie.txt); / 指定cookie文件 / curl_easy_setopt(curl, CURLOPT_COOKIEJAR, /tmp/cookie.txt); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, &logintype=uid&u=xieyan&psw=xxx86); / 指定post内容 curl_easy_setopt(curl, CURLOPT_PROXY, 01:8080); curl_easy_setopt(curl, CURLOPT_URL, /cgi-bin/login.cgi); / 指定url curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); res = curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(fp); return true;int main(void) getUrl(/tmp/get.html); postUrl(/tmp/post.html);e) 编译 g+ main.cpp -o main -lcurlWebkit Loader模块介绍前面说过, webkit只是一个排版引擎,在Webkit排版/渲染一个网页之前, 它肯定需要从网络上、或者本地文件系统中读到网页的http数据,对吧,对webkit来讲,他要的就是数据,不管你是从网络读的还是本地文件读的。Loader就是这样一个模块,它承上启下,不仅负责为webkit引擎提供数据,还控制着webkit的绘制。另外,它同时还与提供数据的“来源”打交道。先简单举例说明: 用户输入一个url,这时是Loader接收url请求,它把url传递给curl,设置curl的回调函数,当curl读到数据,loader把数据传递给Parser,开始生成DOM。一下面重点介绍一下与Loader相关的数据结构和模块。Frame:可以看做是浏览器外壳调用Loader的总入口,它就像我们印象中的一个网页,它关注的是页面的显示 (FrameView) 、页面数据的加载(FrameLoader) 、页面内的各种控制器 (Editor, EventHandler, ScriptController, etc.) 等等,它包含以下模块(只列出重点):DocumentPageFrameViewRenderViewFrameLoaderDOMWindow下面分别介绍(PS: 必须要了解这些概念,不然后面的东东都无法理解):1)Document:这个类的爷爷类是 Node ,它是 DOM 树各元素的基类; Document 有个子类是 HTMLDocument ,它是整个文档 DOM 树的根结点,这样就明白了:原来 Document 就是描述具体文档的代码,看一下它的头文件,就更明白了,它的属性与方法就是围绕着各种各样的结点: Text , Comment , CDATASection , Element2)Page: 我的理解是,Page与Frame(严格说是FrameView)是一一对应的,Frame关注UI,Page关注数据。现在的浏览器一般都提供同时打开多个窗口,每一个窗口对应的数据就是这个Page在管理了。 在 page.cpp 文件里,还有个重要的全局指针变量: static HashSet* allPages; 这个变量包含了所有的page 实例。3)FrameView: 可以理解为为一个网页的ViewPort, 它提供一个显示区域,同时包含的有Render根节点、layout排版相关接口、Scroll相关等。 FrameView是Layout排版的总入口。4)RenderView: 与FrameView差不多,只是分工不同,它管理与Render树相关的东东。5) FrameLoader:重点,FrameLoader类将Documents加载到Frames。当点击一个链接时,FrameLoader创建一个新的处于“policy”状态的DocumentLoader对象,一旦webkit指示FrameLoader将本次加载视为一个导航(navigation),FrameLoader就推动DocumentLoader进入“provisional”状态,(在该状态,DocumentLoader发调用CURL发起一个网络请求,并等待是html还是下载文件。)同时, DocumentLoader会创建一个MainResourceLoader对象(该对象在后面单独介绍)。6)。DOMWindow: 实现了Dom的一些接口,如CreateNode等。后面可以详细讲讲。上面介绍的概念比较多,我也不晓得好不好理解,没理解也不怕,多去看看代码,这是必须的。另外看看下面的图,就会清晰很多的。二、Webkit的Loader有两条加载数据的主线: (从上图可以看到)1. MainResourceLoader: 该模块主要加载主网页请求。后面称为MainResource。2. DocLoader: 该模块除了主网页外的所有子请求,如:.js文件,图片资源,.css文件。 后面称为SubResource。MainResource部分:FrameLoader-DocumentLoader-MainResourceLoader-ResourceHandle DocumentLoader经历状态:1)policy 2) provisional 3) commited分别是等待、作为navigation发送network request、文件下载完毕Subresource部分:DocLoader-Cache-CacheObjects example: CacheImage-SubresourceLoader-ResourceHandle 当请求一个资源时,首先查看Cache中是否存在该对象,如果存在直接返回;如果不存在,创建该Cache对象(如CacheImage),然后创建一个SubresourceLoader,加载资源。举例说明: 加载图片时, DocLoader首先询问Cache, 在内存中是否也存在(CachedImage对象),如果已存在,则直接加载,即省了时间又省了流量。如果图片不在Cache中, Cache首先创建一个新的CachedImage对象来代表该图片,然后由CachedImage对象调用Loader对象发起一个网络请求,Loader对象创建SubResourceLoader。后面的流程就一样了,SubResourceLoader也是直接把ResourceHandle打交道的。接下来跟踪一下Loader发送请求的代码实现:1. 用户输入URL后,最先调用的接口是:FrameLoader:load(const ResourceRequest& request)ResourceRequest包含了:KURL(处理url的一个类)、setHTTPHeaderField、setHTTPContentType等与HTTP头部相关的函数2. Load()通过ResourceRequest数据调用createDocumentLoader(request, substituteData)来创建一个DocumentLoader。3.Load()函数继续给request设置HttpAccept, Cache-Control HTTP头等信息。4. 设置FrameLoader:checkNavigationPolicy函数进入Policy状态。5.判断该url是否在Cache中等一系列状态判断后,进入DocumentLoader:startLoadingMainResource函数准备加载MainResource。该函数首先会创建调用MainResourceLoader。6.进入MainResourceLoader:load函数,调用illSendRequest(r, ResourceResponse();做发送请求前的准备。7.调用PolicyCheck检查policy的状态后,进入 FrameLoader:callContinueLoadAfterNavigationPolicy继续往下走。8:在MainResourceLoader:loadNow(ResourceRequest& r)函数里创建ResourceHandle,在创建ResourceHandle函数中,调用start函数,start函数把ResourceHandle自已添加到ResourceHandleManager的m_resourceHandleList队列里。 同时,调用m_downloadTimer.startOneShot激活网页请求下载的定时器。(这是个毫秒级的定时器,采用定时器的原因也是为了实现异步的请法) 可以看到m_downloadTimer的定义: Timer m_downloadTimer; m_downloadTimer是实现的一个定时器模块类,在它的构造函数里已经传入了回调函数的地址:ResourceHandleManager:downloadTimerCallback。9. 一路返回到Load()函数,并返回到调用源,函数执行完毕。10. ResourceHandleManager:downloadTimerCallback回调函数被定时器调用。11. 可以看到downloadTimerCallback函数的代码:调用libcurl库的接口curl_multi_fdset, curl_multi_perform等查询数据。以下调试时Loader执行流程的函数调用栈截图:webkit应用场景再举例:用户给出一个 URL (直接输入或者点击链接或者 JavaScript 解析等方式)。然后浏览器外壳调用 FrameLoader 来装载页面。 FrameLoader 首先检查一些条件 (policyCheck() ,如 URL 是否非空、 URL 是否可达,用户是否取消等等。然后通过 DocumentLoader 启动一个 MainResourceLoader 来装载页面。MainResourceLoader 调用 network 模块中的接口来下载页面内容( ResourceHandle ),实际上这里的Resourcehandle 已经是平台相关的内容了,接收到数据以后,会有回调函数,告诉MainResourceLoader 数据已经接收到了。然后一路返回到 FrameLoader 开始调用 HTMLTokenizer 解析 HTML 文本。解析过程中,如果遇到 Javascript 脚本的话,也会调用 Javascript 引擎( Webkit 中的 JavascriptCore , chrome 中的 V8 )来解析。数据被解析完了以后,生成了一个一个的 node ,生成 DOM 树和 Render 树,然后通过 FrameLoaderClient 调用外部的壳把内容显示出来。”因此,总结Loader的功能:Loader 是在WebKit 里面一个很重要的连接器,通过loader 发起IO下载网页,图片等数据,再通过loader发起解析,以及最后的渲染功能。Loader的代码和架构清楚了没, 没清楚? 看代码吧,呵呵。文笔不好,或者加我QQ一起交流:270977395Webkit Parser模块前篇在讲parser模块之前,需要知道数据从curl怎么过来的,那就要先看看ResourceHandleManager.cpp里下面这几个函数:headerCallbackwriteCallbackreadCallback顾名思义,这三个函数是http请求发出以后的回调函数(为了实现异步操作),分别为写回调、http头回调、读回调, 翻代码发现在ResourceHandleManager的initializeHandle函数里会调用以下函数,把这几个回调注册到libcurl里:curl_easy_setopt(d-m_handle, CURLOPT_HEADERFUNCTION, headerCallback);curl_easy_setopt(d-m_handle, CURLOPT_WRITEFUNCTION, writeCallback);curl_easy_setopt(d-m_handle, CURLOPT_READFUNCTION, readCallback);重点先讲一下readCallback函数,它有点特殊,它是在ResourceHandleManager的setupPOST里函数里设置的,为什么呢? 下面解说之前,读者先要了解http协议的Get和Post才行,这是必须滴。因为一般请求URL地址,都只是Get请求,请求发出去后,只要接收http数据显示就行了。并不需要再发送啥数据了。只有当Post(上传)一个文件或者提交Form表单的Post数据时,才需要读的回调, 读回调被调用的时机是: socket的connect建立成功后,先发送的是post请求的http头部数据,再发送Body的数据,也就是说readCallback是用来发送body数据的。能理解吗?下面分别列举一下Get和Post的数据:GetGET /books/?name=maxxiang HTTP/1.1Host: User-Agent: QQBrowser/1.3 (MTK 6235; U; MTK 1.3; ch-china; rv:1.7.6)Connection: Keep-AlivePOSTPOST / HTTP/1.1Host: User-Agent: QQBrowser/1.3 (MTK 6235; U; MTK 1.3; ch-china; rv:1.7.6)Content-Type: application/x-www-form-urlencodedContent-Length: 29Connection: Keep-Alive (此处空一行)name=maxxiang&publisher=china注意: POST的http头和Body部分,中间要有2个”rn”来区分。下面来分别跟踪一下代码:1) headerCallback从上面的函数调用栈能看出,源头就是Loader章节讲到的downloadTimerCallback函数,它是读取libcurl数据的总控制函数。Curl库的Curl_client_write函数分别把http头,按”rn”切隔分多次调用headerCallback传递给Loader,每次只传一个http字段,这样的做法好处是,curl需要自已解析并保存http头部字段的数据值,同时,也方便了webkit的处理,因为webkit也是需要处理这些数据的,它需要把http头部字段都set到m_response里,后面用得着。2) writeCallback发现writeCallback的函数调用栈比headerCallback深了一些,是因为html body的数据是可以做压缩的,而curl发现http头部标识的是gzip压缩的数据,会先解压后,再传给webkit的writeCallback函数。在writeCallback里,首先会判断Http的 返回Code, 200表示成功等。 if (CURLE_OK = err & httpCode = 300 & httpCode client() d-client()-didReceiveData(job, static_cast(ptr), totalSize, 0);可以看到,httpCode判断了300400之间,如果属于这个区间,就直接返回了,为什么呢,这是因为300-400之间的代码,都是需要再处理的或再跳转请求的。举例如下(目前有用到好像只有是300-307,具体可以去查看RFC规范,这里仅举两个例子):如果301,302都表示跳转,就不用去解析body部分了,直接跳转。如果303表示请求是 POST,那么就要转为调用 GET再请求才能取到正确的数据。3) readCallbackreadCallback里,直接调用的m_formDataStream.read(ptr, size, nmemb)函数来上传。FormDataStream类可以重点看一下,它的read函数实现了上传文件和上传Form表单(httpbody)的两个分支流程。Webkit Parser模块1.在介绍parser模块前,先介绍另一个基础,这个基础是理解Parser和DOM的核心点: 1).我们都知道一个HTML文件,都是以开头。(WML是以开头)在webcore中 标签对应的是HTMLHtmlElement节点。但实际上标签(HTMLHtmlElement)并不是DOM树的根节点,webkit中DOM树的真正根节点是:HTMLDocument。 当我们在浏览器里打开一个空白页面的时候,webkit首先会生成DOM Tree的根节点HTMLDocument和Render Tree的根节点RenderView。也就是说,当前是空白页而没有html网页显示时,这个DOM Tree和Render Tree的根节点就已经存在了。只是这两棵Tree的子节点都是“空”的而已。理解了吗? 2).当用户在同一个浏览器页面中,先后打开两个不同的HTML文本文件时,会发现HTMLDocument和RenderView两个根节点并没有发生改变,改变的是HTMLHtmlElement及下面的子树,以及对应的Rendering Tree的子树。为什么这样设计?原因是HTMLDocument和RenderView服从于浏览器页面的设置,譬如页面的大小和在整个屏幕中的位置等等。这些设置与页面中要显示什么的内容无关。同时HTMLDocument包含一个HTMLTokenizer的成员,而HTMLTokenizer绑定HTMLParser。(下面具体介绍这两个组件)这样设计的好处是: 因为HTMLElement是一开始就创建的,不会随着打开一个新的URL页面而释放(free)再创建(malloc),节省了CPU时间。2.回顾一下大学课程里的编译原理课: 1).语言的解析一般分为词法分析(lexical analysis)和语法分析(Syntax analysis)两个阶段,WebKit中的html解析也不例外。 词法分析的任务是对输入字节流进行逐字扫描,根据构词规则识别单词和符号,分词。 2).状态机:有穷状态机是一个五元组 (Q,q0,F),后面省略.3.下面介绍Parser模块里两个“非常非常”重要的组件: HTMLTokenizer和HTMLParser。 1).HTMLTokenizer类理解为词法解析器,HTML词法解析器的任务,就是将输入的字节流解析成一个个的标记(HTMLToken),然后由语法解析器进行下一步的分析。 2).HTMLParser类理解为语法分析器,它通过HTMLTokenizer识别出的一个一个的标识(tag)来创建Element(Node),把Element组织成一个DOM Tree, 同时,同步生成Render Tree。4.Parser模块代码走读(如何生成DOM树和Render树的): 1). 上文提到的writeCallback接收到html数据后,首先调用ResourceLoader的didReceiveData。一路往下传:ResourceLoader:didReceiveData-MainResourceLoader:didReceiveData-.-FrameLoader:receivedData-DocumentLoader:receivedData-FrameLoader:committedLoad 2). FrameLoader:committedLoad函数这里注意,它会判断ArchiveMimeType,如果是同类的,则不需要往下走。(也就是上面第1节说的,不需往下创建HTMLTokenizer了,因为可以复用嘛) 注: 有兴趣可继续往下看代码,HTMLTokenizer是在HTMLDocument里被创建的。 3). 接下来会进入FrameLoader:addData-write函数。 write函数首先处理字符编码的问题,把解码后的html数据,继续往下丢给HTMLTokenizer的write函数: if (tokeniz

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论