1 QtWebKitd4.dll!WebCore::MainResourceLoader::loadNow(WebCore::ResourceRequest & r={...}) 行458 C++
2 QtWebKitd4.dll!WebCore::MainResourceLoader::load(const WebCore::ResourceRequest & r={...}, const WebCore::SubstituteData & substituteData={...}) 行494 + 0x12 字节 C++
3 QtWebKitd4.dll!WebCore::DocumentLoader::startLoadingMainResource(unsigned long identifier=0x00000004) 行807 + 0x32 字节 C++
4 QtWebKitd4.dll!WebCore::FrameLoader::continueLoadAfterWillSubmitForm(WebCore::PolicyAction __formal=PolicyUse) 行3274 + 0x16 字节 C++
5 QtWebKitd4.dll!WebCore::FrameLoader::continueLoadAfterNavigationPolicy(const WebCore::ResourceRequest & __formal={...}, WTF::PassRefPtr formState={...}, bool shouldContinue=true) 行3968 C++
6 QtWebKitd4.dll!WebCore::FrameLoader::callContinueLoadAfterNavigationPolicy(void * argument=0x01d424e8, const WebCore::ResourceRequest & request={...}, WTF::PassRefPtr formState={...}, bool shouldContinue=true) 行3906 C++
7 QtWebKitd4.dll!WebCore::PolicyCheck::call(bool shouldContinue=true) 行4963 + 0x3b 字节 C++
8 QtWebKitd4.dll!WebCore::FrameLoader::continueAfterNavigationPolicy(WebCore::PolicyAction policy=PolicyUse) 行3899 C++
9 QtWebKitd4.dll!WebCore::FrameLoaderClientQt::slotCallPolicyFunction(int action=0x00000000) 行194 C++
10 QtWebKitd4.dll!WebCore::FrameLoaderClientQt::dispatchDecidePolicyForNavigationAction(void (WebCore::PolicyAction)* function=0x10018f0c, const WebCore::NavigationAction & action={...}, const WebCore::ResourceRequest & request={...}, WTF::PassRefPtr __formal={...}) 行938 C++
11 QtWebKitd4.dll!WebCore::FrameLoader::checkNavigationPolicy(const WebCore::ResourceRequest & request={...}, WebCore::DocumentLoader * loader=0x00f63ff8, WTF::PassRefPtr formState={...}, void (void *, const WebCore::ResourceRequest &, WTF::PassRefPtr, bool)* function=0x1004e661, void * argument=0x01d424e8) 行3868 C++
12 QtWebKitd4.dll!WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader * loader=0x00f63ff8, WebCore::FrameLoadType type=FrameLoadTypeRedirectWithLockedHistory, WTF::PassRefPtr prpFormState={...}) 行2291 C++
13 QtWebKitd4.dll!WebCore::FrameLoader::loadWithNavigationAction(const WebCore::ResourceRequest & request={...}, const WebCore::NavigationAction & action={...}, WebCore::FrameLoadType type=FrameLoadTypeRedirectWithLockedHistory, WTF::PassRefPtr formState={...}) 行2226 C++
14 QtWebKitd4.dll!WebCore::FrameLoader::loadURL(const WebCore::KURL & newURL={...}, const WebCore::String & referrer={...}, const WebCore::String & frameName={...}, WebCore::FrameLoadType newLoadType=FrameLoadTypeRedirectWithLockedHistory, WebCore::Event * event=0x00000000, WTF::PassRefPtr prpFormState={...}) 行2174 C++
15 QtWebKitd4.dll!WebCore::FrameLoaderClientQt::createFrame(const WebCore::KURL & url={...}, const WebCore::String & name={...}, WebCore::HTMLFrameOwnerElement * ownerElement=0x00f681a0, const WebCore::String & referrer={...}, bool allowsScrolling=false, int marginWidth=0xffffffff, int marginHeight=0xffffffff) 行981 + 0x70 字节 C++
16 QtWebKitd4.dll!WebCore::FrameLoader::loadSubframe(WebCore::HTMLFrameOwnerElement * ownerElement=0x00f681a0, const WebCore::KURL & url={...}, const WebCore::String & name={...}, const WebCore::String & referrer={...}) 行472 + 0x74 字节 C++
17 QtWebKitd4.dll!WebCore::FrameLoader::requestFrame(WebCore::HTMLFrameOwnerElement * ownerElement=0x00f681a0, const WebCore::String & urlString={...}, const WebCore::AtomicString & frameName={...}) 行442 + 0x29 字节 C++
18 QtWebKitd4.dll!WebCore::HTMLFrameElementBase::openURL() 行105 C++
19 QtWebKitd4.dll!WebCore::HTMLFrameElementBase::setNameAndOpenURL() 行161 C++
20 QtWebKitd4.dll!WebCore::HTMLFrameElementBase::setNameAndOpenURLCallback(WebCore::Node * n=0x00f681a0) 行166 C++
21 QtWebKitd4.dll!WebCore::ContainerNode::dispatchPostAttachCallbacks() 行572 + 0x7 字节 C++
22 QtWebKitd4.dll!WebCore::ContainerNode::attach() 行587 C++
23 QtWebKitd4.dll!WebCore::Element::attach() 行648 C++
24 QtWebKitd4.dll!WebCore::HTMLFrameElementBase::attach() 行194 C++
25 QtWebKitd4.dll!WebCore::HTMLFrameElement::attach() 行67 C++
26 QtWebKitd4.dll!WebCore::HTMLParser::insertNode(WebCore::Node * n=0x00f681a0, bool flat=false) 行351 C++
27 QtWebKitd4.dll!WebCore::HTMLParser::parseToken(WebCore::Token * t=0x00f65fd0) 行256 + 0x19 字节 C++
28 > QtWebKitd4.dll!WebCore::HTMLTokenizer::processToken() 行1902 + 0x20 字节 C++
29 QtWebKitd4.dll!WebCore::HTMLTokenizer::parseTag(WebCore::SegmentedString & src={...}, WebCore::HTMLTokenizer::State state={...}) 行1484 + 0x12 字节 C++
30 QtWebKitd4.dll!WebCore::HTMLTokenizer::write(const WebCore::SegmentedString & str={...}, bool appendData=true) 行1730 + 0x23 字节 C++
31 QtWebKitd4.dll!WebCore::FrameLoader::write(const char * str=0x01d3f5c0, int len=0x000001df, bool flush=false) 行1039 + 0x23 字节 C++
32 QtWebKitd4.dll!WebCore::FrameLoader::addData(const char * bytes=0x01d3f5c0, int length=0x000001df) 行1891 C++
33 QtWebKitd4.dll!WebCore::FrameLoaderClientQt::committedLoad(WebCore::DocumentLoader * loader=0x00f881e0, const char * data=0x01d3f5c0, int length=0x000001df) 行680 C++
34 QtWebKitd4.dll!WebCore::FrameLoader::committedLoad(WebCore::DocumentLoader * loader=0x00f881e0, const char * data=0x01d3f5c0, int length=0x000001df) 行3513 C++
35 QtWebKitd4.dll!WebCore::DocumentLoader::commitLoad(const char * data=0x01d3f5c0, int length=0x000001df) 行356 C++
36 QtWebKitd4.dll!WebCore::DocumentLoader::receivedData(const char * data=0x01d3f5c0, int length=0x000001df) 行368 C++
37 QtWebKitd4.dll!WebCore::FrameLoader::receivedData(const char * data=0x01d3f5c0, int length=0x000001df) 行2342 C++
38 QtWebKitd4.dll!WebCore::MainResourceLoader::addData(const char * data=0x01d3f5c0, int length=0x000001df, bool allAtOnce=false) 行147 C++
39 QtWebKitd4.dll!WebCore::ResourceLoader::didReceiveData(const char * data=0x01d3f5c0, int length=0x000001df, __int64 lengthReceived=0x00000000000001df, bool allAtOnce=false) 行267 C++
40 QtWebKitd4.dll!WebCore::MainResourceLoader::didReceiveData(const char * data=0x01d3f5c0, int length=0x000001df, __int64 lengthReceived=0x00000000000001df, bool allAtOnce=false) 行342 C++
41 QtWebKitd4.dll!WebCore::ResourceLoader::didReceiveData(WebCore::ResourceHandle * __formal=0x00fb9aa0, const char * data=0x01d3f5c0, int length=0x000001df, int lengthReceived=0x000001df) 行418 C++
42 QtWebKitd4.dll!WebCore::QNetworkReplyHandler::forwardData() 行341 C++
43 QtWebKitd4.dll!WebCore::QNetworkReplyHandler::qt_metacall(QMetaObject::Call _c=InvokeMetaMethod, int _id=0x00000002, void * * _a=0x00fba378) 行74 C++
44 QtCored4.dll!QMetaCallEvent::placeMetaCall(QObject * object=0x00f810d0) 行478 C++
45 QtCored4.dll!QObject::event(QEvent * e=0x01d3ee18) 行1102 + 0x14 字节 C++
46 QtGuid4.dll!QApplicationPrivate::notify_helper(QObject * receiver=0x00f810d0, QEvent * e=0x01d3ee18) 行4065 + 0x11 字节 C++
47 QtGuid4.dll!QApplication::notify(QObject * receiver=0x00f810d0, QEvent * e=0x01d3ee18) 行3605 + 0x10 字节 C++
48 QtCored4.dll!QCoreApplication::notifyInternal(QObject * receiver=0x00f810d0, QEvent * event=0x01d3ee18) 行610 + 0x15 字节 C++
49 QtCored4.dll!QCoreApplication::sendEvent(QObject * receiver=0x00f810d0, QEvent * event=0x01d3ee18) 行213 + 0x39 字节 C++
50 QtCored4.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver=0x00000000, int event_type=0x00000000, QThreadData * data=0x00e78f60) 行1247 + 0xd 字节 C++
51 QtCored4.dll!QEventDispatcherWin32::processEvents(QFlags flags={...}) 行679 + 0x10 字节 C++
52 QtGuid4.dll!QGuiEventDispatcherWin32::processEvents(QFlags flags={...}) 行1182 + 0x15 字节 C++
53 QtCored4.dll!QEventLoop::processEvents(QFlags flags={...}) 行150 C++
54 QtCored4.dll!QEventLoop::exec(QFlags flags={...}) 行201 + 0x2d 字节 C++
55 QtCored4.dll!QCoreApplication::exec() 行888 + 0x15 字节 C++
56 QtGuid4.dll!QApplication::exec() 行3526 C++
57 previewer.exe!main(int argc=0x00000001, char * * argv=0x00e78e20) 行51 + 0x6 字节 C++
58 previewer.exe!WinMain(HINSTANCE__ * instance=0x00400000, HINSTANCE__ * prevInstance=0x00000000, char * __formal=0x001520d9, int cmdShow=0x00000001) 行137 + 0x12 字节 C++
59 previewer.exe!__tmainCRTStartup() 行574 + 0x35 字节 C
60 previewer.exe!WinMainCRTStartup() 行399 C
61 kernel32.dll!7c82f23b()
[下面的框架可能不正确和/或缺失,没有为 kernel32.dll 加载符号]
分三个阶段对QWebView进行分析:初始化(获取数据)、HTML解析、页面显示。从QT自带的文档中可以知道
1 QWebView -> QWebPage => QWebFrame(一个QWebPage含多个QWebFrame)
在界面中选择了Open URL,输入URL之后,调用的是:void MainWindow::openUrl()
1 void MainWindow::openUrl()
2 {
3 bool ok;
4 QString url = QInputDialog::getText(this, tr("Enter a URL"),
5 tr("URL:"), QLineEdit::Normal, "http://", &ok);
6
7 if (ok && !url.isEmpty()) {
8 centralWidget->webView->setUrl(url);
9 }
10 }
调用的是QWebView::setUrl()
1 void QWebView::setUrl(const QUrl &url)
2 {
3 page()->mainFrame()->setUrl(url);
4 }
其中page()是获取QWebPage指针,QWebPage::mainFrame()获取的是QWebFrame指针
所以调用的是:QWebFrame::setUrl()
1 void QWebFrame::setUrl(const QUrl &url)
2 {
3 d->frame->loader()->begin(ensureAbsoluteUrl(url));
4 d->frame->loader()->end();
5 load(ensureAbsoluteUrl(url));
6 }
ensureAbsoluteUrl()函数作用是,确保URL是绝对URL(完整URL)。所谓相对URL是指没有输入http://或者https://等前缀的web地址。先看第一句的调用。其中隐含了从QUrl到KURL的变换。
1 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
2 {
3 // We need to take a reference to the security origin because |clear|
4 // might destroy the document that owns it.
5 RefPtr forcedSecurityOrigin = origin;
6
7 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
8 clear(resetScripting, resetScripting); // 清除上一次的数据,为本次装载准备
9 if (resetScripting)
10 m_frame->script()->updatePlatformScriptObjects(); // 在Windows平台下,这是空函数
11 if (dispatch)
12 dispatchWindowObjectAvailable();
13
14 m_needsClear = true;
15 m_isComplete = false;
16 m_didCallImplicitClose = false;
17 m_isLoadingMainResource = true;
18 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
19
20 KURL ref(url);
21 ref.setUser(String());
22 ref.setPass(String());
23 ref.setRef(String());
24 m_outgoingReferrer = ref.string();
25 m_URL = url;
26
27 RefPtr document;
28
29 if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
30 document = PluginDocument::create(m_frame);
31 else
32 document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode()); // 创建DOM文件,m_responseMIMEType不同实体不同。
33
34 // 如果是"text/html"创建HTMLDocument实体;"application/xhtml+xml"创建Document实体
35
36 // 如果是"application/x-ftp-directory"则是FTPDirectoryDocument实体
37
38 // text/vnd.wap.wml 对应 WMLDocument 实体(无线)
39
40 // "application/pdf" /"text/plain" 对应 PluginDocument实体
41
42 // 如果是MediaPlayer::supportsType(type),创建的是MediaDocument实体
43
44 // "image/svg+xml" 对应 SVGDocument实体
45 m_frame->setDocument(document);
46
47 document->setURL(m_URL);
48 if (m_decoder)
49 document->setDecoder(m_decoder.get());
50 if (forcedSecurityOrigin)
51 document->setSecurityOrigin(forcedSecurityOrigin.get());
52
53 m_frame->domWindow()->setURL(document->url());
54 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
55
56 updatePolicyBaseURL(); // 更新排布策略的基础URL
57
58 Settings* settings = document->settings();
59 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
60
61 if (m_documentLoader) {
62 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
63 if (!dnsPrefetchControl.isEmpty())
64 document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
65 }
66
67 #if FRAME_LOADS_USER_STYLESHEET
68 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
69 if (!userStyleSheet.isEmpty())
70 m_frame->setUserStyleSheetLocation(userStyleSheet);
71 #endif
72
73 restoreDocumentState();
74
75 document->implicitOpen();
76
77 if (m_frame->view())
78 m_frame->view()->setContentsSize(IntSize());
79
80 #if USE(LOW_BANDWIDTH_DISPLAY)
81 // Low bandwidth display is a first pass display without external resources
82 // used to give an instant visual feedback. We currently only enable it for
83 // HTML documents in the top frame.
84 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
85 m_pendingSourceInLowBandwidthDisplay = String();
86 m_finishedParsingDuringLowBandwidthDisplay = false;
87 m_needToSwitchOutLowBandwidthDisplay = false;
88 document->setLowBandwidthDisplay(true);
89 }
90 #endif
91 }
看其中document->implicitOpen()的代码:
1 void Document::implicitOpen()
2 {
3 cancelParsing();
4
5 clear();
6 m_tokenizer = createTokenizer();
7 setParsing(true);
8 }
9
10 Tokenizer *HTMLDocument::createTokenizer()
11 {
12 bool reportErrors = false;
13 if (frame())
14 if (Page* page = frame()->page())
15 reportErrors = page->inspectorController()->windowVisible();
16
17 return new HTMLTokenizer(this, reportErrors);
18 }
新创建的HTMLTokenizer对象,就是HTML的解析器。
回到QWebFrame::setUrl()的第二句:d->frame->loader()->end();
只是把上次未完的解析停止:
1 void FrameLoader::endIfNotLoadingMainResource()
2 {
3 if (m_isLoadingMainResource || !m_frame->page())
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 protector(m_frame);
10
11 // make sure nothing's left in there
12 if (m_frame->document()) {
13 write(0, 0, true);
14 m_frame->document()->finishParsing();
15 } else
16 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
17 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
18 // become true. An example is when a subframe is a pure text doc, and that subframe is the
19 // last one to complete.
20 checkCompleted();
21 }
再来看QWebFrame::setUrl()的第三句:load(ensureAbsoluteUrl(url));
1 void QWebFrame::load(const QUrl &url)
2 {
3 load(QNetworkRequest(ensureAbsoluteUrl(url)));
4 }
新建一个QNetworkRequest对象,然后调用
1 void load(const QNetworkRequest &request,
2 QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
3 const QByteArray &body = QByteArray());
看其代码:
1 void QWebFrame::load(const QNetworkRequest &req, 2 QNetworkAccessManager::Operation operation, 3 const QByteArray &body) 4 { 5 if (d->parentFrame()) 6 d->page->d->insideOpenCall = true; 7 8 QUrl url = ensureAbsoluteUrl(req.url()); 9 10 WebCore::ResourceRequest request(url); 11 12 switch (operation) { 13 case QNetworkAccessManager::HeadOperation: 14 request.setHTTPMethod("HEAD"); 15 break; 16 case QNetworkAccessManager::GetOperation: 17 request.setHTTPMethod("GET"); 18 break; 19 case QNetworkAccessManager::PutOperation: 20 request.setHTTPMethod("PUT"); 21 break; 22 case QNetworkAccessManager::PostOperation: 23 request.setHTTPMethod("POST"); 24 break; 25 case QNetworkAccessManager::UnknownOperation: 26 // eh? 27 break; 28 } 29 30 QListhttpHeaders = req.rawHeaderList(); 31 for (int i = 0; i < httpHeaders.size(); ++i) { 32 const QByteArray &headerName = httpHeaders.at(i); 33 request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName))); 34 } 35 36 if (!body.isEmpty()) 37 request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size())); 38 39 d->frame->loader()->load(request); 40 41 if (d->parentFrame()) 42 d->page->d->insideOpenCall = false; 43 }
看关键的FrameLoader::load()
1 void FrameLoader::load(const ResourceRequest& request)
2 {
3 load(request, SubstituteData());
4 }
5
6 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
7 {
8 if (m_inStopAllLoaders)
9 return;
10
11 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
12 m_loadType = FrameLoadTypeStandard;
13 load(m_client->createDocumentLoader(request, substituteData).get());
14 }
上面m_client对应的是FrameLoaderClientQt实体,m_client->createDocumentLoader()创建的是DocumentLoader对象。进一步看FrameLoader::load(DocumentLoader *)的代码:
1 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2 {
3 ResourceRequest& r = newDocumentLoader->request();
4 addExtraFieldsToMainResourceRequest(r);
5 FrameLoadType type;
6
7 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
8 r.setCachePolicy(ReloadIgnoringCacheData);
9 type = FrameLoadTypeSame;
10 } else
11 type = FrameLoadTypeStandard;
12
13 if (m_documentLoader)
14 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
15
16 // When we loading alternate content for an unreachable URL that we're
17 // visiting in the history list, we treat it as a reload so the history list
18 // is appropriately maintained.
19 //
20 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
21 // shouldn't a more explicit type of reload be defined, that means roughly
22 // "load without affecting history" ?
23 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
24 ASSERT(type == FrameLoadTypeStandard);
25 type = FrameLoadTypeReload;
26 }
27
28 loadWithDocumentLoader(newDocumentLoader, type, 0);
29 }
看FrameLoader::loadWithDocumentLoader()的代码:
1 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr prpFormState)
2 {
3 ASSERT(m_client->hasWebView());
4
5 // Unfortunately the view must be non-nil, this is ultimately due
6 // to parser requiring a FrameView. We should fix this dependency.
7
8 ASSERT(m_frame->view());
9
10 m_policyLoadType = type;
11 RefPtr formState = prpFormState;
12 bool isFormSubmission = formState;
13
14 const KURL& newURL = loader->request().url();
15
16 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) {
17 RefPtr oldDocumentLoader = m_documentLoader;
18 NavigationAction action(newURL, m_policyLoadType, isFormSubmission);
19
20 oldDocumentLoader->setTriggeringAction(action);
21 stopPolicyCheck();
22 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState,
23 callContinueFragmentScrollAfterNavigationPolicy, this);
24 } else {
25 if (Frame* parent = m_frame->tree()->parent())
26 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
27
28 stopPolicyCheck();
29 setPolicyDocumentLoader(loader);
30
31 checkNavigationPolicy(loader->request(), loader, formState,
32 callContinueLoadAfterNavigationPolicy, this);
33 }
34 }
上面调用checkNavigationPolicy()是关键,看其实现:
1 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
2 PassRefPtr formState, NavigationPolicyDecisionFunction function, void* argument)
3 {
4 NavigationAction action = loader->triggeringAction();
5 if (action.isEmpty()) {
6 action = NavigationAction(request.url(), NavigationTypeOther);
7 loader->setTriggeringAction(action);
8 }
9
10 // Don't ask more than once for the same request or if we are loading an empty URL.
11 // This avoids confusion on the part of the client.
12 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
13 function(argument, request, 0, true);
14 loader->setLastCheckedRequest(request);
15 return;
16 }
17
18 // We are always willing to show alternate content for unreachable URLs;
19 // treat it like a reload so it maintains the right state for b/f list.
20 if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
21 if (isBackForwardLoadType(m_policyLoadType))
22 m_policyLoadType = FrameLoadTypeReload;
23 function(argument, request, 0, true);
24 return;
25 }
26
27 loader->setLastCheckedRequest(request);
28
29 m_policyCheck.set(request, formState.get(), function, argument);
30
31 m_delegateIsDecidingNavigationPolicy = true;
32 m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
33 action, request, formState);
34 m_delegateIsDecidingNavigationPolicy = false;
35 }
其中m_client是FrameLoaderClientQt实体指针
1 void FrameLoaderClientQt::dispatchDecidePolicyForNavigationAction(FramePolicyFunction function, const WebCore::NavigationAction& action, const WebCore::ResourceRequest& request, PassRefPtr<:formstate>) 2 { 3 Q_ASSERT(!m_policyFunction); 4 Q_ASSERT(m_webFrame); 5 m_policyFunction = function; 6 #if QT_VERSION < 0x040400 7 QWebNetworkRequest r(request); 8 #else 9 QNetworkRequest r(request.toNetworkRequest()); 10 #endif 11 QWebPage*page = m_webFrame->page(); 12 13 if (!page->d->acceptNavigationRequest(m_webFrame, r, QWebPage::NavigationType(action.type()))) { 14 if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted) 15 m_frame->loader()->resetMultipleFormSubmissionProtection(); 16 17 if (action.type() == NavigationTypeLinkClicked && r.url().hasFragment()) { 18 ResourceRequest emptyRequest; 19 m_frame->loader()->activeDocumentLoader()->setLastCheckedRequest(emptyRequest); 20 } 21 22 slotCallPolicyFunction(PolicyIgnore); 23 return; 24 } 25 slotCallPolicyFunction(PolicyUse); 26 } 27 void FrameLoaderClientQt::slotCallPolicyFunction(int action) 28 { 29 if (!m_frame || !m_policyFunction) 30 return; 31 FramePolicyFunction function = m_policyFunction; 32 m_policyFunction = 0; 33 (m_frame->loader()->*function)(WebCore::PolicyAction(action)); 34 }
用函数指针回调,FrameLoader::continueAfterNavigationPolicy(PolicyAction policy),参数为PolicyUse
1 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
2 {
3 PolicyCheck check = m_policyCheck;
4 m_policyCheck.clear();
5
6 bool shouldContinue = policy == PolicyUse;
7
8 switch (policy) {
9 case PolicyIgnore:
10 check.clearRequest();
11 break;
12 case PolicyDownload:
13 m_client->startDownload(check.request());
14 check.clearRequest();
15 break;
16 case PolicyUse: {
17 ResourceRequest request(check.request());
18
19 if (!m_client->canHandleRequest(request)) {
20 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
21 check.clearRequest();
22 shouldContinue = false;
23 }
24 break;
25 }
26 }
27
28 check.call(shouldContinue);
29 }
上面调用的是PolicyCheck::call(),参数为true
1 void PolicyCheck::call(bool shouldContinue)
2 {
3 if (m_navigationFunction)
4 m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue);
5 if (m_newWindowFunction)
6 m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, shouldContinue);
7 ASSERT(!m_contentFunction);
8 }
m_navigationFunction又是一个函数指针,指向的是FrameLoader::callContinueLoadAfterNavigationPolicy()
1 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
2 const ResourceRequest& request, PassRefPtr formState, bool shouldContinue)
3 {
4 FrameLoader* loader = static_cast(argument);
5 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
6 }
7
8 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr formState, bool shouldContinue)
9 {
10 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
11 // nil policyDataSource because loading the alternate page will have passed
12 // through this method already, nested; otherwise, policyDataSource should still be set.
13 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
14
15 bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
16
17 // Two reasons we can't continue:
18 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
19 // is the user responding Cancel to the form repost nag sheet.
20 // 2) User responded Cancel to an alert popped up by the before unload event handler.
21 // The "before unload" event handler runs only for the main frame.
22 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
23
24 if (!canContinue) {
25 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
26 // need to report that the client redirect was cancelled.
27 if (m_quickRedirectComing)
28 clientRedirectCancelledOrFinished(false);
29
30 setPolicyDocumentLoader(0);
31
32 // If the navigation request came from the back/forward menu, and we punt on it, we have the
33 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
34 // we only do this when punting a navigation for the target frame or top-level frame.
35 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))
36 if (Page* page = m_frame->page()) {
37 Frame* mainFrame = page->mainFrame();
38 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get()) {
39 page->backForwardList()->goToItem(resetItem);
40 Settings* settings = m_frame->settings();
41 page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : resetItem);
42 }
43 }
44 return;
45 }
46
47 FrameLoadType type = m_policyLoadType;
48 stopAllLoaders();
49
50 // - In certain circumstances on pages with multiple frames, stopAllLoaders()
51 // might detach the current FrameLoader, in which case we should bail on this newly defunct load.
52 if (!m_frame->page())
53 return;
54
55 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
56 m_loadType = type;
57 setState(FrameStateProvisional);
58
59 setPolicyDocumentLoader(0);
60
61 if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
62 return;
63
64 if (formState)
65 m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState);
66 else
67 continueLoadAfterWillSubmitForm();
68 }
69
70 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
71 {
72 if (!m_provisionalDocumentLoader)
73 return;
74
75 // DocumentLoader calls back to our prepareForLoadStart
76 m_provisionalDocumentLoader->prepareForLoadStart();
77
78 // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader,
79 // so we need to null check it again.
80 if (!m_provisionalDocumentLoader)
81 return;
82 // 先看活动的DocumentLoader能否装载
83 DocumentLoader* activeDocLoader = activeDocumentLoader();
84 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
85 return;
86 // 看Cache中能否装载
87 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
88
89 unsigned long identifier = 0;
90
91 if (Page* page = m_frame->page()) {
92 identifier = page->progress()->createUniqueIdentifier();
93 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
94 }
95
96 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
97 m_provisionalDocumentLoader->updateLoading();
98 }
上面的装载过程,如果是第一次并且只有m_provisionalDocumentLoader的话,只会执行最后一中装载。
1 bool DocumentLoader::startLoadingMainResource(unsigned long identifier)
2 {
3 ASSERT(!m_mainResourceLoader);
4 m_mainResourceLoader = MainResourceLoader::create(m_frame);
5 m_mainResourceLoader->setIdentifier(identifier);
6
7 // FIXME: Is there any way the extra fields could have not been added by now?
8 // If not, it would be great to remove this line of code.
9 frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
10
11 if (!m_mainResourceLoader->load(m_request, m_substituteData)) {
12 // FIXME: If this should really be caught, we should just ASSERT this doesn't happen;
13 // should it be caught by other parts of WebKit or other parts of the app?
14 LOG_ERROR("could not create WebResourceHandle for URL %s -- should be caught by policy handler level", m_request.url().string().ascii().data());
15 m_mainResourceLoader = 0;
16 return false;
17 }
18
19 return true;
20 }
创建MainResourceLoader对象,并调用load()
1 bool MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& substituteData)
2 {
3 ASSERT(!m_handle);
4
5 m_substituteData = substituteData;
6
7 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
8 // Check if this request should be loaded from the application cache
9 if (!m_substituteData.isValid() && frameLoader()->frame()->settings() && frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled()) {
10 ASSERT(!m_applicationCache);
11
12 m_applicationCache = ApplicationCacheGroup::cacheForMainRequest(r, m_documentLoader.get());
13
14 if (m_applicationCache) {
15 // Get the resource from the application cache. By definition, cacheForMainRequest() returns a cache that contains the resource.
16 ApplicationCacheResource* resource = m_applicationCache->resourceForRequest(r);
17 m_substituteData = SubstituteData(resource->data(),
18 resource->response().mimeType(),
19 resource->response().textEncodingName(), KURL());
20 }
21 }
22 #endif
23
24 ResourceRequest request(r);
25 bool defer = defersLoading();
26 if (defer) {
27 bool shouldLoadEmpty = shouldLoadAsEmptyDocument(r.url());
28 if (shouldLoadEmpty)
29 defer = false;
30 }
31 if (!defer) {
32 if (loadNow(request)) {
33 // Started as an empty document, but was redirected to something non-empty.
34 ASSERT(defersLoading());
35 defer = true;
36 }
37 }
38 if (defer)
39 m_initialRequest = request;
40
41 return true;
42 }
继续深入看MainResourceLoader::loadNow()
1 bool MainResourceLoader::loadNow(ResourceRequest& r)
2 {
3 bool shouldLoadEmptyBeforeRedirect = shouldLoadAsEmptyDocument(r.url());
4
5 ASSERT(!m_handle);
6 ASSERT(shouldLoadEmptyBeforeRedirect || !defersLoading());
7
8 // Send this synthetic delegate callback since clients expect it, and
9 // we no longer send the callback from within NSURLConnection for
10 // initial requests.
11 willSendRequest(r, ResourceResponse());
12
13 //
14 // willSendRequest() is liable to make the call to frameLoader() return NULL, so we need to check that here
15 if (!frameLoader())
16 return false;
17
18 const KURL& url = r.url();
19 bool shouldLoadEmpty = shouldLoadAsEmptyDocument(url) && !m_substituteData.isValid();
20
21 if (shouldLoadEmptyBeforeRedirect && !shouldLoadEmpty && defersLoading())
22 return true;
23
24 if (m_substituteData.isValid())
25 handleDataLoadSoon(r);
26 else if (shouldLoadEmpty || frameLoader()->representationExistsForURLScheme(url.protocol()))
27 handleEmptyLoad(url, !shouldLoadEmpty);
28 else
29 m_handle = ResourceHandle::create(r, this, m_frame.get(), false, true, true);
30
31 return false;
32 }
主要两个调用:willSendRequest()和ResourceHandle::create(),前面一个估计是发送请求前的相关设定;后一个就是请求发送了。先看前一个:
1 void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
2 {
3 // Note that there are no asserts here as there are for the other callbacks. This is due to the
4 // fact that this "callback" is sent when starting every load, and the state of callback
5 // deferrals plays less of a part in this function in preventing the bad behavior deferring
6 // callbacks is meant to prevent.
7 ASSERT(!newRequest.isNull());
8
9 // The additional processing can do anything including possibly removing the last
10 // reference to this object; one example of this is 3266216.
11 RefPtr protect(this);
12
13 // Update cookie policy base URL as URL changes, except for subframes, which use the
14 // URL of the main frame which doesn't change when we redirect.
15 if (frameLoader()->isLoadingMainFrame())
16 newRequest.setMainDocumentURL(newRequest.url());
17
18 // If we're fielding a redirect in response to a POST, force a load from origin, since
19 // this is a common site technique to return to a page viewing some data that the POST
20 // just modified.
21 // Also, POST requests always load from origin, but this does not affect subresources.
22 if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse))
23 newRequest.setCachePolicy(ReloadIgnoringCacheData);
24
25 ResourceLoader::willSendRequest(newRequest, redirectResponse);
26
27 // Don't set this on the first request. It is set when the main load was started.
28 m_documentLoader->setRequest(newRequest);
29
30 // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
31 // listener. But there's no way to do that in practice. So instead we cancel later if the
32 // listener tells us to. In practice that means the navigation policy needs to be decided
33 // synchronously for these redirect cases.
34
35 ref(); // balanced by deref in continueAfterNavigationPolicy
36 frameLoader()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this);
37 }
主要是调用ResourceLoader::willSendRequest()函数:
1 void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
2 {
3 // Protect this in this delegate method since the additional processing can do
4 // anything including possibly derefing this; one example of this is Radar 3266216.
5 RefPtr protector(this);
6
7 ASSERT(!m_reachedTerminalState);
8
9 if (m_sendResourceLoadCallbacks) {
10 if (!m_identifier) {
11 m_identifier = m_frame->page()->progress()->createUniqueIdentifier();
12 frameLoader()->assignIdentifierToInitialRequest(m_identifier, request);
13 }
14
15 frameLoader()->willSendRequest(this, request, redirectResponse);
16 }
17
18 m_request = request;
19 }
进一步调用FrameLoader::willSendRequest()
1 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
2 {
3 applyUserAgent(clientRequest);
4 dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
5 }
更多的调用:
1 void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
2 {
3 StringImpl* oldRequestURL = request.url().string().impl();
4 m_documentLoader->didTellClientAboutLoad(request.url());
5
6 m_client->dispatchWillSendRequest(loader, identifier, request, redirectResponse);
7
8 // If the URL changed, then we want to put that new URL in the "did tell client" set too.
9 if (oldRequestURL != request.url().string().impl())
10 m_documentLoader->didTellClientAboutLoad(request.url());
11
12 if (Page* page = m_frame->page())
13 page->inspectorController()->willSendRequest(loader, identifier, request, redirectResponse);
14 }
囧~~还有下一步吗??
m_client->dispatchWillSendRequest()实际调用的是FrameLoaderClientQt::dispatchWillSendRequest(),目前是一个空函数(仅在dump的时候打印信息)。
1 void InspectorController::willSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
2 {
3 if (!enabled())
4 return;
5
6 InspectorResource* resource = m_resources.get(identifier).get();
7 if (!resource)
8 return;
9
10 resource->startTime = currentTime();
11
12 if (!redirectResponse.isNull()) {
13 updateResourceRequest(resource, request);
14 updateResourceResponse(resource, redirectResponse);
15 }
16
17 if (resource != m_mainResource && windowVisible()) {
18 if (!resource->scriptObject)
19 addScriptResource(resource);
20 else
21 updateScriptResourceRequest(resource);
22
23 updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
24
25 if (!redirectResponse.isNull())
26 updateScriptResourceResponse(resource);
27 }
28 }
在这里设定了开始时间,猜测是供请求超时判断用的,请求超时的定时器在何处设定有待进一步分析。
看都是一些Resource的更新,感觉意义不大,不再进一步追踪。回到MainResourceLoader::loadNow(),看下一步ResourceHandle::create()
1 PassRefPtr ResourceHandle::create(const ResourceRequest& request, ResourceHandleClient* client,
2 Frame* frame, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle)
3 {
4 RefPtr newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff, mightDownloadFromHandle)));
5
6 if (!request.url().isValid()) {
7 newHandle->scheduleFailure(InvalidURLFailure);
8 return newHandle.release();
9 }
10 // 检查端口号(port)是否合法
11 if (!portAllowed(request)) {
12 newHandle->scheduleFailure(BlockedFailure);
13 return newHandle.release();
14 }
15
16 if (newHandle->start(frame))
17 return newHandle.release();
18
19 return 0;
20 }
看关键的ResourceHandle::start调用:
1 bool ResourceHandle::start(Frame* frame) 2 { 3 if (!frame) 4 return false; 5 6 Page *page = frame->page(); 7 // If we are no longer attached to a Page, this must be an attempted load from an 8 // onUnload handler, so let's just block it. 9 if (!page) 10 return false; 11 12 getInternal()->m_frame = static_cast(frame->loader()->client())->webFrame(); 13 #if QT_VERSION < 0x040400 14 return QWebNetworkManager::self()->add(this, getInternal()->m_frame->page()->d->networkInterface); 15 #else 16 ResourceHandleInternal *d = getInternal(); 17 d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::LoadMode(d->m_defersLoading)); 18 return true; 19 #endif 20 } *>
新创建了一个QNetworkReplyHandler对象,QNetworkReplyHandler在构造的时候会调用QNetworkReplyHandler::start()
1 void QNetworkReplyHandler::start()
2 {
3 m_shouldStart = false;
4
5 ResourceHandleInternal* d = m_resourceHandle->getInternal();
6
7 QNetworkAccessManager* manager = d->m_frame->page()->networkAccessManager();
8
9 const QUrl url = m_request.url();
10 const QString scheme = url.scheme();
11 // Post requests on files and data don't really make sense, but for
12 // fast/forms/form-post-urlencoded.html and for fast/forms/button-state-restore.html
13 // we still need to retrieve the file/data, which means we map it to a Get instead.
14 if (m_method == QNetworkAccessManager::PostOperation
15 && (!url.toLocalFile().isEmpty() || url.scheme() == QLatin1String("data")))
16 m_method = QNetworkAccessManager::GetOperation;
17
18 m_startTime = QDateTime::currentDateTime().toTime_t();
19
20 switch (m_method) {
21 case QNetworkAccessManager::GetOperation:
22 m_reply = manager->get(m_request);
23 break;
24 case QNetworkAccessManager::PostOperation: {
25 FormDataIODevice* postDevice = new FormDataIODevice(d->m_request.httpBody());
26 m_reply = manager->post(m_request, postDevice);
27 postDevice->setParent(m_reply);
28 break;
29 }
30 case QNetworkAccessManager::HeadOperation:
31 m_reply = manager->head(m_request);
32 break;
33 case QNetworkAccessManager::PutOperation: {
34 FormDataIODevice* putDevice = new FormDataIODevice(d->m_request.httpBody());
35 m_reply = manager->put(m_request, putDevice);
36 putDevice->setParent(m_reply);
37 break;
38 }
39 case QNetworkAccessManager::UnknownOperation: {
40 m_reply = 0;
41 ResourceHandleClient* client = m_resourceHandle->client();
42 if (client) {
43 ResourceError error(url.host(), 400 /*bad request*/,
44 url.toString(),
45 QCoreApplication::translate("QWebPage", "Bad HTTP request"));
46 client->didFail(m_resourceHandle, error);
47 }
48 return;
49 }
50 }
51
52 m_reply->setParent(this);
53
54 connect(m_reply, SIGNAL(finished()),
55 this, SLOT(finish()), Qt::QueuedConnection);
56
57 // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
58 // can send the response as early as possible
59 if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
60 connect(m_reply, SIGNAL(metaDataChanged()),
61 this, SLOT(sendResponseIfNeeded()), Qt::QueuedConnection);
62
63 connect(m_reply, SIGNAL(readyRead()),
64 this, SLOT(forwardData()), Qt::QueuedConnection);
65 }
看到了熟悉的QNetworkAccessManager、QNetworkReply。跟踪至此,初始化和URL请求发送基本完成。
前面分析WebView初始化的时候,在QNetworkReplyHandler::start()里有设定读取数据的处理函数:
1 connect(m_reply, SIGNAL(finished()),
2 this, SLOT(finish()), Qt::QueuedConnection);
3
4 // For http(s) we know that the headers are complete upon metaDataChanged() emission, so we
5 // can send the response as early as possible
6 if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
7 connect(m_reply, SIGNAL(metaDataChanged()),
8 this, SLOT(sendResponseIfNeeded()), Qt::QueuedConnection);
9
10 connect(m_reply, SIGNAL(readyRead()),
11 this, SLOT(forwardData()), Qt::QueuedConnection);
先看QNetworkReplyHandler::forwardData()
1 void QNetworkReplyHandler::forwardData()
2 {
3 m_shouldForwardData = (m_loadMode == LoadDeferred);
4 if (m_loadMode == LoadDeferred)
5 return;
6
7 sendResponseIfNeeded();
8
9 // don't emit the "Document has moved here" type of HTML
10 if (m_redirected)
11 return;
12
13 if (!m_resourceHandle)
14 return;
15
16 QByteArray data = m_reply->read(m_reply->bytesAvailable());
17
18 ResourceHandleClient* client = m_resourceHandle->client();
19 if (!client)
20 return;
21
22 if (!data.isEmpty())
23 client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/);
24 }
实际就是两个调用:read()和didReceiveData()。其中QNetworkReply::read()前面分析过不再重复;
ResourceHandleClient* client->didReceiveData()实际调用的是MainResourceLoader::didReceiveData()
1 void MainResourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
2 {
3 ASSERT(data);
4 ASSERT(length != 0);
5
6 // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
7 // See for more details.
8 #if !PLATFORM(CF)
9 ASSERT(!defersLoading());
10 #endif
11
12 // The additional processing can do anything including possibly removing the last
13 // reference to this object; one example of this is 3266216.
14 RefPtr protect(this);
15
16 ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce);
17 }
进一步看其调用:
1 void ResourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
2 {
3 // Protect this in this delegate method since the additional processing can do
4 // anything including possibly derefing this; one example of this is Radar 3266216.
5 RefPtr protector(this);
6
7 addData(data, length, allAtOnce);
8 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
9 // However, with today's computers and networking speeds, this won't happen in practice.
10 // Could be an issue with a giant local file.
11 if (m_sendResourceLoadCallbacks && m_frame)
12 frameLoader()->didReceiveData(this, data, length, static_cast(lengthReceived));
13 }
在ResourceLoader类中addData()是虚函数,client->didReceiveData()中client指针实际的实体为MainResourceLoader对象,所以addData()先调用 MainResourceLoader::addData()
1 void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
2 {
3 ResourceLoader::addData(data, length, allAtOnce);
4 frameLoader()->receivedData(data, length);
5 }
这里只有两个调用,前一个是将接收到的数据保存到一个buffer中,供后续语法扫描使用(猜测的),暂不深入分析。看frameLoader->receivedData()
1 void FrameLoader::receivedData(const char* data, int length)
2 {
3 activeDocumentLoader()->receivedData(data, length);
4 }
5
6 void DocumentLoader::receivedData(const char* data, int length)
7 {
8 m_gotFirstByte = true;
9 if (doesProgressiveLoad(m_response.mimeType()))
10 commitLoad(data, length);
11 }
其中doesProgressiveLoad()会测试MIME的类型,重点是commitLoad()
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 protect(this);
6
7 commitIfReady();
8 if (FrameLoader* frameLoader = DocumentLoader::frameLoader())
9 frameLoader->committedLoad(this, data, length);
10 }
前面一个调用:commitIfReady()是清理前一次页面扫描的中间数据;committedLoad()才是正题。
1 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
2 {
3 if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType()))
4 return;
5 m_client->committedLoad(loader, data, length);
6 }
其中m_client指向的是FrameLoaderClientQT对象实体。
1 void FrameLoaderClientQt::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)
2 {
3 if (!m_pluginView) {
4 if (!m_frame)
5 return;
6 FrameLoader *fl = loader->frameLoader();
7 if (m_firstData) {
8 fl->setEncoding(m_response.textEncodingName(), false);
9 m_firstData = false;
10 }
11 fl->addData(data, length);
12 }
13
14 // We re-check here as the plugin can have been created
15 if (m_pluginView) {
16 if (!m_hasSentResponseToPlugin) {
17 m_pluginView->didReceiveResponse(loader->response());
18 // didReceiveResponse sets up a new stream to the plug-in. on a full-page plug-in, a failure in
19 // setting up this stream can cause the main document load to be cancelled, setting m_pluginView
20 // to null
21 if (!m_pluginView)
22 return;
23 m_hasSentResponseToPlugin = true;
24 }
25 m_pluginView->didReceiveData(data, length);
26 }
27 }
其中fl->setEncoding()是根据服务器返回的HTML数据流设定编码格式(例如:中文gb2312),另外处理了其他一些事情,例如Redirect等。fl->addData()是关键:
1 void FrameLoader::addData(const char* bytes, int length)
2 {
3 ASSERT(m_workingURL.isEmpty());
4 ASSERT(m_frame->document());
5 ASSERT(m_frame->document()->parsing());
6 write(bytes, length);
7 }
上面的FrameLoader::write()调用,启动了HTML/JS分析扫描
在继续分析FrameLoader::write()之前,先回到前面,那里曾经保存了一个完整的调用堆栈,
......
QtWebKitd4.dll!WebCore::HTMLTokenizer::write(const WebCore::SegmentedString & str={...}, bool appendData=true) 行1730 + 0x23 字节 C++
QtWebKitd4.dll!WebCore::FrameLoader::write(const char *
可知调用的次序为:FrameLoader::write()调用了HTMLTokenizer::write()。
下面是FrameLoader::write()的定义:
1 void write(const char* str, int len = -1, bool flush = false);
这里包含了两个缺省值调用定义,在前一篇,调用的形式是:write(bytes, length);
实际传递的的是:write(bytes, length,
false);
接着看write()的实现
1 void FrameLoader::write(const char* str, int len, bool flush)
2 {
3 if (len == 0 && !flush)
4 return;
5
6 if (len == -1)
7 len = strlen(str);
8
9 Tokenizer* tokenizer = m_frame->document()->tokenizer();
10 if (tokenizer && tokenizer->wantsRawData()) {
11 if (len > 0)
12 tokenizer->writeRawData(str, len);
13 return;
14 }
15
16 if (!m_decoder) {
17 Settings* settings = m_frame->settings();
18 m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
19 if (m_encoding.isEmpty()) {
20 Frame* parentFrame = m_frame->tree()->parent();
21 if (parentFrame && parentFrame->document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin()))
22 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::DefaultEncoding);
23 } else {
24 m_decoder->setEncoding(m_encoding,
25 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
26 }
27 m_frame->document()->setDecoder(m_decoder.get());
28 }
29
30 String decoded = m_decoder->decode(str, len);
31 if (flush)
32 decoded += m_decoder->flush();
33 if (decoded.isEmpty())
34 return;
35
36 #if USE(LOW_BANDWIDTH_DISPLAY)
37 if (m_frame->document()->inLowBandwidthDisplay())
38 m_pendingSourceInLowBandwidthDisplay.append(decoded);
39 #endif
40
41 if (!m_receivedData) {
42 m_receivedData = true;
43 if (m_decoder->encoding().usesVisualOrdering())
44 m_frame->document()->setVisuallyOrdered();
45 m_frame->document()->recalcStyle(Node::Force);
46 }
47
48 if (tokenizer) {
49 ASSERT(!tokenizer->wantsRawData());
50 tokenizer->write(decoded, true);
51 }
52 }
怎么和HTMLTokenizer关联的呢?就是在《QT分析之WebKit(三)》初始化Document对象的时候关联上的。
1 DOMImplementation::createDocument()
上面程序做了一些边缘的工作,例如设定编码(因为可以在HTTP协议、HTML的TITLE部分或者浏览器特别指定编码),主要是新建一个decoder另外一个是调用tokenizer->write()
接着前面的分析,先看m_decoder->decode(str, len);
1 String TextResourceDecoder::decode(const char* data, size_t len)
2 {
3 if (!m_checkedForBOM)
4 checkForBOM(data, len); // 检查是否为Unicode编码
5
6 bool movedDataToBuffer = false;
7
8 if (m_contentType == CSS && !m_checkedForCSSCharset)
9 if (!checkForCSSCharset(data, len, movedDataToBuffer)) // 如果是CSS,则检查CSS的字符集
10 return "";
11
12 if ((m_contentType == HTML || m_contentType == XML) && !m_checkedForHeadCharset) // HTML and XML
13 if (!checkForHeadCharset(data, len, movedDataToBuffer)) // 检查HTML/XML的字符集
14 return "";
15
16 // Do the auto-detect if our default encoding is one of the Japanese ones.
17 // FIXME: It seems wrong to change our encoding downstream after we have already done some decoding.
18 if (m_source != UserChosenEncoding && m_source != AutoDetectedEncoding && encoding().isJapanese())
19 detectJapaneseEncoding(data, len); // 检查日文编码(为什么没有检查中文编码的啊?)
20
21 ASSERT(encoding().isValid());
22
23 if (m_buffer.isEmpty())
24 return m_decoder.decode(data, len, false, m_contentType == XML, m_sawError);
25
26 if (!movedDataToBuffer) {
27 size_t oldSize = m_buffer.size();
28 m_buffer.grow(oldSize + len);
29 memcpy(m_buffer.data() + oldSize, data, len);
30 }
31
32 String result = m_decoder.decode(m_buffer.data(), m_buffer.size(), false, m_contentType == XML, m_sawError);
33 m_buffer.clear();
34 return result;
35 }
再回到tokenizer->write(decoded, true);看其具体实现:
1 bool HTMLTokenizer::write(const SegmentedString& str, bool appendData)
2 {
3 if (!m_buffer)
4 return false;
5
6 if (m_parserStopped)
7 return false;
8
9 SegmentedString source(str);
10 if (m_executingScript)
11 source.setExcludeLineNumbers();
12
13 if ((m_executingScript && appendData) || !m_pendingScripts.isEmpty()) {
14 // don't parse; we will do this later
15 if (m_currentPrependingSrc)
16 m_currentPrependingSrc->append(source);
17 else {
18 m_pendingSrc.append(source);
19 #if PRELOAD_SCANNER_ENABLED
20 if (m_preloadScanner && m_preloadScanner->inProgress() && appendData)
21 m_preloadScanner->write(source);
22 #endif
23 }
24 return false;
25 }
26
27 #if PRELOAD_SCANNER_ENABLED
28 if (m_preloadScanner && m_preloadScanner->inProgress() && appendData)
29 m_preloadScanner->end();
30 #endif
31
32 if (!m_src.isEmpty())
33 m_src.append(source);
34 else
35 setSrc(source);
36
37 // Once a timer is set, it has control of when the tokenizer continues.
38 if (m_timer.isActive())
39 return false;
40
41 bool wasInWrite = m_inWrite;
42 m_inWrite = true;
43
44 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
45 if (!m_doc->ownerElement())
46 printf("Beginning write at time %d ", m_doc->elapsedTime());
47 #endif
48
49 int processedCount = 0;
50 double startTime = currentTime();
51
52 Frame* frame = m_doc->frame();
53
54 State state = m_state;
55
56 while (!m_src.isEmpty() && (!frame || !frame->loader()->isScheduledLocationChangePending())) {
57 if (!continueProcessing(processedCount, startTime, state))
58 break;
59
60 // do we need to enlarge the buffer?
61 checkBuffer();
62
63 UChar cc = *m_src;
64
65 bool wasSkipLF = state.skipLF();
66 if (wasSkipLF)
67 state.setSkipLF(false);
68
69 if (wasSkipLF && (cc == ' '))
70 m_src.advance();
71 else if (state.needsSpecialWriteHandling()) {
72 // it's important to keep needsSpecialWriteHandling with the flags this block tests
73 if (state.hasEntityState())
74 state = parseEntity(m_src, m_dest, state, m_cBufferPos, false, state.hasTagState());
75 else if (state.inPlainText())
76 state = parseText(m_src, state);
77 else if (state.inAnySpecial())
78 state = parseSpecial(m_src, state);
79 else if (state.inComment())
80 state = parseComment(m_src, state);
81 else if (state.inDoctype())
82 state = parseDoctype(m_src, state);
83 else if (state.inServer())
84 state = parseServer(m_src, state);
85 else if (state.inProcessingInstruction())
86 state = parseProcessingInstruction(m_src, state);
87 else if (state.hasTagState())
88 state = parseTag(m_src, state);
89 else if (state.startTag()) {
90 state.setStartTag(false);
91
92 switch(cc) {
93 case '/':
94 break;
95 case '!': {
96 // or
97 searchCount = 1; // Look for ' m_doctypeSearchCount = 1;
98 break;
99 }
100 case '?': {
101 // xml processing instruction
102 state.setInProcessingInstruction(true);
103 tquote = NoQuote;
104 state = parseProcessingInstruction(m_src, state);
105 continue;
106
107 break;
108 }
109 case '%':
110 if (!m_brokenServer) {
111 //
112 state.setInServer(true);
113 tquote = NoQuote;
114 state = parseServer(m_src, state);
115 continue;
116 }
117 // else fall through
118 default: {
119 if( ((cc >= 'a') && (cc = 'A') && (cc ownerElement())
169 printf("Ending write at time %d ", m_doc->elapsedTime());
170 #endif
171
172 m_inWrite = wasInWrite;
173
174 m_state = state;
175
176 if (m_noMoreData && !m_inWrite && !state.loadingExtScript() && !m_executingScript && !m_timer.isActive()) {
177 end(); // this actually causes us to be deleted
178 return true;
179 }
180 return false;
181 }
在调用的时候,因为调用参数decoded是String类型的,所以先隐含转化成SegmentedString。SegmentedString可以附带行号,也可以不带行号(可以设定)。上面程序中的while循环主体,就是一个分析程序主体。
WebKit的结构与解构
原文地址:http://blog.sina.com.cn/s/blog_46d0a3930100d5pt.html
从指定一个HTML文本文件,到绘制出一幅布局复杂,字体多样,内含图片音频视频等等多媒体内容的网页,这是一个复杂的过程。在这个过程中Webkit所做的一切,都是围绕DOM Tree和Rendering Tree这两个核心。上一章我们谈到这两棵树各自的功用,这一章,我们借一个简单的HTML文件,展示一下DOM Tree和Rendering Tree的具体构成,同时解剖一下Webkit是如何构造这两棵树的。
Figure 1. From HTML to webpage, and the underlying DOM tree and rendering tree. Courtesy http://farm4.static.flickr.com/3351/3556972420_23a30366c2_o.jpg
1. DOM Tree 与 Rendering Tree 的结构
Figure 1中左上是一个简单的HTML文本文件,右上是Webkit rendering engine绘制出来的页面。页面的内容包括一个标题,”AI”,一行正 ,”Ape’s Intelligence”,以及一幅照片。整个页面分成前后两个层面,标题和正文绘制在前一个层面,照片处于后一个层面。L君和我亦步亦趋地跟踪了,从解析这个HTML文本文件,到生成DOM Tree和Rendering Tree的整个流程,目的是为了了解DOM Tree和Rendering Tree的具体成份,以及构造的各个步骤。
先说Figure 1中左下角的DOM Tree。基本上HTML文本文件中每个tag,在webkit/webcore/html中都有一个class与之对应。譬如 tag 对应HTMLHtmlElement, tag 对应HTMLHeadElement,
Original: https://www.cnblogs.com/bigben0123/p/15292474.html
Author: Bigben
Title: QT分析之WebKit
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551299/
转载文章受原作者版权保护。转载请注明原作者出处!