谷歌浏览器的源码分析(23)

系统 1587 0
 

继续上一次来分析 LoadRequest 的代码,在分析这个函数代码之前,先看看 WebFrame 类的继承层次关系,如下:

class WebFrame : public base::RefCounted<WebFrame> {

WebFrame 是一个接口类,但它先继承引用计数类 RefCounted ,这样对于这个对象多次访问,就可以使用引用计数来判断对象的生命周期了。对于 base::RefCounted<WebFrame> 的语法,其实它是一种模板实现的多态特性,这种方案是最高效的实现方式,比使用虚函数更少占内存,并且运行的速度也更快。它就是解决如下的问题:

  void Release() {

    if (subtle::RefCountedBase::Release()) {

      delete static_cast<T*>(this);

    }

  }

上面的函数里 static_cast<T*>(this) ,它就是一种多态的实现方法,由于 base::RefCounted 类并没有声明为虚析构函数,如下:

template <class T>

class RefCounted : public subtle::RefCountedBase {

  public:

  RefCounted() { }

  ~RefCounted() { }

 

既然没有把类 RefCounted 声明为虚析构函数,又想在基类里调用派生类的析构函数,只好使用 static_cast 和类型转换了,这是一种比较好的模板使用方法,在 WTL 里就大量使用这种技术。

接着可以看到:

class WebFrameImpl : public WebFrame {

  public:

  WebFrameImpl();

  ~WebFrameImpl();

WebFrameImpl 是继承接口类 WebFrame ,这里是使用接口与实现分析的设计模式,这样更方便代码灵活地复用。可见设计 Chrome 的设计师和写代码的程序员,都是顶尖的模板高手,大部的思想与 WTL 库的设计是一脉相承。也难怪 Chrome 的浏览器使用 WTL 库来设计界面。

 

#001   void WebFrameImpl::LoadRequest(WebRequest* request) {

#002     SubstituteData data;

#003     InternalLoadRequest(request, data, false);

#004   }

WebFrame 里调用函数 LoadRequest ,实际上是调用实现类 WebFrameImpl 函数 LoadRequest ,而在这个函数又是调用 InternalLoadRequest 来实现的,它的代码如下:

#001   void WebFrameImpl::InternalLoadRequest(const WebRequest* request,

#002                                          const SubstituteData& data,

#003                                          bool replace) {

 

// 转换请求参数。

#004     const WebRequestImpl* request_impl =

#005         static_cast<const WebRequestImpl*>(request);

#006  

 

获取请求的资源。

#007     const ResourceRequest& resource_request =

#008         request_impl->frame_load_request().resourceRequest();

#009  

#010     // Special-case javascript URLs.   Do not interrupt the existing load when

#011     // asked to load a javascript URL unless the script generates a result.

#012     // We can't just use FrameLoader::executeIfJavaScriptURL because it doesn't

#013     // handle redirects properly.

 

获取需要下载网页的地址。

#014     const KURL& kurl = resource_request.url();

 

处理加载 javascript 的连接情况。

#015     if (!data.isValid() && kurl.protocol() == "javascript") {

#016       // Don't attempt to reload javascript URLs.

#017       if (resource_request.cachePolicy() == ReloadIgnoringCacheData)

#018         return;

#019  

#020       // We can't load a javascript: URL if there is no Document!

#021       if (!frame_->document())

#022         return;

#023  

#024       // TODO(darin): Is this the best API to use here?   It works and seems good,

#025       // but will it change out from under us?

#026       DeprecatedString script =

#027           KURL::decode_string(kurl.deprecatedString().mid(sizeof("javascript:")-1));

#028       bool succ = false;

 

加载执行脚本。

#029       WebCore::String value =

#030           frame_->loader()->executeScript(script, &succ, true);

#031       if (succ && !frame_->loader()->isScheduledLocationChangePending()) {

#032         // TODO(darin): We need to figure out how to represent this in session

#033         // history.   Hint: don't re-eval script when the user or script navigates

#034         // back-n-forth (instead store the script result somewhere).

#035         LoadDocumentData(kurl, value, String("text/html"), String());

#036       }

#037       return;

#038     }

#039  

 

停止上一次没有完成的加载情况。

#040     StopLoading();   // make sure existing activity stops

#041  

#042     // Keep track of the request temporarily.   This is effectively a way of

#043     // passing the request to callbacks that may need it.   See

#044     // WebFrameLoaderClient::createDocumentLoader.

 

保存当前的请求连接。

#045     currently_loading_request_ = request;

#046  

#047     // If we have a current datasource, save the request info on it immediately.

#048     // This is because WebCore may not actually initiate a load on the toplevel

#049     // frame for some subframe navigations, so we want to update its request.

 

获取当前数据源,如果已经存在就可以保存它。

#050     WebDataSourceImpl* datasource = GetDataSourceImpl();

#051     if (datasource)

#052       CacheCurrentRequestInfo(datasource);

#053  

 

如果数据有效就可以直接替换就行了。

#054     if (data.isValid()) {

#055       frame_->loader()->load(resource_request, data);

#056       if (replace) {

#057         // Do this to force WebKit to treat the load as replacing the currently

#058         // loaded page.

#059         frame_->loader()->setReplacing();

#060       }

 

如果是历史网页选择,就判断是否出错的加载处理。

#061     } else if (request_impl->history_item()) {

#062       // Use the history item if we have one, otherwise fall back to standard

#063       // load.

#064       RefPtr<HistoryItem> current_item = frame_->loader()->currentHistoryItem();

#065  

#066       // If there is no current_item, which happens when we are navigating in

#067       // session history after a crash, we need to manufacture one otherwise

#068       // WebKit hoarks. This is probably the wrong thing to do, but it seems to

#069        // work.

#070       if (!current_item) {

#071         current_item = new HistoryItem(KURL("about:blank"), "");

#072         frame_->loader()->setCurrentHistoryItem(current_item);

#073         frame_->page()->backForwardList()->setCurrentItem(current_item.get());

#074  

#075         // Mark the item as fake, so that we don't attempt to save its state and

#076         // end up with about:blank in the navigation history.

#077         frame_->page()->backForwardList()->setCurrentItemFake(true);

#078       }

#079  

#080       frame_->loader()->goToItem(request_impl->history_item().get(),

#081                                  WebCore::FrameLoadTypeIndexedBackForward);

 

重新加载网页。

#082     } else if (resource_request.cachePolicy() == ReloadIgnoringCacheData) {

#083       frame_->loader()->reload();

 

 

下面开始调用 load 来加载新下载的网页资源。

#084     } else {

#085       frame_->loader()->load(resource_request);

#086     }

#087  

#088     currently_loading_request_ = NULL;

#089   }

 

上面通过几种情况来分别实现了加载 javascript 网页的处理,还有历史选项处理,还有重新加载网页和加载新网页的处理。下一次再来分析加载新网页的函数 frame_->loader()->load 的实现。

谷歌浏览器的源码分析(23)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论