Webkit中加载页面时需要进行资源加载,分为主资源加载及派生资源加载两种流程。
MainResource加载流程:
1. DocumentLoader::startLoadingMainResource()调用 MainResourceLoader::load() 向 loader 发起请求
2. 调用 MainResourceLoader::loadNow()
3. 调用 MainResourceLoader::willSendRequest()
4. 调用 ResourceLoader::willSendRequest(), 将 callback 通过 ResourceNotifier 传导给 FrameLoaderClientAndroid 。 Client 可以在回调中操作 ResourceRequest ,比如设置请求头部。
5. 调用 PolicyChecker::checkNavigationPolicy() 过滤掉重复请求等
6. loader 调用 ResourceHandle::create() 向 Network 发起加载请求
7. ResourceHandleAndroid::start()调用ResourceLoaderAndroid::start()
8. ResourceLoaderAndroid::start()中通过webFrame调用WebFrame::startLoadingResource()进而通过JNI调用java层函数startLoadingResource()发起网络请求。
9. 收到第一个 HTTP 响应数据包 ,Network 回调MainResourceLoader::didReceiveResponse() ,主要处理 HTTP 头部。
10. 调用 PolicyChecker:: checkContentPolicy(), 并最终通过 FrameLoaderClientAndroid 的dispatchDecidePolicyForMIMEType() 判断是否为下载请求(存在 "Content-Disposition"http 头部)
11. 通过PolicyChecken::ContinuAfterContentPolicy()回调 MainResourceLoader::continueAfterContentPolicy() ,根据ResourceResponse 检测是否发生错误。
12. 调用 ResourceLoader::didReceiveResponse() ,将 callback 通过 ResourceNotifier传导给 FrameLoaderClientAndroid 。
13. 收到 HTTP 体部数据,调用 MainResourceLoader::didReceiveData()
14. 调用 ResourceLoader::didReceiveData() ,将 callback 通过 ResourceNotifier 传导给 FrameLoaderClientAndroid
15. 多态调用 MainResourceLoader::addData()
16. 调用 DocumentLoader::receivedData()
17. 调用 DocumentLoader::commitLoad()
18. 在DocumentLoader::commitLoad()中调用DocumentLoader::commitIfReady(),在其中调用 FrameLoader::commitProvisionalLoad() , FrameLoader 从 provisional 状态跃迁到 Committed 状态
19. 在DocumentLoader::commitLoad()中调用 FrameLoader::committedLoad()
20. 多态调用FrameLoaderClientAndroid::committedLoad(),通过DocumentLoader中的FrameLoader 对象来处理数据(FrameLoader::setEncoding() , FrameLoader::addData() )
21. 调用 FrameLoader::addData()
22. 调用FrameLoader::write()
23. 多态调用 HTMLTokenizer::write() ,进行 HTML 解析
24. 数据来齐,调用 MainResourceLoader::didFinishLoading()
25. 调用 FrameLoader::finishedLoading()
26. 调用 DocumentLoader::finishedLoading()
27. 调用 FrameLoader::finishedLoadingDocument() ,启动 FrameLoad 对象接收剩余数据,重复 21-23 进行解析
28. 调用 FrameLoader::end()
29. 调用FrameLoader::endIfNotLoadingMainResource()结束接收数据(通过Frame对象调用 Document::finishParsing() )
30. 调用 HTMLTokenizer::finish()
SubResource加载流程:
以 image 为例分析其加载过程
1. 解析 html 页面的时候,解析到 img 标签,调用 HTMLImageElement::HTMLImageElement()创建 HTMLImageElement 对象,该对象包含 HTMLImageLoader 对象m_imageLoader
2. 解析到 img 的 href 属性,调用ImageLoader::updateFromElementIgnoringPreviousError()
3. 调用 ImageLoader::updateFromElement()
4. 调用 DocLoader::requestImage()
5. 调用 DocLoader::requestResource()
6. 调用 Cache::requestResource()
7. 调用Cache::resourceForURL()在cache中查找是否有对应的cache条目,如果没有创建之
8. 根据 Resource 的类型调用static createResource() 创建对应的 CachedResource
9. 调用 CachedImage::load()
10. 调用 CachedResource::load()
11. 调用 Loader::load()创建新的reques对象,并添加到请求队列中,设置相关优先顺序。
其后执行流程与MainResourceLoader流程类似。
最后接收到数据之后根据mimetypr创建ImageDocument对象,调用相应的ImageTokenizer::writeRawData对象,在CachedImage::data中创建image对象并进行数据保存,finish之后则在ImageTokenizer::finish中调用CachedImage::data进行处理将相应的数据保存至缓存中。
当输入url点击Go按钮后即会创建一个新的webview,依次调用WebView.loadUrl、BrowserFrame.loadUrl,在JAVA层创建BrowserFrame时会通过JNI函数调用CreateFrame,在CreateFrame中创建Page对象,随后通过jni调用WebCoreFrameBridge::LoadUr,依次创建Frame、FrameLoader对象,随后在执行loadWithDocumentLoader时创建Document对象。
在Frameloader::begin中,通过调用DOMImplementation::createDocument创建相应的document对象。在DOMImplementation::createDocument中,根据MIMETYPE值不同创建不同的document对象(若页面为HTML或者XHTML时,通过Document::createXHTML函数创建document对象;若页面为WML时,通过WMLDocument::create函数创建WMLDocument对象;若为ftp时,则调用FTPDirectoryDocument::create创建FTPDirectoryDocument对象;当MIMETYPE为pdf时,则调用PluginDocument::create创建PluginDocument对象.)
当执行Document::write时,通过调用Document::open函数,在调用Document::implicitOpen函数中创建Tokenizer对象,若为HTML则调用HTMLDocument::createTokenizer,返回HTMLTokenizer对象;若为WML则由于WMLDocument.cpp中未实现createTokenizer函数而直接调用Document::createTokenizer函数,返回XMLTokenizer对象。