參考地址:http://blog.csdn.net/dlmu2001/article/details/6168545html
FrameLoader類負責一個Frame的加載,在Frame的流程中起到很是重要的做用,同不少組件都有交互,本文將分析FrameLoader類的代碼web
顧名思義,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 }
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來對這些請求進行校驗,以肯定是否容許繼續,護着須要其餘的動做
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等的接口進行初始化操做
功能:
提交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請求網絡加載完成的時候調用此接口
實現:
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下載完成,以便進行後續操做(提交數據,解析)
功能:
解析完成調用此接口
函數調用系列:
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()
功能:
加載一個Frame請求,Frame請求相關的數據,封裝成ResourceRequest傳入
函數調用系列:
通常由應用觸發
源碼跟蹤:
見前文
說明:
這個接口調用FrameLoaderClientQt::createDocumentLoader建立出DocumentLoader,並以此DocumentLoader爲Policy DocumentLoder,進入Policy check流程