基于 Safari
在 WebKit2 中
打开一个新的Tab,首先调用的
void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
{
// It is necessary to check for page existence here since during a window.open() (or targeted
// link) the WebPage gets created both in the synchronous handler and through the normal way.
HashMap<uint64_t, RefPtr<WebPage> >::AddResult result = m_pageMap.add(pageID, 0);
if (result.isNewEntry) {
ASSERT(!result.iterator->value);
result.iterator->value = WebPage::create(pageID, parameters);
创建WebPage
PassRefPtr<WebPage> WebPage::create(uint64_t pageID, const WebPageCreationParameters& parameters)
{
RefPtr<WebPage> page = adoptRef(new WebPage(pageID, parameters));
接下来进入 WebPage 的构造函数 ,构造函数中创建 PageClients, WebChromeClient, WebContextMenuClient, WebEditorClient, WebDragClient, WebBackForwardListProxy, WebInspectorClient, WebPluginClient 以及Page 对象等。
WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
Settings::setDefaultMinDOMTimerInterval(0.004);
Page::PageClients pageClients;
pageClients.chromeClient = new WebChromeClient(this);
pageClients.contextMenuClient = new WebContextMenuClient(this);
pageClients.editorClient = new WebEditorClient(this);
pageClients.dragClient = new WebDragClient(this);
pageClients.backForwardClient = WebBackForwardListProxy::create(this);
m_inspectorClient = new WebInspectorClient(this);
pageClients.inspectorClient = m_inspectorClient;
pageClients.plugInClient = new WebPlugInClient(this);
m_page = adoptPtr(new Page(pageClients));
...
Page 的构造函数中创建 Chrome 对象,DragCaretController对象,FocusController,ContextMenuController,
InspectorController,Settings 等
//WebCore
Page::Page(PageClients& pageClients)
: m_chrome(Chrome::create(this, pageClients.chromeClient))
, m_dragCaretController(DragCaretController::create())
#if ENABLE(DRAG_SUPPORT)
, m_dragController(DragController::create(this, pageClients.dragClient))
#endif
, m_focusController(FocusController::create(this))
#if ENABLE(CONTEXT_MENUS)
, m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
#endif
#if ENABLE(INSPECTOR)
, m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
#endif
, m_settings(Settings::create(this))
, m_progress(ProgressTracker::create())
, m_backForwardController(BackForwardController::create(this, pageClients.backForwardClient))
Page 对象创建完之后 WebPage 还会接着创建以下对象:
//WebKit2
#if ENABLE(GEOLOCATION)
WebCore::provideGeolocationTo(m_page.get(), new WebGeolocationClient(this));
#endif
#if ENABLE(NETWORK_INFO)
WebCore::provideNetworkInfoTo(m_page.get(), new WebNetworkInfoClient(this));
#endif
#if ENABLE(VIBRATION)
WebCore::provideVibrationTo(m_page.get(), new WebVibrationClient(this));
#endif
#if ENABLE(PROXIMITY_EVENTS)
WebCore::provideDeviceProximityTo(m_page.get(), new WebDeviceProximityClient(this));
#endif
m_page->setCanStartMedia(false);
m_mayStartMediaWhenInWindow = parameters.mayStartMediaWhenInWindow;
m_pageGroup = WebProcess::shared().webPageGroup(parameters.pageGroupData);
m_page->setGroupName(m_pageGroup->identifier());
m_page->setDeviceScaleFactor(parameters.deviceScaleFactor);
m_drawingArea = DrawingArea::create(this, parameters);
m_drawingArea->setPaintingEnabled(false);
updatePreferences(parameters.store);
platformInitialize();
m_mainFrame = WebFrame::createMainFrame(this);
这里先看一下 WebFrame::createMainFrame(this), 创建 WebFrame,并对 frame做初始化。
PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page)
{
RefPtr<WebFrame> frame = create();
page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
frame->init(page, String(), 0);
return frame.release(); // 这个 release 只是减少了引用计数
}
frame 的 init 过程会创建 Frame对象
void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
{
RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
把创建的Frame 设定成 MainFrame,关于MainFrame,Frame,Page,Document 的关系,参看《 走进WebKit--开篇》
//WebCore
PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
{
RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
if (!ownerElement)
page->setMainFrame(frame);
return frame.release();
}
在 Frame 的构造函数中依次给成员变量赋值
Page* m_page;
mutable FrameTree m_treeNode; //
用来协助管理父帧和子帧,常见的是 main frame 和 iframe之间
mutable FrameLoader m_loader; // 用来完成 Frame 的加载
mutable NavigationScheduler m_navigationScheduler; // 页面跳转调度器
HTMLFrameOwnerElement* m_ownerElement;
RefPtr<FrameView> m_view; // 用于Frame 的排版
RefPtr<Document> m_doc; // 用来管理DOM节点
ScriptController m_script; // 脚本控制器
mutable Editor m_editor; //处理页面编辑
mutable FrameSelection m_selection; // 选取
mutable EventHandler m_eventHandler; //处理鼠标事件,按键事件等 UI交互事件
mutable AnimationController m_animationController;
inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
: m_page(page)
, m_treeNode(this, parentFromOwnerElement(ownerElement))
, m_loader(this, frameLoaderClient)
, m_navigationScheduler(this)
, m_ownerElement(ownerElement)
, m_script(this)
, m_editor(this)
, m_selection(this)
, m_eventHandler(this)
, m_animationController(this)
, m_pageZoomFactor(parentPageZoomFactor(this))
, m_textZoomFactor(parentTextZoomFactor(this))
#if ENABLE(ORIENTATION_EVENTS)
, m_orientation(0)
#endif
, m_inViewSourceMode(false)
, m_activeDOMObjectsAndAnimationsSuspendedCount(0)
{
ASSERT(page);
AtomicString::init();
HTMLNames::init();
QualifiedName::init();
MediaFeatureNames::init();
SVGNames::init();
XLinkNames::init();
MathMLNames::init();
XMLNSNames::init();
XMLNames::init();
WebKitFontFamilyNames::init();
FrameLoader 构造函数中初始化成员变量。
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
: m_frame(frame)
, m_client(client)
, m_policyChecker(frame)
, m_history(frame)
, m_notifer(frame)
, m_subframeLoader(frame)
, m_icon(frame)
, m_mixedContentChecker(frame)
, m_state(FrameStateProvisional)
, m_loadType(FrameLoadTypeStandard)
, m_delegateIsHandlingProvisionalLoadError(false)
, m_quickRedirectComing(false)
, m_sentRedirectNotification(false)
, m_inStopAllLoaders(false)
, m_isExecutingJavaScriptFormAction(false)
, m_didCallImplicitClose(true)
, m_wasUnloadEventEmitted(false)
, m_pageDismissalEventBeingDispatched(NoDismissal)
, m_isComplete(false)
, m_needsClear(false)
, m_checkTimer(this, &FrameLoader::checkTimerFired)
, m_shouldCallCheckCompleted(false)
, m_shouldCallCheckLoadComplete(false)
, m_opener(0)
#if PLATFORM(CHROMIUM)
, m_didAccessInitialDocument(false)
, m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
#endif
, m_didPerformFirstNavigation(false)
, m_loadingFromCachedPage(false)
, m_suppressOpenerInNewFrame(false)
, m_forcedSandboxFlags(SandboxNone)
{
}
WebFrame::init 完成后面会调用 frame->init() 进行初始化动作
void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
{
RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
m_coreFrame = frame.get();
frame->tree()->setName(frameName);
if (ownerElement) {
ASSERT(ownerElement->document()->frame());
ownerElement->document()->frame()->tree()->appendChild(frame);
}
frame->init();
}
其实只做了一件事情,初始化 FrameLoader
inline void Frame::init()
{
m_loader.init();
}
void FrameLoader::init()
{
// This somewhat odd set of steps gives the frame an initial empty document.
setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, emptyString())), SubstituteData()).get());
setProvisionalDocumentLoader(m_policyDocumentLoader.get());
m_provisionalDocumentLoader->startLoadingMainResource();
m_frame->document()->cancelParsing();
m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
m_networkingContext = m_client->createNetworkingContext();
m_progressTracker = FrameProgressTracker::create(m_frame);
}
创建DocumentLoader过程中会创建 CachedResourceLoader,DocumentWriter 等
FrameLoader 维护了三个 DocumentLoader 对象分别对应三个不同的阶段。在后面加载过程中再做分析
RefPtr<DocumentLoader> m_documentLoader;
RefPtr<DocumentLoader> m_provisionalDocumentLoader;
RefPtr<DocumentLoader> m_policyDocumentLoader;
接下来的 m_provisionalDocumentLoader->startLoadingMainResource(); 实际上只判断是不是加载空页面就返回了。
if (maybeLoadEmpty())
return;
maybeLoadEmpty()中关键 call stack 如下: maybeLoadEmpty() 做一些处理之后,调用 finishedLoading(), finishedLoading() 调用 commitIfReady() ,在 commitProvisionalLoad 中完成提交。
frame #0: 0x0000000103e402e5 WebCore`WebCore::FrameLoader::transitionToCommitted(this=0x000000010c121080, cachedPage=0x00007fff5fbfc5e8)
frame #1: 0x0000000103e3f623 WebCore`WebCore::FrameLoader::commitProvisionalLoad(this=0x000000010c121080)
frame #2: 0x0000000103b6136c WebCore`WebCore::DocumentLoader::commitIfReady(this=0x000000010b94d400)
frame #3: 0x0000000103b613f9 WebCore`WebCore::DocumentLoader::finishedLoading(this=0x000000010b94d400)
frame #4: 0x0000000103b63ecb WebCore`WebCore::DocumentLoader::maybeLoadEmpty(this=0x000000010b94d400)
在 transitionToCommitted 中把前面 m_provisionalDocumentLoader 赋值给
m_documentLoader, 将 m_provisionalDocumentLoader 置空,将 FrameLoader的
m_state 从初始化时的 FrameStateProvisional 设定成FrameStateCommittedPage, DocumentWriter 的MIMEType设定成 “text/html”, 此时 DocumentStateMachine 还是CreatingInitialEmptyDocument 状态
m_committed = true;
setDocumentLoader(m_provisionalDocumentLoader.get());
setProvisionalDocumentLoader(0);
setState(FrameStateCommittedPage);
m_documentLoader->writer()->setMIMEType(dl->responseMIMEType());
if (m_stateMachine.creatingInitialEmptyDocument())
return;
返回到 finishedLoading() 中
void DocumentLoader::finishedLoading()
{
commitIfReady();
if (!frameLoader())
return;
if (!maybeCreateArchive()) {
// If this is an empty document, it will not have actually been created yet. Commit dummy data so that
// DocumentWriter::begin() gets called and creates the Document.
if (!m_gotFirstByte)
commitData(0, 0);
frameLoader()->client()->finishedLoading(this);
}
m_writer.end();
if (!m_mainDocumentError.isNull())
return;
clearMainResourceLoader();
if (!frameLoader()->stateMachine()->creatingInitialEmptyDocument())
frameLoader()->checkLoadComplete();
}
注意上面的注释,正是初始化过程的情况。 commitData(0,0) 会调用到DocumentWriter::begin(), 在里面创建 Document 和 DOMWindow,设置 DocumentParser,将WriterState 设定为 StartedWritingStatecommitData 之后就会调用
frameLoader()->client()->finishedLoading(this);
m_writer.end();
m_writer.end() 中会 把 WriterState 改成 FinishedWritingState,然后将 DocumentParser 清理掉
void DocumentWriter::end()
{
ASSERT(m_frame->page());
ASSERT(m_frame->document());
// The parser is guaranteed to be released after this point. begin() would
// have to be called again before we can start writing more data.
m_state = FinishedWritingState;
// http://bugs.webkit.org/show_bug.cgi?id=10854
// The frame's last ref may be removed and it can be deleted by checkCompleted(),
// so we'll add a protective refcount
RefPtr<Frame> protector(m_frame);
if (!m_parser)
return;
// FIXME: m_parser->finish() should imply m_parser->flush().
m_parser->flush(this);
if (!m_parser)
return;
m_parser->finish();
m_parser = 0;
}