Layout Object Tree 创建

本文详细分析了网页加载完成后,从DOM Tree到Layout Object Tree的创建过程。从Browser进程下载内容到Render进程接收并处理,最终通过ResourceDispatcher、ResourceLoader、WebURLLoaderImpl等组件协同工作,构建DOM Tree。当内容下载完成后,DocumentLoader调用DocumentWriter和HTMLDocumentParser的相关方法,完成HTML解析,然后计算CSS属性,构建Layout Object Tree。Layout Object Tree的每个节点对应需要渲染的DOM节点,用于网页的渲染和布局。
摘要由CSDN通过智能技术生成

站在老罗的肩膀上:https://blog.csdn.net/luoshengyang/article/details/50615628

每一个HTML标签在DOM Tree中都有一个对应的HTMLElement节点。相应地,在DOM Tree中每一个需要渲染的HTMLElement节点在Layout  Object Tree中都有一个对应的Layout  Object节点,如图1所示(To Update):

图1 Layout  Object Tree与DOM Tree、Render Layer Tree和Graphics Layer Tree的关系

       从图1还可以看到,Layout  Object Tree创建完成之后,WebKit还会继续根据它的内容创建一个Layout  Layer Tree和一个Graphics Layer Tree。本文主要关注Render Object Tree的创建过程。

       从前面Chromium DOM Tree创建过程分析一文还可以知道,DOM Tree是在网页内容的下载过程中创建的。一旦网页内容下载完成,DOM Tree就创建完成了。网页的Layout  Object Tree与DOM Tree不一样,它是在网页内容下载完成之后才开始创建的。因此,接下来我们就从网页内容下载完成时开始分析网页的Layout  Object Tree的创建过程。

       从前面Chromium网页URL加载过程分析一文可以知道,WebKit是通过Browser进程下载网页内容的。Browser进程一方面通过Net模块中的URLRequest类去Web服务器请求网页内容,另一方面又通过Content模块中的ResourceLoader类的成员函数OnReadCompleted不断地获得URLRequest类请求回来的网页内容,如下所示:

void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
               "ResourceLoader::OnReadCompleted");
  DCHECK_EQ(request_.get(), unused);
  DVLOG(1) << "OnReadCompleted: \"" << request_->url().spec() << "\""
           << " bytes_read = " << bytes_read;

  pending_read_ = false;

  // bytes_read == -1 always implies an error.
  if (bytes_read == -1 || !request_->status().is_success()) {
    ResponseCompleted();
    return;
  }

  CompleteRead(bytes_read);
}

  src/content/browser/loader/resource_loader.cc

参数bytes_read表示当前这次从URLRequest类中读取回来的网页内容的长度。当这个长度值等于0的时候,就表示所有的网页内容已经读取完毕。这时候ResourceLoader类的成员函数OnReadCompleted就会调用另外一个成员函数ResponseCompleted进行下一步处理。

       ResourceLoader类的成员函数ResponseCompleted的实现如下所示:

void ResourceLoader::ResponseCompleted() {
  TRACE_EVENT_WITH_FLOW0("loading", "ResourceLoader::ResponseCompleted", this,
                         TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);

  DVLOG(1) << "ResponseCompleted: " << request_->url().spec();

  ScopedDeferral scoped_deferral(this, DEFERRED_FINISH);
  handler_->OnResponseCompleted(request_->status(),
                                std::make_unique<Controller>(this));
}

src/content/browser/loader/mojo_async_resource_handler.cc 

      在前面Chromium网页URL加载过程分析一文中,我们假设ResourceLoader类的成员变量handler_指向的是一个MojoAsyncResourceHandler对象。ResourceLoader类的成员函数ResponseCompleted调用这个MojoAsyncResourceHandler对象的成员函数OnResponseCompleted进行下一步处理。

      MojoAsyncResourceHandler类的成员函数OnResponseCompleted的实现如下所示:

void MojoAsyncResourceHandler::OnResponseCompleted(
    const net::URLRequestStatus& request_status,
    std::unique_ptr<ResourceController> controller) {
  ...
  url_loader_client_->OnComplete(loader_status);
  ...
}

src/content/browser/loader/mojo_async_resource_handler.cc 

void URLLoaderClientProxy::OnComplete(
    const network::URLLoaderCompletionStatus& in_status) {
  ...
  auto message = URLLoaderClientProxy_OnComplete_Message::Build(
      kSerialize, kExpectsResponse, kIsSync, std::move(in_status));
  ...
  ignore_result(receiver_->Accept(&message));
}

src/out/Debug/gen/services/network/public/mojom/url_loader.mojom.cc 

receiver为renderer进程的AsyncResourceHandler类的成员函数OnResponseCompleted所做的事情是向Render进程发送一个类型为ResourceMsg_RequestComplete的IPC消息,用来通知Render进程它所请求的网页内容已下载完毕。

       Render进程是通过ResourceDispatcher类的成员函数DispatchMessage接收类型为ResourceMsg_RequestComplete的IPC消息的,如下所示:

How renderer process accept message from browser
...Missing...

      从这里可以看到,ResourceDispatcher类的成员函数DispatchMessage将类型为mojo::Messege消息分发给另外一个成员函数OnRequestComplete处理。

      ResourceDispatcher类的成员函数OnRequestComplete的实现如下所示:

void ResourceDispatcher::OnRequestComplete(
    int request_id,
    const network::URLLoaderCompletionStatus& status) {
  TRACE_EVENT0("loader", "ResourceDispatcher::OnRequestComplete");

  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
  ...
  RequestPeer* peer = request_info->peer.get();
  ...
  peer->OnCompletedRequest(renderer_status);
}

src/content/renderer/loader/resource_dispatcher.cc

从前面Chromium网页URL加载过程分析一文可以知道,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的实现如下所示:

void WebURLLoaderImpl::RequestPeerImpl::OnCompletedRequest(
    const network::URLLoaderCompletionStatus& status) {
  context_->OnCompletedRequest(status);
}
void WebURLLoaderImpl::Context::OnCompletedRequest(
    const network::URLLoaderCompletionStatus& status) {
  ...
  if (client_) {
    ...
      client_->DidFail(
          status.cors_error_status
              ? WebURLError(*status.cors_error_status, has_copy_in_cache, url_)
              : WebURLError(status.error_code, status.extended_error_code,
                            has_copy_in_cache,
                            WebURLError::IsWebSecurityViolation::kFalse, url_),
          total_transfer_size, encoded_body_size, status.decoded_body_length);
    } else {
      client_->DidFinishLoading(status.completion_time, total_transfer_size,
                                encoded_body_size, status.decoded_body_length,
                                status.should_report_corb_blocking);
    }
  }
}

src/content/renderer/loader/web_url_loader_impl.cc 

       从前面Chromium网页URL加载过程分析一文可以知道,WebURLLoaderImpl::Context类的成员变量client_指向的是WebKit模块中的一个ResourceLoader对象。在成功下载完成网页内容的情况下,WebURLLoaderImpl::Context类的成员函数OnC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值