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流程

 

posted @ 2016-04-20 18:44  lfsblack  阅读(1340)  评论(0编辑  收藏  举报