您的位置:首页 > 其它

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

2008-10-09 21:55 225 查看
继续上一次来分析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的实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: