• 走进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


    
    
  • 相关阅读:
    在为知笔记中使用JQuery
    解决Wireshark安装Npcap组件失败
    SSL/TLS抓包出现提示Ignored Unknown Record
    Metasploit中aggregator插件无法使用
    Metasploit运行环境内存不要低于2GB
    如何查看抓包文件所使用的捕获过滤器
    Nvidia的CUDA库现在恢复使用了
    Metasploit远程调用Nessus出错
    Nessus更新到8.3.0
    Kali Linux安装字典StarDict
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2995392.html
Copyright © 2020-2023  润新知