该文章整理自 网易博客 http://blog.163.com/net_worm/blog/static/12770241920101831312381/
转载请注明出处
WebKit是QT4新整合的第三方构件。按照惯例动手分析之前,先了解大概
WebKit由三个模块组成:JavaScriptCore、WebCore 和 WebKit
WebKit作为了整个项目的名称。其目录结构:(未校准)
WebCore:
¨Page与外框相关的内容(Frame,Page,History,Focus,Window)
¨Loader加载资源及Cache
¨HTML-DOM HTML内容及解析
¨DOM- DOM CORE内容
¨XML- XML内容及解析
¨Render-排版功能
¨CSS-DOM CSS内容
¨Binding-DOM与JavascriptCore绑定的功能
¨Editing-所有与编辑相关的功能
JavascriptCore-javascript引擎
¨API-基本javascript功能
¨Binding与其它功能绑定的功能,如:DOM,C,JNI
¨DerviedSource自动产生的代码
¨ForwordHeads头文件,无实际意义
¨PCRE-Perl-Compatible Regular Expressions
¨KJS-Javascript Kernel
¨WTF-KDE的C++模板库
Unicode unicode 库
Tools tools库
CURL-url 客户端传输库
PlatForm- 与平台相关的功能,如图形图像,字体,Unicode, IO,输入法等.
在QT自带的例子中,有WebKit相关的例子。我选中previewer作为分析的项目。
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<WebCore::FormState> formState={...}, bool shouldContinue=true) 行3968 C++
6 QtWebKitd4.dll!WebCore::FrameLoader::callContinueLoadAfterNavigationPolicy(void * argument=0x01d424e8, const WebCore::ResourceRequest & request={...}, WTF::PassRefPtr<WebCore::FormState> 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<WebCore::FormState> __formal={...}) 行938 C++
11 QtWebKitd4.dll!WebCore::FrameLoader::checkNavigationPolicy(const WebCore::ResourceRequest & request={...}, WebCore::DocumentLoader * loader=0x00f63ff8, WTF::PassRefPtr<WebCore::FormState> formState={...}, void (void *, const WebCore::ResourceRequest &, WTF::PassRefPtr<WebCore::FormState>, bool)* function=0x1004e661, void * argument=0x01d424e8) 行3868 C++
12 QtWebKitd4.dll!WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader * loader=0x00f63ff8, WebCore::FrameLoadType type=FrameLoadTypeRedirectWithLockedHistory, WTF::PassRefPtr<WebCore::FormState> prpFormState={...}) 行2291 C++
13 QtWebKitd4.dll!WebCore::FrameLoader::loadWithNavigationAction(const WebCore::ResourceRequest & request={...}, const WebCore::NavigationAction & action={...}, WebCore::FrameLoadType type=FrameLoadTypeRedirectWithLockedHistory, WTF::PassRefPtr<WebCore::FormState> 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<WebCore::FormState> 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<enum QEventLoop::ProcessEventsFlag> flags={...}) 行679 + 0x10 字节 C++
52 QtGuid4.dll!QGuiEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) 行1182 + 0x15 字节 C++
53 QtCored4.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...}) 行150 C++
54 QtCored4.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> 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<SecurityOrigin> 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> 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<Frame> 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 QList<QByteArray> httpHeaders = 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<FormState> 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> formState = prpFormState; 12 bool isFormSubmission = formState; 13 14 const KURL& newURL = loader->request().url(); 15 16 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) { 17 RefPtr<DocumentLoader> 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> 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<WebCore::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> formState, bool shouldContinue) 3 { 4 FrameLoader* loader = static_cast<FrameLoader*>(argument); 5 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue); 6 } 7 8 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> 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 // <rdar://problem/6250856> - 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 // <rdar://problem/4801066> 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<MainResourceLoader> 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<ResourceLoader> 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> ResourceHandle::create(const ResourceRequest& request, ResourceHandleClient* client, 2 Frame* frame, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle) 3 { 4 RefPtr<ResourceHandle> 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<FrameLoaderClientQt*>(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请求发送基本完成。
原文:http://www.cnblogs.com/lfsblack/p/5278777.html