WebKit内核分析之FrameLoader
参考地址:http://blog.csdn.net/dlmu2001/article/details/6168545
FrameLoader类负责一个Frame的加载,在Frame的流程中起到非常重要的作用,同很多组件都有交互,本文将分析FrameLoader类的代码
1. 概述
顾名思义,FrameLoader是一个Frame的loader,它的作用就是为客户端提供一个下载一个Frame的一系列的接口。这里的客户指的是类的客户,比如Frame类,间接客户是上层应用,比如 qwebframe
从它的定义看,最容易想到的是一个load接口,用来将一个frame load下来。任何一个页面都需要一个mainframe,因此一个页面的下载一般就是从load 一个 mainframe开始
在 load frame的过程中,通过FrameLoaderClient接口将load过程的不同阶段告知客户
FrameLoader通过 setDocumentLoader相当于把load的工作委托给了 DocumentLoader类
FrameLoader同 DocumentLoader是has-a的关系。一般在load的时候创建 DocumentLoader。Frame调用DocumentLoader的startLoadingMainResource开始 load frame
类数据代码:
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指针
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的职责范围内。
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流程