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 ...
随机推荐
- 为什么不能把委托(delegate)放在一个接口(interface)当中?
stackoverflow上有人问,为什么不能把委托放在一个接口当中? 投票最多的第一个答案第一句话说,“A Delegate is just another type, so you don't g ...
- 玩转cocos2d-x lua-binding, 实现c++与lua混合编程
引言 城市精灵GO(http://csjl.teamtop3.com/)是一款基于cocos2d-x开发的LBS社交游戏, 通过真实地图的探索, 发现和抓捕隐匿于身边的野生精灵, 利用游戏中丰富的玩法 ...
- 第八章xml学习
1.ASP.NET和JSP的关系 ASP.NET 和JSP都是用来开发动态网站的技术,只不过ASP.NET是通过c#语言来操作的, 而JSP是通过Java语言来操作的. 2.为什么学习XML? 01. ...
- pro02总结:spring mvc + jdbc
在pro01的基础上,加入springMVC. applicationContext.xml: <?xml version="1.0" encoding="UTF- ...
- mysql join 查询图
mysql join 查询,特别是对查两个表之间的差集,可以用table字段=null来做. 注意千万不是join on XX!=XX ,这样出来的结果是错误的.
- atitit.二维码生成总结java zxing
atitit.二维码生成总结java zxing #-----zxing类库.. but zxing3.0 的类库core-3.0.jar 需要jdk7 只好zing2.2.jar ..jdk6走o ...
- 使用iMovie和Keynote制作App Preview
App Preview是什么 App Preview就是一段15-30秒的短视频,用来展示你的应用的特性.用户界面.交互方式等内容.在App Store你的应用的详细信息页面里,放在原来的截图之前.体 ...
- 关于EditText的OnClickListener失效的解决办法
最近开发,遇到一个问题,就是如果EditText只作为显示,不需要编辑文本,但需要点击该布局可以执行其他事件,就会冲突,EditText依然处于文本编辑状态: 如: 如:有5个EditText,最后一 ...
- linux中touch命令参数修改文件的时间戳(转)
linux中touch命令参数不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件,以下是linux中touch命令参数的使用方法: touch [-acm][-r ...
- C#中判断一个集合是另外一个集合的子集
有这样的两个集合: string[] bigArr = new string[] { "a", "b", "c" };string[] sm ...