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

 

继续上一次来分析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))