走进WebKit——打开新Tab(一)

基于 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()); // 1
    setProvisionalDocumentLoader(m_policyDocumentLoader.get()); //2
    m_provisionalDocumentLoader->startLoadingMainResource();    //3
    m_frame->document()->cancelParsing();       //4
    m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);  //5

    m_networkingContext = m_client->createNetworkingContext();  //6
    m_progressTracker = FrameProgressTracker::create(m_frame);  //7
}

 创建DocumentLoader过程中会创建 CachedResourceLoader,DocumentWriter 等

刚创建的 DocumentLoader 会被 setPolicyDocumentLoader 设定成 m_policyDocumentLoader,然后被

setProvisionalDocumentLoader设定为 m_provisionalDocumentLoader

 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: WebCore`WebCore::FrameLoader::commitProvisionalLoad(this=0x000000010c121080) 
    frame #2: WebCore`WebCore::DocumentLoader::commitIfReady(this=0x000000010b94d400) 
    frame #3: WebCore`WebCore::DocumentLoader::finishedLoading(this=0x000000010b94d400)
    frame #4: 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,从Document中获取DocumentParser,将WriterState 设定为 StartedWritingState

commitData 之后就会调用 

frameLoader()->client()->finishedLoading(this);
m_writer.end();

m_writer.end() 中会 把 WriterState 改成 FinishedWritingState,然后将 DocumentWriter 维护的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;
}

至此 DocumentWriter 的状态完成跃迁:

    
DocumentWriter::DocumentWriter()  begin()end()
WriterStateNotStartedWritingStateStartedWritingStateFinishedWritingState

void FrameLoader::init() 中

m_provisionalDocumentLoader->startLoadingMainResource(); //3  执行完之后,接着执行

 m_frame->document()->cancelParsing(); 把 Document 的解析取消掉,调用关系如下

Document::cancelParsing()  >> Document::detachParser() >> Document::explicitClose() >> FrameLoader::checkCompleted() >> FrameLoader::checkLoadComplete() >> FrameLoader::checkLoadCompleteForThisFrame() >> setState(FrameStateComplete);

到这里, FrameLoader 中维护的 FrameState 也转了一圈

    enum FrameState {

        FrameStateProvisional,

        // This state indicates we are ready to commit to a page,

        // which means the view will transition to use the new data source.

        FrameStateCommittedPage,

        FrameStateComplete

    };

FrameLoader::FrameLoader()transitionToCommited()checkLoadCompleteForThisFrame()
FrameStateFrameStateProvisionalFrameStateCommittedPageFrameStateComplete







                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值