




已阅读5页,还剩16页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Chromium网页Render Object Tree创建过程分析在前面一文中,我们分析了网页DOM Tree的创建过程。网页DOM Tree创建完成之后,WebKit会根据它的内容创建一个Render Object Tree。Render Object Tree是和网页渲染有关的一个Tree。这意味着只有在DOM Tree中需要渲染的节点才会在Render Object Tree中有对应节点。本文接下来就分析网页Render Object Tree的创建过程。从前面一文可以知道,每一个HTML标签在DOM Tree中都有一个对应的HTMLElement节点。相应地,在DOM Tree中每一个需要渲染的HTMLElement节点在Render Object Tree中都有一个对应的RenderObject节点,如图1所示:从图1还可以看到,Render Object Tree创建完成之后,WebKit还会继续根据它的内容创建一个Render Layer Tree和一个Graphics Layer Tree。本文主要关注Render Object Tree的创建过程。 从前面一文还可以知道,DOM Tree是在网页内容的下载过程中创建的。一旦网页内容下载完成,DOM Tree就创建完成了。网页的Render Object Tree与DOM Tree不一样,它是在网页内容下载完成之后才开始创建的。因此,接下来我们就从网页内容下载完成时开始分析网页的Render Object Tree的创建过程。 从前面一文可以知道,WebKit是通过Browser进程下载网页内容的。Browser进程一方面通过Net模块中的URLRequest类去Web服务器请求网页内容,另一方面又通过Content模块中的ResourceLoader类的成员函数OnReadCompleted不断地获得URLRequest类请求回来的网页内容,如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void ResourceLoader:OnReadCompleted(net:URLRequest* unused, int bytes_read) . CompleteRead(bytes_read); . if (bytes_read 0) StartReading(true); / Read the next chunk. else / URLRequest reported an EOF. Call ResponseCompleted. DCHECK_EQ(0, bytes_read); ResponseCompleted(); 这个函数定义在文件external/chromium_org/content/browser/loader/resource_loader.cc中。 参数bytes_read表示当前这次从URLRequest类中读取回来的网页内容的长度。当这个长度值等于0的时候,就表示所有的网页内容已经读取完毕。这时候ResourceLoader类的成员函数OnReadCompleted就会调用另外一个成员函数ResponseCompleted进行下一步处理。 ResourceLoader类的成员函数ResponseCompleted的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void ResourceLoader:ResponseCompleted() . handler_-OnResponseCompleted(request_-status(), security_info, &defer); . 这个函数定义在文件external/chromium_org/content/browser/loader/resource_loader.cc中。 在前面一文中,我们假设ResourceLoader类的成员变量handler_指向的是一个AsyncResourceHandler对象。ResourceLoader类的成员函数ResponseCompleted调用这个AsyncResourceHandler对象的成员函数OnResponseCompleted进行下一步处理。 AsyncResourceHandler类的成员函数OnResponseCompleted的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void AsyncResourceHandler:OnResponseCompleted( const net:URLRequestStatus& status, const std:string& security_info, bool* defer) const ResourceRequestInfoImpl* info = GetRequestInfo(); . ResourceMsg_RequestCompleteData request_complete_data; request_complete_data.error_code = error_code; request_complete_data.was_ignored_by_handler = was_ignored_by_handler; request_complete_data.exists_in_cache = request()-response_info().was_cached; request_complete_data.security_info = security_info; request_complete_pletion_time = TimeTicks:Now(); request_complete_data.encoded_data_length = request()-GetTotalReceivedBytes(); info-filter()-Send( new ResourceMsg_RequestComplete(GetRequestID(), request_complete_data); 这个函数定义在文件external/chromium_org/content/browser/loader/async_resource_handler.cc中。 AsyncResourceHandler类的成员函数OnResponseCompleted所做的事情是向Render进程发送一个类型为ResourceMsg_RequestComplete的IPC消息,用来通知Render进程它所请求的网页内容已下载完毕。 Render进程是通过ResourceDispatcher类的成员函数DispatchMessage接收类型为ResourceMsg_RequestComplete的IPC消息的,如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void ResourceDispatcher:DispatchMessage(const IPC:Message& message) IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher, message) . IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete, OnRequestComplete) IPC_END_MESSAGE_MAP() 这个函数定义在文件external/chromium_org/content/child/resource_dispatcher.cc中。 从这里可以看到,ResourceDispatcher类的成员函数DispatchMessage将类型为ResourceMsg_RequestComplete的IPC消息分发给另外一个成员函数OnRequestComplete处理。 ResourceDispatcher类的成员函数OnRequestComplete的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void ResourceDispatcher:OnRequestComplete( int request_id, const ResourceMsg_RequestCompleteData& request_complete_data) . PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); . RequestPeer* peer = request_info-peer; . peer-OnCompletedRequest(request_complete_data.error_code, request_complete_data.was_ignored_by_handler, request_complete_data.exists_in_cache, request_complete_data.security_info, renderer_completion_time, request_complete_data.encoded_data_length); 这个函数定义在文件external/chromium_org/content/child/resource_dispatcher.cc中。 从前面一文可以知道,Render进程在请求Browser进程下载指定URL对应的网页内容之前,会创建一个PendingRequestInfo对象。这个PendingRequestInfo对象以一个Request ID为键值保存在ResourceDispatcher类的内部。这个Request ID即为参数request_id描述的Request ID。因此,ResourceDispatcher类的成员函数OnRequestComplete可以通过参数request_id获得一个PendingRequestInfo对象。有了这个PendingRequestInfo对象之后,ResourceDispatcher类的成员函数OnSetDataBuffer再通过它的成员变量peer获得一个WebURLLoaderImpl:Context对象,并且调用它的成员函数OnCompletedRequest通知它下载网页内容的请求已完成。 WebURLLoaderImpl:Context类的成员函数OnCompletedRequest的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void WebURLLoaderImpl:Context:OnCompletedRequest( int error_code, bool was_ignored_by_handler, bool stale_copy_in_cache, const std:string& security_info, const base:TimeTicks& completion_time, int64 total_transfer_size) . if (client_) if (error_code != net:OK) client_-didFail(loader_, CreateError(request_.url(), stale_copy_in_cache, error_code); else client_-didFinishLoading( loader_, (completion_time - TimeTicks().InSecondsF(), total_transfer_size); . 这个函数定义在文件external/chromium_org/content/child/web_url_loader_impl.cc中。 从前面一文可以知道,WebURLLoaderImpl:Context类的成员变量client_指向的是WebKit模块中的一个ResourceLoader对象。在成功下载完成网页内容的情况下,WebURLLoaderImpl:Context类的成员函数OnCompletedRequest调用这个ResourceLoader对象的成员函数didFinishLoading通知WebKit结束解析网页内容。 ResourceLoader类的成员函数didFinishLoading的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void ResourceLoader:didFinishLoading(blink:WebURLLoader*, double finishTime, int64 encodedDataLength) . m_resource-finish(finishTime); . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp中。 ResourceLoader类的成员变量m_resource描述的是一个RawResource对象。这个RawResource对象的创建过程可以参考前面一文。ResourceLoader类的成员函数didFinishLoading调用这个RawResource对象的成员函数finish结束加载网页内容。 RawResource类的成员函数finish是从父类Resource继承下来的,它的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void Resource:finish(double finishTime) . finishOnePart(); . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/fetch/Resource.cpp中。 Resource类的成员函数finish调用另外一个成员函数finishOnePart结束加载网页的内容。注意Resource类的成员函数finishOnePart的命名。有前面一文中,我们提到,当网页内容的MIME类型为“multipart/x-mixed-replace”时,下载回来网页内容实际是包含多个部分的,每一个部分都有着自己的MIME类型。每一个部分下载完成时,都会调用Resource类的成员函数finishOnePart进行处理。为了统一接口,对于MIME类型不是“multipart/x-mixed-replace”的网页内容而言,下载回来的网页内容也是当作一个部分进行整体处理。 Resource类的成员函数finishOnePart的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void Resource:finishOnePart() . checkNotify(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/fetch/Resource.cpp中。 Resource类的成员函数finishOnePart调用另外一个成员函数checkNotify通知当前正在前处理的Resource对象的Client,它们所关注的资源,也就是网页内容,已经下载完成了。 Resource类的成员函数checkNotify的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void Resource:checkNotify() . ResourceClientWalker w(m_clients); while (ResourceClient* c = w.next() c-notifyFinished(this); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/fetch/Resource.cpp中。 从前面一文可以知道,在Resource类的成员变量m_clients中,保存有一个DocumentLoader对象。这个DocumentLoader对象是从ResourceClient类继承下来的,它负责创建和加载网页的文档对象。Resource类的成员函数checkNotify会调用这个DocumentLoader对象的成员函数notifyFinished通知它要加载的网页的内容已经下载完成了。 DocumentLoader类的成员函数notifyFinished的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void DocumentLoader:notifyFinished(Resource* resource) . if (!m_mainResource-errorOccurred() & !m_mainResource-wasCanceled() finishedLoading(m_mainResource-loadFinishTime(); return; . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/loader/DocumentLoader.cpp中。 DocumentLoader类的成员变量m_mainResource指向的是一个RawResource对象。这个RawResource对象和前面分析的ResourceLoader类的成员变量m_resource指向的是同一个RawResource对象。这个RawResource对象代表正在请求下载的网页内容。在网页内容成功下载完成的情况下,DocumentLoader类的成员函数notifyFinished就会调用另外一个成员函数finishedLoading进行结束处理。 DocumentLoader类的成员函数finishedLoading的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void DocumentLoader:finishedLoading(double finishTime) . endWriting(m_writer.get(); . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/loader/DocumentLoader.cpp中。 从前面一文可以知道,DocumentLoader类的成员变量m_writer指向的是一个DocumentWriter对象。DocumentLoader类的成员函数finishedLoading调用另外一个成员函数endWriting告诉这个DocumentWriter对象结束对正在加载的网页内容的解析。 DocumentLoader类的成员函数endWriting的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void DocumentLoader:endWriting(DocumentWriter* writer) . m_writer-end(); . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/loader/DocumentLoader.cpp中。 DocumentLoader类的成员函数endWriting调用上述DocumentWriter对象的成员函数end结束对正在加载的网页内容的解析。 DocumentWriter类的成员函数end的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void DocumentWriter:end() . m_parser-finish(); . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/loader/DocumentWriter.cpp中。 从前面一文可以知道,DocumentWriter类的成员变量m_parser指向的是一个HTMLDocumentParser对象。DocumentWriter类的成员函数end调用这个HTMLDocumentParser对象的成员函数finish结束对正在加载的网页内容的解析。 HTMLDocumentParser类的成员函数finish的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLDocumentParser:finish() . attemptToEnd(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp中。 HTMLDocumentParser类的成员函数finish调用另外一个成员函数attemptToEnd结束对正在加载的网页内容的解析。 HTMLDocumentParser类的成员函数attemptToEnd的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLDocumentParser:attemptToEnd() / finish() indicates we will not receive any more data. If we are waiting on / an external script to load, we cant finish parsing quite yet. if (shouldDelayEnd() m_endWasDelayed = true; return; prepareToStopParsing(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp中。 如果网页包含外部JavaScript脚本,并且这些外部JavaScript脚本还没有下载回来,那么这时候HTMLDocumentParser类的成员函数attemptToEnd就还不能结束对正在加载的网页内容的解析,必须要等到外部JavaScript脚本下载回来之后才能进行结束。 另一方面,如果网页没有包含外部JavaScript脚本,那么HTMLDocumentParser类的成员函数attemptToEnd就会马上调用另外一个成员函数prepareToStopParsing结束对正在加载的网页内容的解析。在网页包含外部JavaScript脚本的情况下,等到这些外部JavaScript脚本下载回来处理之后,HTMLDocumentParser类的成员函数prepareToStopParsing也是同样会被调用的。因此,接下来我们就继续分析HTMLDocumentParser类的成员函数prepareToStopParsing的实现。 HTMLDocumentParser类的成员函数prepareToStopParsing的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLDocumentParser:prepareToStopParsing() . attemptToRunDeferredScriptsAndEnd(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp中。 HTMLDocumentParser类的成员函数prepareToStopParsing调用另外一个成员函数attemptToRunDeferredScriptsAndEnd执行那些被延后执行的JavaScript脚本,以及结束对正在加载的网页内容的解析。 HTMLDocumentParser类的成员函数attemptToRunDeferredScriptsAndEnd的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLDocumentParser:attemptToRunDeferredScriptsAndEnd() . if (m_scriptRunner & !m_scriptRunner-executeScriptsWaitingForParsing() return; end(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp中。 HTMLDocumentParser类的成员变量m_scriptRunner指向的是一个HTMLScriptRunner对象。HTMLDocumentParser类的成员函数attemptToRunDeferredScriptsAndEnd调用这个HTMLScriptRunner对象的成员函数executeScriptsWaitingForParsing执行那些被延后执行的JavaScript脚本之后,就会调用HTMLDocumentParser类的成员函数end结束对正在加载的网页内容的解析。 HTMLDocumentParser类的成员函数end的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLDocumentParser:end() . / Informs the the rest of WebCore that parsing is really finished (and deletes this). m_treeBuilder-finished(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp中。 HTMLDocumentParser类的成员变量m_treeBuilder指向的是一个HTMLTreeBuilder对象。HTMLDocumentParser类的成员函数end调用这个HTMLTreeBuilder对象的成员函数finished告诉它结束对网页内容的解析。 HTMLTreeBuilder类的成员函数finished的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLTreeBuilder:finished() . m_tree.finishedParsing(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp中。 HTMLTreeBuilder类的成员变量m_tree描述的是一个HTMLConstructionSite对象。从前面一文可以知道,这个HTMLConstructionSite对象就是用来构造网页的DOM Tree的,HTMLTreeBuilder类的成员函数finished调用它的成员函数finishedParsing告诉它结束构造网页的DOM Tree。 HTMLConstructionSite类的成员函数finishedParsing的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void HTMLConstructionSite:finishedParsing() . m_document-finishedParsing(); 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp中。 HTMLConstructionSite类的成员变量m_document指向的是一个HTMLDocument对象。这个HTMLDocument对象描述的是网页的DOM Tree的根节点,HTMLConstructionSite类的成员函数finishedParsing调用它的成员函数finishedParsing通知它DOM Tree创建结束。 HTMLDocument类的成员函数finishedParsing是从父类Document继承下来的,它的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void Document:finishedParsing() . if (RefPtr f = frame() . const bool mainResourceWasAlreadyRequested = m_frame-loader().stateMachine()-committedFirstRealDocumentLoad(); . if (mainResourceWasAlreadyRequested) updateRenderTreeIfNeeded(); . . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/dom/Document.cpp中。 HTMLDocument类的成员函数finishedParsing首先判断网页的主资源是否已经请求回来了。在请求回来的情况下,才会调用另外一个成员函数updateRenderTreeIfNeeded创建一个Render Object Tree。网页的主资源,指的就是网页文本类型的内容,不包括Image、CSS和Script等资源。 HTMLDocument类的成员函数updateRenderTreeIfNeeded也是从父类Document继承下来的,它的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片class Document : public ContainerNode, public TreeScope, public SecurityContext, public ExecutionContext, public ExecutionContextClient , public DocumentSupplementable, public LifecycleContext . public: . void updateRenderTreeIfNeeded() updateRenderTree(NoChange); . ; 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/dom/Document.h中。 HTMLDocument类的成员函数updateRenderTreeIfNeeded调用另外一个成员函数updateRenderTree创建一个Render Object Tree。 HTMLDocument类的成员函数updateRenderTree是从父类Document继承下来的,它的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void Document:updateRenderTree(StyleRecalcChange change) . updateStyle(change); . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/dom/Document.cpp中。 Document类的成员函数updateRenderTree会调用另外一个成员函数updateStyle更新网页各个元素的CSS属性。Document类的成员函数updateStyle在更新网页各个元素的CSS属性的过程中,会分别为它们创建一个对应的Render Object。这些Render Object最终就会形成一个Render Object Tree。 Document类的成员函数updateStyle的实现如下所示:cpp view plain copy 在CODE上查看代码片派生到我的代码片void Document:updateStyle(StyleRecalcChange change) . if (styleChangeType() = SubtreeStyleChange) change = Force; . if (change = Force) . RefPtr documentStyle = StyleResolver:styleForDocument(*this); StyleRecalcChange localChange = RenderStyle:stylePropagationDiff(documentStyle.get(), renderView()-style(); if (localChange != NoCange) renderView()-setStyle(documentStyle.release(); . if (Element* documentElement = this-documentElement() . if (documentElement-shouldCallRecalcStyle(change) documentElement-recalcStyle(change); . . 这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/dom/Document.cpp中。 从前面一文可以知道,当前正在处理的Document对象实际上是一个HTMLDocument对象。这个HTMLDocument对象即为网页DOM Tree的根节点,它的子孙节点就是网页中的各个HTML标签。在DOM Tree创建之初,这些HTML标签的CSS属性还没有进行计算,因此这时候DOM Tree的根节点就会被标记为子树CSS属性需要进行计算,也就是调用当前正在处理的Document对象的成员函数styleChangeType获得的值会等于SubtreeStyleChange。在这种情况下,参数change的值也会被修改为Force,表示要对每一个HTML标签的CSS属性进行一次计算和设置。 接下来,Document类的成员函数updateStyle首先是计算根节点的CSS属性,这是通过调用StyleResolver类的静态成员函数styleForDocument实现的,接着又比较根节点新的CSS属性与旧的CSS属性是否有不同的地方。如果有不同的地方,那么就会将新的CSS属性值保存在与根节点对应的Render Objec
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 油库合作方案(3篇)
- 装备采购排查方案(3篇)
- 板材改色处理方案(3篇)
- 幕墙项目维修方案(3篇)
- 电容柜安装方案(3篇)
- 焦作新材料职业学院《语言基础及应用》2023-2024学年第二学期期末试卷
- 企业联合供暖方案(3篇)
- 讲座备用方案及(3篇)
- 吉安职业技术学院《公共艺术基础》2023-2024学年第二学期期末试卷
- 阴极保护采购方案(3篇)
- 租房合同到期交接协议书
- 中国废旧轮胎橡胶粉项目投资计划书
- 子宫内膜异位性疾病护理
- 人工智能芯片研究报告
- 2025贵州中考:历史高频考点
- pc构件吊装安全专项施工方案
- 汽车质量意识培训
- 新疆开放大学2025年春《国家安全教育》形考作业1-4终考作业答案
- 管网工程有限空间内清淤作业检测修复安全专项施工方案
- 成本预算绩效分析实施案例
- 2025年中质协注册质量经理认证考试题库大全(含答案)
评论
0/150
提交评论