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
类数据代码:
- class FrameLoader {
- WTF_MAKE_NONCOPYABLE(FrameLoader);
- private:
- Frame* m_frame;
- FrameLoaderClient* m_client;
- mutable PolicyChecker m_policyChecker;
- mutable HistoryController m_history;
- mutable ResourceLoadNotifier m_notifer;
- mutable SubframeLoader m_subframeLoader;
- mutable FrameLoaderStateMachine m_stateMachine;
- FrameState m_state;
- FrameLoadType m_loadType;
- // Document loaders for the three phases of frame loading. Note that while
- // a new request is being loaded, the old document loader may still be referenced.
- // E.g. while a new request is in the "policy" state, the old document loader may
- // be consulted in particular as it makes sense to imply certain settings on the new loader.
- RefPtr<DocumentLoader> m_documentLoader;
- RefPtr<DocumentLoader> m_provisionalDocumentLoader;
- RefPtr<DocumentLoader> m_policyDocumentLoader;
- bool m_delegateIsHandlingProvisionalLoadError;
- bool m_quickRedirectComing;
- bool m_sentRedirectNotification;
- bool m_inStopAllLoaders;
- String m_outgoingReferrer;
- bool m_isExecutingJavaScriptFormAction;
- bool m_didCallImplicitClose;
- bool m_wasUnloadEventEmitted;
- bool m_pageDismissalEventBeingDispatched;
- bool m_isComplete;
- bool m_isLoadingMainResource;
- RefPtr<SerializedScriptValue> m_pendingStateObject;
- KURL m_workingURL;
- OwnPtr<IconLoader> m_iconLoader;
- bool m_mayLoadIconLater;
- bool m_needsClear;
- KURL m_submittedFormURL;
- Timer<FrameLoader> m_checkTimer;
- bool m_shouldCallCheckCompleted;
- bool m_shouldCallCheckLoadComplete;
- Frame* m_opener;
- HashSet<Frame*> m_openedFrames;
- bool m_didPerformFirstNavigation;
- bool m_loadingFromCachedPage;
- bool m_suppressOpenerInNewFrame;
- SandboxFlags m_sandboxFlags;
- SandboxFlags m_forcedSandboxFlags;
- RefPtr<FrameNetworkingContext> m_networkingContext;
- KURL m_previousUrl;
- }
2. 类关系
1,Frame 和 FrameLoader 是 contain-a的关系,在 Frame的构造函数中调用 FraomeLoader的构造函数,调用时传入参数 Frame指针 和 FrameLoaderClient指针
- inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
- : m_page(page)
- , m_treeNode(this, parentFromOwnerElement(ownerElement))
- , m_loader(this, frameLoaderClient)
- , m_navigationScheduler(this)
- , m_ownerElement(ownerElement)
- , m_script(this)
- , m_editor(this)
- , m_selectionController(this)
- , m_eventHandler(this)
- , m_animationController(this)
- , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
- , m_pageZoomFactor(parentPageZoomFactor(this))
- , m_textZoomFactor(parentTextZoomFactor(this))
- , m_pageScaleFactor()
- #if ENABLE(ORIENTATION_EVENTS)
- , m_orientation()
- #endif
- , m_inViewSourceMode(false)
- , m_isDisconnected(false)
- , m_excludeFromTextSearch(false)
- #if ENABLE(MEDIA_STREAM)
- , m_mediaStreamFrameController(RuntimeEnabledFeatures::mediaStreamEnabled() ? adoptPtr(new MediaStreamFrameController(this)) : PassOwnPtr<MediaStreamFrameController>())
- #endif
- {
- ....
- }
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对象,分别对应不同的阶段。
- RefPtr<DocumentLoader> m_documentLoader;
- RefPtr<DocumentLoader> m_provisionalDocumentLoader;
- RefPtr<DocumentLoader> m_policyDocumentLoader;
m_policyDocumentLoader 对应于 收到用户 load 调用,进行 policy check 阶段
m_provisionalDocumentLoader 对应于 policy check 通过之后,Frame数据还没有到来之前,它会负责 startLoadingMainResource的调用
m_documentLoader 则是 Frame第一个数据到来以后使用的 DocumentLoader,这个时候,前一个主 Frame 的 DocumentLoader已经不能再用(user agent开始白屏,刷掉前一个页面的显示)
- inline void Frame::init()
- {
- m_loader.init();
- }
- void FrameLoader::init()
- {
- // Propagate sandbox attributes to this Frameloader and its descendants.
- // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
- updateSandboxFlags();
- // this somewhat odd set of steps is needed to give the frame an initial empty document
- m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
- setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
- setProvisionalDocumentLoader(m_policyDocumentLoader.get());
- setState(FrameStateProvisional);
- m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", , String(), String()));
- m_provisionalDocumentLoader->finishedLoading();
- m_documentLoader->writer()->begin(KURL(), false);
- m_documentLoader->writer()->end();
- m_frame->document()->cancelParsing();
- m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
- m_didCallImplicitClose = true;
- m_networkingContext = m_client->createNetworkingContext();
- }
从上面代码可以看出,在Frame初始化的时候,仅仅调用FrameLoader的初始化函数
然后FrameLoader初始化的时候,首先把状态机的状态标识成 FrameLoaderStateMachine::CreatingInitialEmptyDocument ,然后调用客户端实现创建一个DocumentLoader,然后设置为PolicyDocumentLoader,并且设置ProvisionalDocumentLoader和PolicyDocumentLoader为同一个loader,并且设置FrameState状态为 Provisional(初始化为commitPage状态)
然后把状态机状态更新为 FrameLoaderStateMachine::DisplayingInitialEmptyDocument 完成初始化
后面还有一次load的变迁:
- void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
- {
- ASSERT(m_client->hasWebView());
- ASSERT(m_state == FrameStateProvisional);
- if (m_state != FrameStateProvisional)
- return;
- if (m_frame->view())
- m_frame->view()->scrollAnimator()->cancelAnimations();
- m_client->setCopiesOnScroll();
- history()->updateForCommit();
- // The call to closeURL() invokes the unload event handler, which can execute arbitrary
- // JavaScript. If the script initiates a new load, we need to abandon the current load,
- // or the two will stomp each other.
- DocumentLoader* pdl = m_provisionalDocumentLoader.get();
- if (m_documentLoader)
- closeURL();
- if (pdl != m_provisionalDocumentLoader)
- return;
- // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
- if (m_documentLoader)
- m_documentLoader->stopLoadingSubresources();
- if (m_documentLoader)
- m_documentLoader->stopLoadingPlugIns();
- setDocumentLoader(m_provisionalDocumentLoader.get());
- setProvisionalDocumentLoader();
- setState(FrameStateCommittedPage);
- // Handle adding the URL to the back/forward list.
- DocumentLoader* dl = m_documentLoader.get();
- switch (m_loadType) {
- case FrameLoadTypeForward:
- case FrameLoadTypeBack:
- case FrameLoadTypeIndexedBackForward:
- if (m_frame->page()) {
- // If the first load within a frame is a navigation within a back/forward list that was attached
- // without any of the items being loaded then we need to update the history in a similar manner as
- // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
- if (!m_stateMachine.committedFirstRealDocumentLoad())
- history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
- history()->updateForBackForwardNavigation();
- // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
- if (history()->currentItem() && !cachedPage)
- m_pendingStateObject = history()->currentItem()->stateObject();
- // Create a document view for this document, or used the cached view.
- if (cachedPage) {
- DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
- ASSERT(cachedDocumentLoader);
- cachedDocumentLoader->setFrame(m_frame);
- m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
- } else
- m_client->transitionToCommittedForNewPage();
- }
- break;
- case FrameLoadTypeReload:
- case FrameLoadTypeReloadFromOrigin:
- case FrameLoadTypeSame:
- case FrameLoadTypeReplace:
- history()->updateForReload();
- m_client->transitionToCommittedForNewPage();
- break;
- case FrameLoadTypeStandard:
- history()->updateForStandardLoad();
- if (m_frame->view())
- m_frame->view()->setScrollbarsSuppressed(true);
- m_client->transitionToCommittedForNewPage();
- break;
- case FrameLoadTypeRedirectWithLockedBackForwardList:
- history()->updateForRedirectWithLockedBackForwardList();
- m_client->transitionToCommittedForNewPage();
- break;
- // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
- // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
- default:
- ASSERT_NOT_REACHED();
- }
- m_documentLoader->writer()->setMIMEType(dl->responseMIMEType());
- // Tell the client we've committed this URL.
- ASSERT(m_frame->view());
- if (m_stateMachine.creatingInitialEmptyDocument())
- return;
- if (!m_stateMachine.committedFirstRealDocumentLoad())
- m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
- if (!m_client->hasHTMLView())
- receivedFirstData();
- }
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. 主要接口
- void FrameLoader::init()
功能:
FrameLoader的初始化
实现:
- void FrameLoader::init()
- {
- // Propagate sandbox attributes to this Frameloader and its descendants.
- // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
- updateSandboxFlags();
- // this somewhat odd set of steps is needed to give the frame an initial empty document
- m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
- setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());
- setProvisionalDocumentLoader(m_policyDocumentLoader.get());
- setState(FrameStateProvisional);
- m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", , String(), String()));
- m_provisionalDocumentLoader->finishedLoading();
- m_documentLoader->writer()->begin(KURL(), false);
- m_documentLoader->writer()->end();
- m_frame->document()->cancelParsing();
- m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
- m_didCallImplicitClose = true;
- m_networkingContext = m_client->createNetworkingContext();
- }
函数调用系列:
- QWebFrame::QWebFrame(QwebPage* parent,QWebFrameData *frameData)
- QWebFramePrivate::init(QWebFrame* qwebframe,QWebFrameData* frameData)
- Frame::init()
- FrameLoader::init()
源码追踪:
1,QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
- QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
- : QObject(parent)
- , d(new QWebFramePrivate)
- {
- d->page = parent;
- d->init(this, frameData);
- if (!frameData->url.isEmpty()) {
- WebCore::ResourceRequest request(frameData->url, frameData->referrer);
- d->frame->loader()->load(request, frameData->name, false);
- }
- #if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
- connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
- d->m_orientation.start();
- #endif
- }
2,QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)
- void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)
- {
- q = qframe;
- allowsScrolling = frameData->allowsScrolling;
- marginWidth = frameData->marginWidth;
- marginHeight = frameData->marginHeight;
- frame = frameData->frame.get();
- frameLoaderClient = frameData->frameLoaderClient;
- frameLoaderClient->setFrame(qframe, frame);
- frame->init();
- }
3,Frame::init()
- inline void Frame::init()
- {
- m_loader.init();
- }
4, FrameLoader::init()
OK,源码跟踪到此
说明:
主要做一些自身的初始化工作,比如初始化状态机,Sandbox Flags,创建DocumentLoader被设置为 PolicyDocumentLoader 和 Provisional DocumentLoader,调用 DocumentLoader 和 documentWriter等的接口进行初始化操作
FrameLoader::commitProvisionalLoad
功能:
提交Provisional阶段下载的数据
实现:
- void FrameLoader::commitProvisionalLoad()
- {
- RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : ;
- RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
- LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(),
- m_frame->document() ? m_frame->document()->url().string().utf8().data() : "",
- pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>");
- // Check to see if we need to cache the page we are navigating away from into the back/forward cache.
- // We are doing this here because we know for sure that a new page is about to be loaded.
- HistoryItem* item = history()->currentItem();
- if (!m_frame->tree()->parent() && PageCache::canCache(m_frame->page()) && !item->isInPageCache())
- pageCache()->add(item, m_frame->page());
- if (m_loadType != FrameLoadTypeReplace)
- closeOldDataSources();
- if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
- m_client->makeRepresentation(pdl.get());
- transitionToCommitted(cachedPage);
- if (pdl) {
- // Check if the destination page is allowed to access the previous page's timing information.
- RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(pdl->request().url());
- m_documentLoader->timing()->hasSameOriginAsPreviousDocument = securityOrigin->canRequest(m_previousUrl);
- }
- // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
- // status has changed, if there was a redirect. The frame load delegate may have saved some state about
- // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
- // just about to commit a new page, there cannot possibly be a pending redirect at this point.
- if (m_sentRedirectNotification)
- clientRedirectCancelledOrFinished(false);
- if (cachedPage && cachedPage->document()) {
- prepareForCachedPageRestore();
- cachedPage->restore(m_frame->page());
- dispatchDidCommitLoad();
- // If we have a title let the WebView know about it.
- StringWithDirection title = m_documentLoader->title();
- if (!title.isNull())
- m_client->dispatchDidReceiveTitle(title);
- checkCompleted();
- } else {
- KURL url = pdl->substituteData().responseURL();
- if (url.isEmpty())
- url = pdl->url();
- if (url.isEmpty())
- url = pdl->responseURL();
- if (url.isEmpty())
- url = blankURL();
- didOpenURL(url);
- }
- LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(),
- m_frame->document() ? m_frame->document()->url().string().utf8().data() : "");
- if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
- history()->updateForClientRedirect();
- if (m_loadingFromCachedPage) {
- m_frame->document()->documentDidBecomeActive();
- // Force a layout to update view size and thereby update scrollbars.
- m_frame->view()->forceLayout();
- const ResponseVector& responses = m_documentLoader->responses();
- size_t count = responses.size();
- for (size_t i = ; i < count; i++) {
- const ResourceResponse& response = responses[i];
- // FIXME: If the WebKit client changes or cancels the request, this is not respected.
- ResourceError error;
- unsigned long identifier;
- ResourceRequest request(response.url());
- requestFromDelegate(request, identifier, error);
- // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
- // However, with today's computers and networking speeds, this won't happen in practice.
- // Could be an issue with a giant local file.
- notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, response, static_cast<int>(response.expectedContentLength()), , error);
- }
- pageCache()->remove(history()->currentItem());
- m_documentLoader->setPrimaryLoadComplete(true);
- // FIXME: Why only this frame and not parent frames?
- checkLoadCompleteForThisFrame();
- }
- }
函数调用系列:(两种情况)
- DocumentLoader::finishLoading
- DocumentLoader::commitIfReady
- FrameLoader::commitProvisionalLoad
- ResourceLoader::didReceiveData
- MainResourceLoader::addData
- DocumentLoader::receiveData
- DocumentLoader::commitLoad
- DocumentLoader::commitIfReady
- DocumentLoader::commitProvisionalLoad
源码跟踪:
情况一
1,MainResourceLoader::didFinishLoading(double finishTime)
- void MainResourceLoader::didFinishLoading(double finishTime)
- {
- // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
- // See <rdar://problem/6304600> for more details.
- #if !USE(CF)
- ASSERT(shouldLoadAsEmptyDocument(frameLoader()->activeDocumentLoader()->url()) || !defersLoading());
- #endif
- // The additional processing can do anything including possibly removing the last
- // reference to this object.
- RefPtr<MainResourceLoader> protect(this);
- #if ENABLE(OFFLINE_WEB_APPLICATIONS)
- RefPtr<DocumentLoader> dl = documentLoader();
- #endif
- ASSERT(!documentLoader()->timing()->responseEnd);
- documentLoader()->timing()->responseEnd = finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : currentTime());
- frameLoader()->finishedLoading();
- ResourceLoader::didFinishLoading(finishTime);
- #if ENABLE(OFFLINE_WEB_APPLICATIONS)
- dl->applicationCacheHost()->finishedLoadingMainResource();
- #endif
- }
2,FrameLoader::finishedLoading()
- void FrameLoader::finishedLoading()
- {
- // Retain because the stop may release the last reference to it.
- RefPtr<Frame> protect(m_frame);
- RefPtr<DocumentLoader> dl = activeDocumentLoader();
- dl->finishedLoading();
- if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
- return;
- dl->setPrimaryLoadComplete(true);
- m_client->dispatchDidLoadMainResource(dl.get());
- checkLoadComplete();
- }
3,DocumentLoader::finishedLoading()
- void DocumentLoader::finishedLoading()
- {
- m_gotFirstByte = true;
- commitIfReady();
- if (FrameLoader* loader = frameLoader()) {
- loader->finishedLoadingDocument(this);
- m_writer.end();
- }
- }
4, DocumentLoader::commitIfReady()
- void DocumentLoader::commitIfReady()
- {
- if (m_gotFirstByte && !m_committed) {
- m_committed = true;
- frameLoader()->commitProvisionalLoad();
- }
- }
5, FrameLoader::commitProvisionalLoad()
OK!
情况二:
1,MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
- void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
- {
- ASSERT(data);
- ASSERT(length != );
- ASSERT(!m_response.isNull());
- #if USE(CFNETWORK) || PLATFORM(MAC)
- // Workaround for <rdar://problem/6060782>
- if (m_response.isNull()) {
- m_response = ResourceResponse(KURL(), "text/html", , String(), String());
- if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader())
- documentLoader->setResponse(m_response);
- }
- #endif
- // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
- // See <rdar://problem/6304600> for more details.
- #if !USE(CF)
- ASSERT(!defersLoading());
- #endif
- #if ENABLE(OFFLINE_WEB_APPLICATIONS)
- documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce);
- #endif
- // The additional processing can do anything including possibly removing the last
- // reference to this object; one example of this is 3266216.
- RefPtr<MainResourceLoader> protect(this);
- m_timeOfLastDataReceived = currentTime();
- ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
- }
2,ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
- void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
- {
- // The following assertions are not quite valid here, since a subclass
- // might override didReceiveData in a way that invalidates them. This
- // happens with the steps listed in 3266216
- // ASSERT(con == connection);
- // ASSERT(!m_reachedTerminalState);
- // Protect this in this delegate method since the additional processing can do
- // anything including possibly derefing this; one example of this is Radar 3266216.
- RefPtr<ResourceLoader> protector(this);
- addData(data, length, allAtOnce);
- // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
- // However, with today's computers and networking speeds, this won't happen in practice.
- // Could be an issue with a giant local file.
- if (m_sendResourceLoadCallbacks && m_frame)
- frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength));
- }
3,MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
- void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
- {
- ResourceLoader::addData(data, length, allAtOnce);
- documentLoader()->receivedData(data, length);
- }
4,DocumentLoader::receivedData(const char* data, int length)
- void DocumentLoader::receivedData(const char* data, int length)
- {
- m_gotFirstByte = true;
- if (doesProgressiveLoad(m_response.mimeType()))
- commitLoad(data, length);
- }
5,DocumentLoader::commitLoad(const char* data, int length)
- void DocumentLoader::commitLoad(const char* data, int length)
- {
- // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
- // by starting a new load, so retain temporarily.
- RefPtr<Frame> protectFrame(m_frame);
- RefPtr<DocumentLoader> protectLoader(this);
- commitIfReady();
- FrameLoader* frameLoader = DocumentLoader::frameLoader();
- if (!frameLoader)
- return;
- #if ENABLE(WEB_ARCHIVE)
- if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
- return;
- #endif
- frameLoader->client()->committedLoad(this, data, length);
- }
6, DocumentLoader::commitIfReady()
- void DocumentLoader::commitIfReady()
- {
- if (m_gotFirstByte && !m_committed) {
- m_committed = true;
- frameLoader()->commitProvisionalLoad();
- }
- }
7,FrameLoader::commitProvisionalLoad()
OK, 跟踪over!!
说明: 这个接口主要的操作是将Provisional DocumentLoader设置成 DocumentLoader,因为已经收到数据,所以FrameState也会跃迁到FrameStateCommittedPage。还有历史记录,PageCache相关的操作。另外,这个接口会间接调用 FrameLoaderClientQt::transitionToCommittedForNewPage,通过Frame::createView 创建出 FrameView来。
Frame::finishedLoading
功能:
frame请求网络加载完成的时候调用此接口
实现:
- void FrameLoader::finishedLoading()
- {
- // Retain because the stop may release the last reference to it.
- RefPtr<Frame> protect(m_frame);
- RefPtr<DocumentLoader> dl = activeDocumentLoader();
- dl->finishedLoading();
- if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
- return;
- dl->setPrimaryLoadComplete(true);
- m_client->dispatchDidLoadMainResource(dl.get());
- checkLoadComplete();
- }
函数调用系列:
- ResourceLoader::didFinishLoading
- MainResourceLoader::didFinishLoading
- FrameLoader::finishedLoading
- FrameLoader::init()
说明:
检查是否有网络错误,告诉DocumentLoader和DocumentWriter下载完成,以便进行后续操作(提交数据,解析)
FrameLoader::finishedParsing
功能:
解析完成调用此接口
函数调用系列:
- DocumentWritter::end
- ….
- Document::finishParsing
- ….
- Document::finishedParsing
- FrameLoader::finishedParsing
源码跟踪:
1,DocumentLoader::finishedLoading()
- void DocumentLoader::finishedLoading()
- {
- m_gotFirstByte = true;
- commitIfReady();
- if (FrameLoader* loader = frameLoader()) {
- loader->finishedLoadingDocument(this);
- m_writer.end();
- }
- }
2, DocumentWriter::end()
- void DocumentWriter::end()
- {
- m_frame->loader()->didEndDocument();
- endIfNotLoadingMainResource();
- }
3,DocumentWriter::endIfNotLoadingMainResource()
- void DocumentWriter::endIfNotLoadingMainResource()
- {
- if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
- return;
- // http://bugs.webkit.org/show_bug.cgi?id=10854
- // The frame's last ref may be removed and it can be deleted by checkCompleted(),
- // so we'll add a protective refcount
- RefPtr<Frame> protector(m_frame);
- // make sure nothing's left in there
- addData(, , true);
- m_frame->document()->finishParsing();
- }
4,Document::finishedParsing()
- void Document::finishedParsing()
- {
- ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
- ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
- setParsing(false);
- if (!m_documentTiming.domContentLoadedEventStart)
- m_documentTiming.domContentLoadedEventStart = currentTime();
- dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false));
- if (!m_documentTiming.domContentLoadedEventEnd)
- m_documentTiming.domContentLoadedEventEnd = currentTime();
- if (RefPtr<Frame> f = frame()) {
- // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
- // resource loads are complete. HTMLObjectElements can start loading their resources from
- // post attach callbacks triggered by recalcStyle(). This means if we parse out an <object>
- // tag and then reach the end of the document without updating styles, we might not have yet
- // started the resource load and might fire the window load event too early. To avoid this
- // we force the styles to be up to date before calling FrameLoader::finishedParsing().
- // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
- updateStyleIfNeeded();
- f->loader()->finishedParsing();
- InspectorInstrumentation::domContentLoadedEventFired(f.get(), url());
- }
- }
5,FrameLoader::finishedParsing()
FrameLoader::load(const ResourceRequest& request,bool lockHistory)
功能:
加载一个Frame请求,Frame请求相关的数据,封装成ResourceRequest传入
函数调用系列:
一般由应用触发
源码跟踪:
见前文
说明:
这个接口调用FrameLoaderClientQt::createDocumentLoader创建出DocumentLoader,并以此DocumentLoader为Policy DocumentLoder,进入Policy check流程
WebKit内核分析之FrameLoader的更多相关文章
- WebKit内核分析之Page
参考地址:http://blog.csdn.net/dlmu2001/article/details/6213377 注:本系列博客是在原博主博客基础上增加了自己的理解和片段,可以看源博文获得清晰的结 ...
- webkit内核分析之 Frame
参考地址:http://blog.csdn.net/dlmu2001/article/details/6164873 1. 描述 Frame类是WebCore内核同应用之间联系的一个重要的类.它 ...
- [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析
[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...
- css3中-moz、-ms、-webkit,-o分别代表的意思,以及微信浏览器内核分析
这种方式在业界上统称:识别码.前缀 //-ms代表[ie]内核识别码 //-moz代表火狐[firefox]内核识别码 //-webkit代表谷歌[chrome]/苹果[safari]内核识别码 // ...
- linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程
1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...
- Linux内核分析作业7:Linux内核如何装载和启动一个可执行程序
1.可执行文件的格式 在 Linux 平台下主要有以下三种可执行文件格式: 1.a.out(assembler and link editor output 汇编器和链接编辑器的输出) ...
- linux内核分析作业6:分析Linux内核创建一个新进程的过程
task_struct结构: struct task_struct { volatile long state;进程状态 void *stack; 堆栈 pid_t pid; 进程标识符 u ...
- linux内核分析作业5:分析system_call中断处理过程
1.增加 Menu 内核命令行 调试系统调用. 步骤:删除menu git clone (tab) make rootfs 这就是我们将 fork 函数写入 Menu 系统内核后的效果, ...
- linux内核分析作业:以一简单C程序为例,分析汇编代码理解计算机如何工作
一.实验 使用gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与他人雷同 int g(int x) { return x + 3; } in ...
随机推荐
- JavaScript 函数惰性载入
最近看JavaScript高级程序设计,大有收获,接下来几天写一下读书笔记.之前写了一篇Ajax初步理解的随笔,里面有个函数用来创建XmlHttpRequest对象,浏览器兼容性原因,写出的代码通过大 ...
- macd综合版
参数设置 SHORE 12 LONG 26 MID 9 DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG); DEA:EMA(DIF,MID),COLOR88888 ...
- atitit.eclipse 新特性总结3.1--4.3
atitit.eclipse 新特性总结3.1--4.3 Eclipse 3.1 1 Eclipse 3.2 Java开发工具的新特性 2 1. 内容辅助(Ctrl+Space)模板 2 2. 动态地 ...
- paip.c++ 转换 java 解决方案
paip.c++ 转换 java 解决方案 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/a ...
- JAVA学习中Swing概述中的JFrame学习
package com.swing; import java.awt.Color;import java.awt.Container;import java.awt.event.WindowAdapt ...
- Singleton模式和Mono-State模式
类和实例 对于大多数的类,都可以创建多个实例.在需要和不需要时,创建和删除这些实例.该过程会伴随着内存的分配和归还. 同时,有一些类,应该仅有一个实例.该实例在程序启动/结束时被创建和删除. root ...
- thinkphp框架下404页面设置
404页面即系统在找不到请求的操作方法和找不到请求的控制器名称时的一种报错行为的优化. 第一步:在thinkphp框架中的Home/Comtroller中建一个EmptyController.clas ...
- git stash恢复
今天下午在使用Git命令进行代码管理时,因为自己一时疏忽直接把自己一天的劳动成果给弄丢了,这还了得,吓死宝宝了.真的,相信有代码丢失的朋友肯定能体会我当时的心情,不能体会我心情的那就祝你们也丢次代码, ...
- zz Windows 10安装教程:硬盘安装Win10 系统步骤(适合32位和64位)
Windows 10安装教程:硬盘安装Win10 系统步骤(适合32位和64位) Posted on 2015年01月28日 by 虾虾 22 Comments 最新的Windows 10 MSD ...
- 写给程序员和UI--Android的切图标准
最近总是有人在问我,Android怎么切图啊,怎么适配啊,不只是Android同行,还有很多新手ui设计师. 于是我就写篇文章,根据我们平时的开发经验,简单的介绍一下吧. 如果UI设计师以1920*1 ...