走进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());

    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 等

刚创建的 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()begin, end

|   |  |

WriterState : NotStartedWritingState -> StartedWritingState -> FinishedWritingState


 

 


你可能感兴趣的:(webkit)