繼續上一次來分析
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
的實現。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
