WebKit內核分析之FrameLoader

參考地址:http://blog.csdn.net/dlmu2001/article/details/6168545html

FrameLoader類負責一個Frame的加載,在Frame的流程中起到很是重要的做用,同不少組件都有交互,本文將分析FrameLoader類的代碼web

1. 概述

     顧名思義,FrameLoader是一個Frame的loader,它的做用就是爲客戶端提供一個下載一個Frame的一系列的接口。這裏的客戶指的是類的客戶,好比Frame類,間接客戶是上層應用,好比 qwebframe瀏覽器

     從它的定義看,最容易想到的是一個load接口,用來將一個frame load下來。任何一個頁面都須要一個mainframe,所以一個頁面的下載通常就是從load 一個 mainframe開始網絡

     在 load frame的過程當中,經過FrameLoaderClient接口將load過程的不一樣階段告知客戶app

     FrameLoader經過 setDocumentLoader至關於把load的工做委託給了 DocumentLoader類dom

     FrameLoader同 DocumentLoader是has-a的關係。通常在load的時候建立 DocumentLoader。Frame調用DocumentLoader的startLoadingMainResource開始 load frameide

類數據代碼:函數

 1 class FrameLoader {
 2     WTF_MAKE_NONCOPYABLE(FrameLoader);
 3 private:
 4     Frame* m_frame;
 5     FrameLoaderClient* m_client;
 6 
 7     mutable PolicyChecker m_policyChecker;
 8     mutable HistoryController m_history;
 9     mutable ResourceLoadNotifier m_notifer;
10     mutable SubframeLoader m_subframeLoader;
11     mutable FrameLoaderStateMachine m_stateMachine;
12 
13     FrameState m_state;
14     FrameLoadType m_loadType;
15 
16     // Document loaders for the three phases of frame loading. Note that while 
17     // a new request is being loaded, the old document loader may still be referenced.
18     // E.g. while a new request is in the "policy" state, the old document loader may
19     // be consulted in particular as it makes sense to imply certain settings on the new loader.
20     RefPtr<DocumentLoader> m_documentLoader;
21     RefPtr<DocumentLoader> m_provisionalDocumentLoader;
22     RefPtr<DocumentLoader> m_policyDocumentLoader;
23 
24     bool m_delegateIsHandlingProvisionalLoadError;
25 
26     bool m_quickRedirectComing;
27     bool m_sentRedirectNotification;
28     bool m_inStopAllLoaders;
29 
30     String m_outgoingReferrer;
31 
32     bool m_isExecutingJavaScriptFormAction;
33 
34     bool m_didCallImplicitClose;
35     bool m_wasUnloadEventEmitted;
36     bool m_pageDismissalEventBeingDispatched;
37     bool m_isComplete;
38     bool m_isLoadingMainResource;
39 
40     RefPtr<SerializedScriptValue> m_pendingStateObject;
41 
42     KURL m_workingURL;
43 
44     OwnPtr<IconLoader> m_iconLoader;
45     bool m_mayLoadIconLater;
46 
47     bool m_needsClear;
48 
49     KURL m_submittedFormURL;
50 
51     Timer<FrameLoader> m_checkTimer;
52     bool m_shouldCallCheckCompleted;
53     bool m_shouldCallCheckLoadComplete;
54 
55     Frame* m_opener;
56     HashSet<Frame*> m_openedFrames;
57 
58     bool m_didPerformFirstNavigation;
59     bool m_loadingFromCachedPage;
60     bool m_suppressOpenerInNewFrame;
61 
62     SandboxFlags m_sandboxFlags;
63     SandboxFlags m_forcedSandboxFlags;
64 
65     RefPtr<FrameNetworkingContext> m_networkingContext;
66 
67     KURL m_previousUrl;
68 }

 

2. 類關係

 

1,Frame 和 FrameLoader 是 contain-a的關係,在 Frame的構造函數中調用 FraomeLoader的構造函數,調用時傳入參數 Frame指針 和 FrameLoaderClient指針post

 1 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
 2     : m_page(page)
 3     , m_treeNode(this, parentFromOwnerElement(ownerElement))
 4     , m_loader(this, frameLoaderClient)
 5     , m_navigationScheduler(this)
 6     , m_ownerElement(ownerElement)
 7     , m_script(this)
 8     , m_editor(this)
 9     , m_selectionController(this)
10     , m_eventHandler(this)
11     , m_animationController(this)
12     , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
13     , m_pageZoomFactor(parentPageZoomFactor(this))
14     , m_textZoomFactor(parentTextZoomFactor(this))
15     , m_pageScaleFactor(1)
16 #if ENABLE(ORIENTATION_EVENTS)
17     , m_orientation(0)
18 #endif
19     , m_inViewSourceMode(false)
20     , m_isDisconnected(false)
21     , m_excludeFromTextSearch(false)
22 #if ENABLE(MEDIA_STREAM)
23     , m_mediaStreamFrameController(RuntimeEnabledFeatures::mediaStreamEnabled() ? adoptPtr(new MediaStreamFrameController(this)) : PassOwnPtr<MediaStreamFrameController>())
24 #endif
25 {
26      ....
27 }

2,Frame 有可能有子Frame, 因此維護 SubFrameLoader對象 m_subframeLoader來管理子 Frame 的load。  Frame能夠對應 xml document,也能夠對應html document,等。跟Document相關的子resource的load不在FrameLoader的職責範圍內。ui

3,包含一個DocumentWriter類對象 m_writer,當Frame的數據 load finish的時候,將數據傳給 DocumentWriter類,進行下一步的處理(好比解碼)

4,FrameLoader維護三個 DocumentLoader對象,分別對應不一樣的階段。 

1     RefPtr<DocumentLoader> m_documentLoader;
2     RefPtr<DocumentLoader> m_provisionalDocumentLoader;
3     RefPtr<DocumentLoader> m_policyDocumentLoader;

 m_policyDocumentLoader 對應於 收到用戶 load 調用,進行 policy check 階段

 m_provisionalDocumentLoader 對應於 policy check 經過以後,Frame數據尚未到來以前,它會負責 startLoadingMainResource的調用

 m_documentLoader 則是 Frame第一個數據到來之後使用的 DocumentLoader,這個時候,前一個主 Frame 的 DocumentLoader已經不能再用(user agent開始白屏,刷掉前一個頁面的顯示)

 1 inline void Frame::init()
 2 {
 3     m_loader.init();
 4 }
 5 
 6 void FrameLoader::init()
 7 {
 8     // Propagate sandbox attributes to this Frameloader and its descendants.
 9     // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
10     updateSandboxFlags();
11 
12     // this somewhat odd set of steps is needed to give the frame an initial empty document
13     m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
14     setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
15     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
16     setState(FrameStateProvisional);
17     m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
18     m_provisionalDocumentLoader->finishedLoading();
19     m_documentLoader->writer()->begin(KURL(), false);
20     m_documentLoader->writer()->end();
21     m_frame->document()->cancelParsing();
22     m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
23     m_didCallImplicitClose = true;
24 
25     m_networkingContext = m_client->createNetworkingContext();
26 }

從上面代碼能夠看出,在Frame初始化的時候,僅僅調用FrameLoader的初始化函數

而後FrameLoader初始化的時候,首先把狀態機的狀態標識成 FrameLoaderStateMachine::CreatingInitialEmptyDocument ,而後調用客戶端實現建立一個DocumentLoader,而後設置爲PolicyDocumentLoader,而且設置ProvisionalDocumentLoader和PolicyDocumentLoader爲同一個loader,而且設置FrameState狀態爲 Provisional(初始化爲commitPage狀態)

而後把狀態機狀態更新爲  FrameLoaderStateMachine::DisplayingInitialEmptyDocument  完成初始化

後面還有一次load的變遷:

  1 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
  2 {
  3     ASSERT(m_client->hasWebView());
  4     ASSERT(m_state == FrameStateProvisional);
  5 
  6     if (m_state != FrameStateProvisional)
  7         return;
  8 
  9     if (m_frame->view())
 10         m_frame->view()->scrollAnimator()->cancelAnimations();
 11 
 12     m_client->setCopiesOnScroll();
 13     history()->updateForCommit();
 14 
 15     // The call to closeURL() invokes the unload event handler, which can execute arbitrary
 16     // JavaScript. If the script initiates a new load, we need to abandon the current load,
 17     // or the two will stomp each other.
 18     DocumentLoader* pdl = m_provisionalDocumentLoader.get();
 19     if (m_documentLoader)
 20         closeURL();
 21     if (pdl != m_provisionalDocumentLoader)
 22         return;
 23 
 24     // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
 25     if (m_documentLoader)
 26         m_documentLoader->stopLoadingSubresources();
 27     if (m_documentLoader)
 28         m_documentLoader->stopLoadingPlugIns();
 29 
 30     setDocumentLoader(m_provisionalDocumentLoader.get());
 31     setProvisionalDocumentLoader(0);
 32     setState(FrameStateCommittedPage);
 33 
 34     // Handle adding the URL to the back/forward list.
 35     DocumentLoader* dl = m_documentLoader.get();
 36 
 37     switch (m_loadType) {
 38         case FrameLoadTypeForward:
 39         case FrameLoadTypeBack:
 40         case FrameLoadTypeIndexedBackForward:
 41             if (m_frame->page()) {
 42                 // If the first load within a frame is a navigation within a back/forward list that was attached
 43                 // without any of the items being loaded then we need to update the history in a similar manner as
 44                 // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
 45                 if (!m_stateMachine.committedFirstRealDocumentLoad())
 46                     history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
 47 
 48                 history()->updateForBackForwardNavigation();
 49 
 50                 // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
 51                 if (history()->currentItem() && !cachedPage)
 52                     m_pendingStateObject = history()->currentItem()->stateObject();
 53 
 54                 // Create a document view for this document, or used the cached view.
 55                 if (cachedPage) {
 56                     DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
 57                     ASSERT(cachedDocumentLoader);
 58                     cachedDocumentLoader->setFrame(m_frame);
 59                     m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
 60 
 61                 } else
 62                     m_client->transitionToCommittedForNewPage();
 63             }
 64             break;
 65 
 66         case FrameLoadTypeReload:
 67         case FrameLoadTypeReloadFromOrigin:
 68         case FrameLoadTypeSame:
 69         case FrameLoadTypeReplace:
 70             history()->updateForReload();
 71             m_client->transitionToCommittedForNewPage();
 72             break;
 73 
 74         case FrameLoadTypeStandard:
 75             history()->updateForStandardLoad();
 76             if (m_frame->view())
 77                 m_frame->view()->setScrollbarsSuppressed(true);
 78             m_client->transitionToCommittedForNewPage();
 79             break;
 80 
 81         case FrameLoadTypeRedirectWithLockedBackForwardList:
 82             history()->updateForRedirectWithLockedBackForwardList();
 83             m_client->transitionToCommittedForNewPage();
 84             break;
 85 
 86         // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
 87         // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
 88         default:
 89             ASSERT_NOT_REACHED();
 90     }
 91 
 92     m_documentLoader->writer()->setMIMEType(dl->responseMIMEType());
 93 
 94     // Tell the client we've committed this URL.
 95     ASSERT(m_frame->view());
 96 
 97     if (m_stateMachine.creatingInitialEmptyDocument())
 98         return;
 99 
100     if (!m_stateMachine.committedFirstRealDocumentLoad())
101         m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
102 
103     if (!m_client->hasHTMLView())
104         receivedFirstData();
105 }

5,包含一個HistoryController對象,用於操做歷史記錄相關的接口,保存或者恢復Document和View相關的狀態,維護前進後退隊列,以實現前進後退功能,前進後退本質上是同Page對象關聯的,FrameLoader經過HistoryController操做 m_backForwardController對象

6,包含一個 ResourceLoadNotifier 對象, 主要用於同 ResourceLoader及FrameLoaderClient打交道,能夠理解爲 ResourceLoader有事件變化或者發生的時候,通知 FrameLoader 的一個手段

7,包含一個SubframeLoader對象,當FrameLoader下載的Document有子幀須要請求的時候(好比 HTMLDocument中解析到 iframe),用於處理子幀請求

8,將FrameLoader的狀態封裝到 FrameLoaderStateMachine 中,這個狀態同 FrameState不一樣。 FrameState傾向於判斷Frame涉及的Document的下載狀態,是出於發起狀態(Provisional),仍是出於已經收到響應但不全(CommitedPage),仍是響應收全狀態,傾向於同HTTP相關。而 FrameLoaderStateMachine 傾向於同DocumentLoader相關,用來描述FrameLoader處理DocumentLoader的節點,是處於已經建立,仍是顯示狀態。

9,PolicyChecker主要用來對FrameLoader進行一些校驗。包括三種校驗: NewWindow,Navigation和Content。

    NewWindow對應於瀏覽器須要打開一個tab頁或新窗口的時候

    Navigation 對應於一個頁面請求發起的時候

    Content校驗對應於收到數據以後(判斷 Mime type等)

    PolicyChecker經過提供對應的接口,由FrameLoaderClient來對這些請求進行校驗,以肯定是否容許繼續,護着須要其餘的動做

 

3.   主要接口

1 void FrameLoader::init()

功能:

      FrameLoader的初始化

實現: 

 1 void FrameLoader::init()
 2 {
 3     // Propagate sandbox attributes to this Frameloader and its descendants.
 4     // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
 5     updateSandboxFlags();
 6 
 7     // this somewhat odd set of steps is needed to give the frame an initial empty document
 8     m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
 9     setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
10     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
11     setState(FrameStateProvisional);
12     m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
13     m_provisionalDocumentLoader->finishedLoading();
14     m_documentLoader->writer()->begin(KURL(), false);
15     m_documentLoader->writer()->end();
16     m_frame->document()->cancelParsing();
17     m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
18     m_didCallImplicitClose = true;
19 
20     m_networkingContext = m_client->createNetworkingContext();
21 }

函數調用系列:

1 QWebFrame::QWebFrame(QwebPage* parent,QWebFrameData *frameData)
2 QWebFramePrivate::init(QWebFrame* qwebframe,QWebFrameData* frameData)
3 Frame::init()
4 FrameLoader::init()

源碼追蹤:

1,QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)

 1 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
 2     : QObject(parent)
 3     , d(new QWebFramePrivate)
 4 {
 5     d->page = parent;
 6     d->init(this, frameData);
 7 
 8     if (!frameData->url.isEmpty()) {
 9         WebCore::ResourceRequest request(frameData->url, frameData->referrer);
10         d->frame->loader()->load(request, frameData->name, false);
11     }
12 #if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
13     connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
14     d->m_orientation.start();
15 #endif
16 }

2,QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)

 1 void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)
 2 {
 3     q = qframe;
 4 
 5     allowsScrolling = frameData->allowsScrolling;
 6     marginWidth = frameData->marginWidth;
 7     marginHeight = frameData->marginHeight;
 8     frame = frameData->frame.get();
 9     frameLoaderClient = frameData->frameLoaderClient;
10     frameLoaderClient->setFrame(qframe, frame);
11 
12     frame->init();
13 }

3,Frame::init()

1 inline void Frame::init()
2 {
3     m_loader.init();
4 }

4, FrameLoader::init()

 

OK,源碼跟蹤到此

說明:

     主要作一些自身的初始化工做,好比初始化狀態機,Sandbox Flags,建立DocumentLoader被設置爲 PolicyDocumentLoader  和  Provisional DocumentLoader,調用 DocumentLoader  和 documentWriter等的接口進行初始化操做

 

FrameLoader::commitProvisionalLoad

功能:

    提交Provisional階段下載的數據

實現:

 1 void FrameLoader::commitProvisionalLoad()
 2 {
 3     RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0;
 4     RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
 5 
 6     LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(),
 7         m_frame->document() ? m_frame->document()->url().string().utf8().data() : "", 
 8         pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>");
 9 
10     // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
11     // We are doing this here because we know for sure that a new page is about to be loaded.
12     HistoryItem* item = history()->currentItem();
13     if (!m_frame->tree()->parent() && PageCache::canCache(m_frame->page()) && !item->isInPageCache())
14         pageCache()->add(item, m_frame->page());
15 
16     if (m_loadType != FrameLoadTypeReplace)
17         closeOldDataSources();
18 
19     if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
20         m_client->makeRepresentation(pdl.get());
21 
22     transitionToCommitted(cachedPage);
23 
24     if (pdl) {
25         // Check if the destination page is allowed to access the previous page's timing information.
26         RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
27         m_documentLoader->timing()->hasSameOriginAsPreviousDocument = securityOrigin->canRequest(m_previousUrl);
28     }
29 
30     // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
31     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
32     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
33     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
34     if (m_sentRedirectNotification)
35         clientRedirectCancelledOrFinished(false);
36     
37     if (cachedPage && cachedPage->document()) {
38         prepareForCachedPageRestore();
39         cachedPage->restore(m_frame->page());
40 
41         dispatchDidCommitLoad();
42 
43         // If we have a title let the WebView know about it. 
44         StringWithDirection title = m_documentLoader->title();
45         if (!title.isNull())
46             m_client->dispatchDidReceiveTitle(title);
47 
48         checkCompleted();
49     } else {        
50         KURL url = pdl->substituteData().responseURL();
51         if (url.isEmpty())
52             url = pdl->url();
53         if (url.isEmpty())
54             url = pdl->responseURL();
55         if (url.isEmpty())
56             url = blankURL();
57 
58         didOpenURL(url);
59     }
60 
61     LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(),
62         m_frame->document() ? m_frame->document()->url().string().utf8().data() : "");
63 
64     if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
65         history()->updateForClientRedirect();
66 
67     if (m_loadingFromCachedPage) {
68         m_frame->document()->documentDidBecomeActive();
69         
70         // Force a layout to update view size and thereby update scrollbars.
71         m_frame->view()->forceLayout();
72 
73         const ResponseVector& responses = m_documentLoader->responses();
74         size_t count = responses.size();
75         for (size_t i = 0; i < count; i++) {
76             const ResourceResponse& response = responses[i];
77             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
78             ResourceError error;
79             unsigned long identifier;
80             ResourceRequest request(response.url());
81             requestFromDelegate(request, identifier, error);
82             // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
83             // However, with today's computers and networking speeds, this won't happen in practice.
84             // Could be an issue with a giant local file.
85             notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, static_cast<int>(response.expectedContentLength()), 0, error);
86         }
87         
88         pageCache()->remove(history()->currentItem());
89 
90         m_documentLoader->setPrimaryLoadComplete(true);
91 
92         // FIXME: Why only this frame and not parent frames?
93         checkLoadCompleteForThisFrame();
94     }
95 }

函數調用系列:(兩種狀況)

 1 DocumentLoader::finishLoading
 2 DocumentLoader::commitIfReady
 3 FrameLoader::commitProvisionalLoad
 4 
 5 
 6 ResourceLoader::didReceiveData
 7 MainResourceLoader::addData
 8 DocumentLoader::receiveData
 9 DocumentLoader::commitLoad
10 DocumentLoader::commitIfReady
11 DocumentLoader::commitProvisionalLoad

源碼跟蹤:

狀況一

1,MainResourceLoader::didFinishLoading(double finishTime)

 1 void MainResourceLoader::didFinishLoading(double finishTime)
 2 {
 3     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
 4     // See <rdar://problem/6304600> for more details.
 5 #if !USE(CF)
 6     ASSERT(shouldLoadAsEmptyDocument(frameLoader()->activeDocumentLoader()->url()) || !defersLoading());
 7 #endif
 8     
 9     // The additional processing can do anything including possibly removing the last
10     // reference to this object.
11     RefPtr<MainResourceLoader> protect(this);
12 
13 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
14     RefPtr<DocumentLoader> dl = documentLoader();
15 #endif
16 
17     ASSERT(!documentLoader()->timing()->responseEnd);
18     documentLoader()->timing()->responseEnd = finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : currentTime());
19     frameLoader()->finishedLoading();
20     ResourceLoader::didFinishLoading(finishTime);
21     
22 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
23     dl->applicationCacheHost()->finishedLoadingMainResource();
24 #endif
25 }

2,FrameLoader::finishedLoading()

 1 void FrameLoader::finishedLoading()
 2 {
 3     // Retain because the stop may release the last reference to it.
 4     RefPtr<Frame> protect(m_frame);
 5 
 6     RefPtr<DocumentLoader> dl = activeDocumentLoader();
 7     dl->finishedLoading();
 8     if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
 9         return;
10     dl->setPrimaryLoadComplete(true);
11     m_client->dispatchDidLoadMainResource(dl.get());
12     checkLoadComplete();
13 }

3,DocumentLoader::finishedLoading()

1 void DocumentLoader::finishedLoading()
2 {
3     m_gotFirstByte = true;   
4     commitIfReady();
5     if (FrameLoader* loader = frameLoader()) {
6         loader->finishedLoadingDocument(this);
7         m_writer.end();
8     }
9 }

4, DocumentLoader::commitIfReady()

1 void DocumentLoader::commitIfReady()
2 {
3     if (m_gotFirstByte && !m_committed) {
4         m_committed = true;
5         frameLoader()->commitProvisionalLoad();
6     }
7 }

5, FrameLoader::commitProvisionalLoad()

 

OK!

狀況二:

1,MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)

 1 void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
 2 {
 3     ASSERT(data);
 4     ASSERT(length != 0);
 5 
 6     ASSERT(!m_response.isNull());
 7 
 8 #if USE(CFNETWORK) || PLATFORM(MAC)
 9     // Workaround for <rdar://problem/6060782>
10     if (m_response.isNull()) {
11         m_response = ResourceResponse(KURL(), "text/html", 0, String(), String());
12         if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader())
13             documentLoader->setResponse(m_response);
14     }
15 #endif
16 
17     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
18     // See <rdar://problem/6304600> for more details.
19 #if !USE(CF)
20     ASSERT(!defersLoading());
21 #endif
22  
23  #if ENABLE(OFFLINE_WEB_APPLICATIONS)
24     documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce);
25 #endif
26 
27     // The additional processing can do anything including possibly removing the last
28     // reference to this object; one example of this is 3266216.
29     RefPtr<MainResourceLoader> protect(this);
30 
31     m_timeOfLastDataReceived = currentTime();
32 
33     ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
34 }

2,ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)

 1 void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
 2 {
 3     // The following assertions are not quite valid here, since a subclass
 4     // might override didReceiveData in a way that invalidates them. This
 5     // happens with the steps listed in 3266216
 6     // ASSERT(con == connection);
 7     // ASSERT(!m_reachedTerminalState);
 8 
 9     // Protect this in this delegate method since the additional processing can do
10     // anything including possibly derefing this; one example of this is Radar 3266216.
11     RefPtr<ResourceLoader> protector(this);
12 
13     addData(data, length, allAtOnce);
14     // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
15     // However, with today's computers and networking speeds, this won't happen in practice.
16     // Could be an issue with a giant local file.
17     if (m_sendResourceLoadCallbacks && m_frame)
18         frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength));
19 }

3,MainResourceLoader::addData(const char* data, int length, bool allAtOnce)

1 void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
2 {
3     ResourceLoader::addData(data, length, allAtOnce);
4     documentLoader()->receivedData(data, length);
5 }

4,DocumentLoader::receivedData(const char* data, int length)

1 void DocumentLoader::receivedData(const char* data, int length)
2 {    
3     m_gotFirstByte = true;
4     if (doesProgressiveLoad(m_response.mimeType()))
5         commitLoad(data, length);
6 }

5,DocumentLoader::commitLoad(const char* data, int length)

 1 void DocumentLoader::commitLoad(const char* data, int length)
 2 {
 3     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
 4     // by starting a new load, so retain temporarily.
 5     RefPtr<Frame> protectFrame(m_frame);
 6     RefPtr<DocumentLoader> protectLoader(this);
 7 
 8     commitIfReady();
 9     FrameLoader* frameLoader = DocumentLoader::frameLoader();
10     if (!frameLoader)
11         return;
12 #if ENABLE(WEB_ARCHIVE)
13     if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
14         return;
15 #endif
16     frameLoader->client()->committedLoad(this, data, length);
17 }

6, DocumentLoader::commitIfReady()

1 void DocumentLoader::commitIfReady()
2 {
3     if (m_gotFirstByte && !m_committed) {
4         m_committed = true;
5         frameLoader()->commitProvisionalLoad();
6     }
7 }

7,FrameLoader::commitProvisionalLoad()

 

OK, 跟蹤over!!

說明: 這個接口主要的操做是將Provisional DocumentLoader設置成 DocumentLoader,由於已經收到數據,因此FrameState也會躍遷到FrameStateCommittedPage。還有歷史記錄,PageCache相關的操做。另外,這個接口會間接調用 FrameLoaderClientQt::transitionToCommittedForNewPage,經過Frame::createView 建立出 FrameView來。

 

Frame::finishedLoading

功能:

     frame請求網絡加載完成的時候調用此接口

實現:

 1 void FrameLoader::finishedLoading()
 2 {
 3     // Retain because the stop may release the last reference to it.
 4     RefPtr<Frame> protect(m_frame);
 5 
 6     RefPtr<DocumentLoader> dl = activeDocumentLoader();
 7     dl->finishedLoading();
 8     if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
 9         return;
10     dl->setPrimaryLoadComplete(true);
11     m_client->dispatchDidLoadMainResource(dl.get());
12     checkLoadComplete();
13 }

函數調用系列:

1 ResourceLoader::didFinishLoading
2 MainResourceLoader::didFinishLoading
3 FrameLoader::finishedLoading
4 FrameLoader::init()

說明:

    檢查是否有網絡錯誤,告訴DocumentLoader和DocumentWriter下載完成,以便進行後續操做(提交數據,解析)

    

FrameLoader::finishedParsing

功能:

     解析完成調用此接口

函數調用系列:

1 DocumentWritter::end
2 ….
3 Document::finishParsing
4 ….
5 Document::finishedParsing
6 FrameLoader::finishedParsing

源碼跟蹤:

1,DocumentLoader::finishedLoading()

1 void DocumentLoader::finishedLoading()
2 {
3     m_gotFirstByte = true;   
4     commitIfReady();
5     if (FrameLoader* loader = frameLoader()) {
6         loader->finishedLoadingDocument(this);
7         m_writer.end();
8     }
9 }

2, DocumentWriter::end()

1 void DocumentWriter::end()
2 {
3     m_frame->loader()->didEndDocument();
4     endIfNotLoadingMainResource();
5 }

3,DocumentWriter::endIfNotLoadingMainResource()

 1 void DocumentWriter::endIfNotLoadingMainResource()
 2 {
 3     if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
 4         return;
 5 
 6     // http://bugs.webkit.org/show_bug.cgi?id=10854
 7     // The frame's last ref may be removed and it can be deleted by checkCompleted(), 
 8     // so we'll add a protective refcount
 9     RefPtr<Frame> protector(m_frame);
10 
11     // make sure nothing's left in there
12     addData(0, 0, true);
13     m_frame->document()->finishParsing();
14 }

4,Document::finishedParsing()

 1 void Document::finishedParsing()
 2 {
 3     ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
 4     ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
 5     setParsing(false);
 6     if (!m_documentTiming.domContentLoadedEventStart)
 7         m_documentTiming.domContentLoadedEventStart = currentTime();
 8     dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false));
 9     if (!m_documentTiming.domContentLoadedEventEnd)
10         m_documentTiming.domContentLoadedEventEnd = currentTime();
11 
12     if (RefPtr<Frame> f = frame()) {
13         // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
14         // resource loads are complete. HTMLObjectElements can start loading their resources from
15         // post attach callbacks triggered by recalcStyle().  This means if we parse out an <object>
16         // tag and then reach the end of the document without updating styles, we might not have yet
17         // started the resource load and might fire the window load event too early.  To avoid this
18         // we force the styles to be up to date before calling FrameLoader::finishedParsing().
19         // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
20         updateStyleIfNeeded();
21 
22         f->loader()->finishedParsing();
23 
24         InspectorInstrumentation::domContentLoadedEventFired(f.get(), url());
25     }
26 }

5,FrameLoader::finishedParsing()

 

FrameLoader::load(const ResourceRequest& request,bool lockHistory)

功能:

     加載一個Frame請求,Frame請求相關的數據,封裝成ResourceRequest傳入

函數調用系列:

     通常由應用觸發

源碼跟蹤:

     見前文

說明:

     這個接口調用FrameLoaderClientQt::createDocumentLoader建立出DocumentLoader,並以此DocumentLoader爲Policy  DocumentLoder,進入Policy check流程

相關文章
相關標籤/搜索