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

  • 相关阅读:
    vue的nuxt框架中使用vue-video-player
    多线程学习笔记-1
    Java模拟简单的KFC程序
    Hankson最大公约数最小公倍数的“逆问题”
    C语言实现三天打鱼两天晒网
    关于border-color的一些小问题
    CSS的超链接样式设计
    CSS ID选择器&通配选择器
    CSS标签选择器&类选择器
    CSS布局属性
  • 原文地址:https://www.cnblogs.com/lfsblack/p/5409531.html
Copyright © 2020-2023  润新知