WebKit内核源码分析

摘要:本系列通过分析WebKit的源代码,试图分析WebKit的内核设计架构,模块之间的关系,分析的时候以Qt的移植为参考,涉及移植的东西不多,主要还是以内核为主。在分析内核的时候,Frame是首当其冲的一个类,本文将分析Frame类的代码。

1.    描述

Frame类是WebCore内核同应用之间联系的一个重要的类。它有点像设计模式中的Façade,将内核的各个不同的零配件组装在了一起,但又不是Façade,因为用户很多时候还是要直接去操作里面的组件。除了设计上的考虑,Frame还有语法上的意义,它对应于Page里面的帧。

2.    类结构

 

 

1)              FrameTree对象用来协助管理父帧和子帧的关系,常见的比如main frame之中有iframe元素,就会调用FrameLoaderClientQt::createFrame来产生子帧,产生的子帧会通过appendChild添加到主帧的树状结构中。Frame通过FrameTree对象,可以方便地访问它的父帧,子帧,兄弟帧。

2)              维护FrameLoader对象用来完成frame的加载,FrameLoader是一个非常重要的类,后续进行进一步的分析。

3)              维护NavigationScheduler对象用来管理页面跳转调度(比如重定向,meta refresh等)。

4)              DOMWindow用来管理同DOM相关的事件、属性和消息。

5)              FrameViwe类用于Frame的排版。

6)              Frame文档解析后,对每一个tag或者attr,会有对应的dom节点关联,Document类用来管理这些dom节点。不同的文档类型继承出不同的子类,比如HTML文档对应子类HTMLDocument,XML文档对应于XMLDocument。

7)              SciptController对象,脚本控制器,用来管理脚本的执行和操作。

8)              Editor对象用来处理页面的编辑相关的操作,比如拷贝,粘贴,输入等,Editor对象,它同Page类的EditorClient对象紧密合作。和EditorClient的关系就如同Page同Frame的关系。

9)              SelectionController用来管理Frame中的选取操作。

10)         AnimationControlle,动画控制,控制动画的播放,暂停,继续(同HTML video标签是否有关系?)

11)         EventHandler,事件处理对象,这里的对象主要是同上层应用也就是用户参与的事件,比如鼠标事件,按键事件(快捷键等),滚动事件,resize事件等。这是一个浏览器外壳经常需要打交道的类。

3.    主要接口

3.1   Create

static PassRefPtr<Frame> create(Page*,HTMLFrameOwnerElement*,FrameLoaderClient*)
描述: 调用Frame构造函数,创建出Frame对象。有两个地方会创建Frame对象,一是要加载一个新的页面请求,这个时候会创建main frame,一是在加载子帧的时候,通过FrameLoaderClientQt的createFrame接口,创建子帧对应的Frame对象,在第一种情况中,HTMLFrameOwnerElement参数为NULL,第二种情况传子帧的父元素。在一个tab页内,main frame会重用。

调用系列:

àQwebPage::setView

àQwebPage::setViewportSize

àQwebPage::mainFrame

àQwebPagePrivate::createMainFrame

àQwebFrameData::QwebFrameData

àFrame::create


àFrameLoader::finishedLoading
à……

àHTMLDocumentParser::append

à……

àHTMLTreeBuilder::processToken

à……

àHTMLElementBase::openURL

àSubFrameLoader::requestFrame

à……

àFrameLoaderClientQt::creatFrame

àQwebFrameData::QwebFrameData

àFrame::create

3.2  createView

void createView(const IntSize&, const Color&, bool, const IntSize&, bool,

            ScrollbarMode = ScrollbarAuto, bool horizontalLock = false,

            ScrollbarMode = ScrollbarAuto, bool verticalLock = false)

描述:创建出FrameView对象,以用于之后的排版。应用调用这个函数的时候需要传入同排版有关的一些信息,如初始视窗大小,背景色,滚动条模式等。创建出FrameView以后,即调用Frame::setView设置成当前的FrameView。
函数调用系列:
àFrameLoader::commitProvisionalLoad

àFrameLoader::transitionToCommitted

àFrameLoaderClientQt::transitionToCommittedForNewPage

àFrame::createView

3.3  setDocument

void setDocument(PassRefPtr<Document>)

描述:设置同Frame关联的Document对象(一般是DocumentWriter创建的)。

函数调用系列:

àQWebFrame::QwebFrame

àQwebFramePrivate::init

àFrame::init

àFrameLoader::init

àDocumentWriter::begin

àFrame::setDocument


àDocumentLoader::receivedData
àDocumentLoader::commitLoad

àFrameLoaderClientQt::committedLoad

àDocumentLoader::commitData

àDocumentWriter::setEncoding

àDocumentWriter::willSetEncoding

àFrameLoader::receivedFirstData

àDocumentWriter::begin

àFrameLoader::clear

àFrame::setDocument

3.4  init

void Frame::init

描述:Frame对象初始化,会调用FrameLoader::init初始化FrameLoader对象。

调用系列:
àQWebFrame::QWebFrame

àQwebFramePrivate::init

àFrame::init

3.5  setPageAndTextZoomFactors

void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)

描述:设置页面放大因子和文字放大因子。在网页缩放或者改变网页字体大小的时候调用。

摘要:本系列通过分析WebKit的源代码,试图分析WebKit的内核设计架构,模块之间的关系,分析的时候以Qt的移植为参考,涉及移植的东西不多,主要还是以内核为主。FrameLoader类负责一个Frame的加载,在Frame的流程中起到非常重要的重要,同很多组件都有交互,本文将分析FrameLoader类的代码。

1. 概述

    顾名思义,FrameLoader是一个Frame的loader,它的作用就是为客户提供一个下载一个Frame的一系列接口。这里的客户指的是类的客户,比如Frame类,间接客户是上层应用,比如qwebframe。
    从它的定义看,最容易想到的是一个load接口,用来将一个frame load下来。任何一个页面至少都需要一个mainframe,因此一个页面的下载一般就是从load一个mainframe开始。
    在load frame的过程中,通过FrameLoaderClient接口将load过程的不同阶段告知客户。
    FrameLoader通过setDocumentLoader相当于把load的工作委托给了DocumentLoader类。
    FrameLoader同DocumentLoader是has-a的关系。一般在load的时候创建DocumentLoader。Frame调用DocumentLoader的startLoadingMainResource开始load frame。

2. 类关系



1)Frame和FrameLoader是contain-a的关系,在Frame的构造函数中调用FrameLoader的构造函数,调用时传入参数Frame指针和FrameLoaderClient指针。
2)Frame有可能有子Frame,所以维护SubFrameLoader对象m_subframeLoader来管理子Frame的load。Frame可以对应xml document,也可对应html document,等等。跟Document相关的子resource的load不在FrameLoader的职责范围内。
3)包含一个DocumentWriter类对象m_writer,当Frame的数据load finish的时候,将数据传给DocumentWriter类,进行下一步的处理(比如解码)
4)FrameLoader维护了三个DocumentLoader对象,分别对应于不同的阶段,m_policyDocumentLoader对应于收到用户load调用,进行policy check阶段,m_provisionalDocumentLoader对应于policy check通过以后,Frame数据还没有到来之前,它会负责startLoadingMainResource的调用。m_documentLoader则是Frame第一个数据到来以后使用的DocumentLoader,这个时候,前一个主Frame的DocumentLoader已经不能再用(user agent开始白屏,刷掉前一个页面的显示)。
5)包含一个HistoryController对象,用于操作历史记录相关的接口,保存或者恢复Document和View相关的状态,维护前进后退队列,以实现前进后退功能,前进后退本质上是同Page对象关联的,FrameLoader通过HistoryController操作m_backFowardController对象
6)包含一个ResourceLoadNotifier对象,主要用于同ResourceLoader及FrameLoaderClient打交道,可以理解为ResourceLoader有事件变化或者发生的时候,通知FrameLoader的一个手段
7)包含一个SubframeLoader对象,当FrameLoader下载的Document有子帧需要请求的时候(比如HTMLDocument中解析到iframe 元素),用来处理子帧请求
8)将FrameLoader的状态封装到FrameLoaderStateMachine中,这个状态同FrameState不同,FrameState倾向于判断Frame涉及的Document的下载状态,是出于发起状态(Provisional),还是出于已经收到响应但不全(CommittedPage),还是响应收全的状态,倾向于同http相关。而FramLoaderStateMachine倾向于同DocumentLoader相关,用来描述FrameLoader处理DocumentLoader的节点,是处于已经创建,还是显示的状态。
9)PolicyChecker主要用来对FrameLoader进行一些校验。包括三种校验:NewWindow,Navigation和Content。NewWindow对应于浏览器需要新开一个tab页或窗口的时候,Navigation对应于一个页面请求发起的时候,Content校验对应于收到数据以后(判断Mime type等),PolicyChecker通过提供对应的接口,由FrameLoaderClient来对这些请求进行校验,以确定是否允许继续,或者需要其它的动作。

3.   主要接口

Frame::init

功能:FrameLoader的初始化

函数调用系列
àQWebFrame::QWebFrame(QwebPage* parent,QWebFrameData *frameData)
àQWebFramePrivate::init(QWebFrame* qwebframe,QWebFrameData* frameData)
àFrame::init()
àFrameLoader::init()

说明:主要做一些自身的初始化工作,比如初始化状态机,Sandbox Flags,创建DocumentLoader被设置为Policy DocumentLoader和Provisional DocumentLoader,调用DocumentLoader和documentWriter等的接口进行初始化操作

FrameLoader::commitProvisionalLoad

功能:提交Provisional阶段下载的数据

函数调用系列:
àDocumentLoader::finishLoading
àDocumentLoader::commitIfReady
àFrameLoader::commitProvisionalLoad

或者
àResourceLoader::didReceiveData
àMainResourceLoader::addData
àDocumentLoader::receiveData
àDocumentLoader::commitLoad
àDocumentLoader::commitIfReady
àDocumentLoader::commitProvisionalLoad

说明:这个接口主要的操作是将Provisional DocumentLoader设置成DocumentLoader,因为已经收到数据,所以FrameState也会跃迁到FrameStateCommittedPage。还有历史记录,PageCache相关的操作。另外,这个接口会间接调用FrameLoaderClientQt::transitionToCommittedForNewPage,通过Frame::createView创建出FrameView来。

Frame::finishedLoading

功能:frame请求网络加载完成的时候调用此接口

函数调用系列
àResourceLoader::didFinishLoading
àMainResourceLoader::didFinishLoading
àFrameLoader::finishedLoading
àFrameLoader::init()

说明:检查是否有网络错误,告诉DocumentLoader和DocumentWriter下载完成,以便进行后续操作(提交数据,解析)。

FrameLoader::finishedParsing

功能:解析完成调用此接口

函数调用系列
àDocumentWritter::end
à….
àDocument::finishParsing
à….
àDocument::finishedParsing
àFrameLoader::finishedParsing

FrameLoader::load(const ResourceRequest& request,bool lockHistory)

功能:加载一个frame请求,Frame请求相关的数据,封装成ResourceRequest传入。

函数调用系列:一般由应用触发调用

说明:这个接口调用FrameLoaderClientQt::createDocumentLoader创建出DocumentLoader,并以此DocumentLoader为Policy Document Loader,进入Policy check流程。

摘要:本系列通过分析WebKit的源代码,试图分析WebKit的内核设计架构,模块之间的关系,分析的时候以Qt的移植为参考,涉及移植的东西不多,主要还是以内核为主。FrameLoader类负责一个Frame的加载,在Frame的流程中起到非常重要的重要,同很多组件都有交互,本文将分析FrameLoader类的代码。

1. 概述

    顾名思义,FrameLoader是一个Frame的loader,它的作用就是为客户提供一个下载一个Frame的一系列接口。这里的客户指的是类的客户,比如Frame类,间接客户是上层应用,比如qwebframe。
    从它的定义看,最容易想到的是一个load接口,用来将一个frame load下来。任何一个页面至少都需要一个mainframe,因此一个页面的下载一般就是从load一个mainframe开始。
    在load frame的过程中,通过FrameLoaderClient接口将load过程的不同阶段告知客户。
    FrameLoader通过setDocumentLoader相当于把load的工作委托给了DocumentLoader类。
    FrameLoader同DocumentLoader是has-a的关系。一般在load的时候创建DocumentLoader。Frame调用DocumentLoader的startLoadingMainResource开始load frame。

2. 类关系



1)Frame和FrameLoader是contain-a的关系,在Frame的构造函数中调用FrameLoader的构造函数,调用时传入参数Frame指针和FrameLoaderClient指针。
2)Frame有可能有子Frame,所以维护SubFrameLoader对象m_subframeLoader来管理子Frame的load。Frame可以对应xml document,也可对应html document,等等。跟Document相关的子resource的load不在FrameLoader的职责范围内。
3)包含一个DocumentWriter类对象m_writer,当Frame的数据load finish的时候,将数据传给DocumentWriter类,进行下一步的处理(比如解码)
4)FrameLoader维护了三个DocumentLoader对象,分别对应于不同的阶段,m_policyDocumentLoader对应于收到用户load调用,进行policy check阶段,m_provisionalDocumentLoader对应于policy check通过以后,Frame数据还没有到来之前,它会负责startLoadingMainResource的调用。m_documentLoader则是Frame第一个数据到来以后使用的DocumentLoader,这个时候,前一个主Frame的DocumentLoader已经不能再用(user agent开始白屏,刷掉前一个页面的显示)。
5)包含一个HistoryController对象,用于操作历史记录相关的接口,保存或者恢复Document和View相关的状态,维护前进后退队列,以实现前进后退功能,前进后退本质上是同Page对象关联的,FrameLoader通过HistoryController操作m_backFowardController对象
6)包含一个ResourceLoadNotifier对象,主要用于同ResourceLoader及FrameLoaderClient打交道,可以理解为ResourceLoader有事件变化或者发生的时候,通知FrameLoader的一个手段
7)包含一个SubframeLoader对象,当FrameLoader下载的Document有子帧需要请求的时候(比如HTMLDocument中解析到iframe 元素),用来处理子帧请求
8)将FrameLoader的状态封装到FrameLoaderStateMachine中,这个状态同FrameState不同,FrameState倾向于判断Frame涉及的Document的下载状态,是出于发起状态(Provisional),还是出于已经收到响应但不全(CommittedPage),还是响应收全的状态,倾向于同http相关。而FramLoaderStateMachine倾向于同DocumentLoader相关,用来描述FrameLoader处理DocumentLoader的节点,是处于已经创建,还是显示的状态。
9)PolicyChecker主要用来对FrameLoader进行一些校验。包括三种校验:NewWindow,Navigation和Content。NewWindow对应于浏览器需要新开一个tab页或窗口的时候,Navigation对应于一个页面请求发起的时候,Content校验对应于收到数据以后(判断Mime type等),PolicyChecker通过提供对应的接口,由FrameLoaderClient来对这些请求进行校验,以确定是否允许继续,或者需要其它的动作。

3.   主要接口

Frame::init

功能:FrameLoader的初始化

函数调用系列
àQWebFrame::QWebFrame(QwebPage* parent,QWebFrameData *frameData)
àQWebFramePrivate::init(QWebFrame* qwebframe,QWebFrameData* frameData)
àFrame::init()
àFrameLoader::init()

说明:主要做一些自身的初始化工作,比如初始化状态机,Sandbox Flags,创建DocumentLoader被设置为Policy DocumentLoader和Provisional DocumentLoader,调用DocumentLoader和documentWriter等的接口进行初始化操作

FrameLoader::commitProvisionalLoad

功能:提交Provisional阶段下载的数据

函数调用系列:
àDocumentLoader::finishLoading
àDocumentLoader::commitIfReady
àFrameLoader::commitProvisionalLoad

或者
àResourceLoader::didReceiveData
àMainResourceLoader::addData
àDocumentLoader::receiveData
àDocumentLoader::commitLoad
àDocumentLoader::commitIfReady
àDocumentLoader::commitProvisionalLoad

说明:这个接口主要的操作是将Provisional DocumentLoader设置成DocumentLoader,因为已经收到数据,所以FrameState也会跃迁到FrameStateCommittedPage。还有历史记录,PageCache相关的操作。另外,这个接口会间接调用FrameLoaderClientQt::transitionToCommittedForNewPage,通过Frame::createView创建出FrameView来。

Frame::finishedLoading

功能:frame请求网络加载完成的时候调用此接口

函数调用系列
àResourceLoader::didFinishLoading
àMainResourceLoader::didFinishLoading
àFrameLoader::finishedLoading
àFrameLoader::init()

说明:检查是否有网络错误,告诉DocumentLoader和DocumentWriter下载完成,以便进行后续操作(提交数据,解析)。

FrameLoader::finishedParsing

功能:解析完成调用此接口

函数调用系列
àDocumentWritter::end
à….
àDocument::finishParsing
à….
àDocument::finishedParsing
àFrameLoader::finishedParsing

FrameLoader::load(const ResourceRequest& request,bool lockHistory)

功能:加载一个frame请求,Frame请求相关的数据,封装成ResourceRequest传入。

函数调用系列:一般由应用触发调用

说明:这个接口调用FrameLoaderClientQt::createDocumentLoader创建出DocumentLoader,并以此DocumentLoader为Policy Document Loader,进入Policy check流程。


摘要:浏览器的请求一般是以页面请求为单位,当用户通过网址栏输入一个url,浏览器就开始一个页面请求。而一个页面请求可能包含有一到多个页面子帧,以及图片、CSS和插件等派生子资源。Page类就是用来对应这样的页面请求。Page类是WebKit中非常重要的一个类,它就像内核对外的一个聚合器。

关键词:WebKit内核源代码,WebCore,Page,FrameWebKit架构

1.
概述

浏览器的请求一般是以页面请求为单位,当用户通过网址栏输入一个url,浏览器就开始一个页面请求。而一个页面请求可能包含有一到多个页面子帧,以及图片、CSS和插件等派生子资源。Page类就是用来对应这样的页面请求。前进后退,导航,编辑,右键菜单,设置,Inspector等这些用户参与的动作,大部分是同Page相关的。而标记语言解析、排版、加载则更多地同Frame相关。

我们通过几个图来看下Qt移植中Page类同应用之间的关系。




QWebPage通过QWebPagePrivate维护Page类的指针,并在QWebPagePrivate的构造函数中实例化Page对象。QWebPage类通过之后的createMainFrame调用实例化QwebFrame,而在QwebFrameData的构造函数中,以Page指针为参数调用了Frame::create 创建出Frame对象。




Page类通过组合其它类的方式,实现了很多功能,Page类本身并没有多少代码。

2.
类关系2.1
PageGroup

PageGroup并不是用来对Page进行管理的,而是设计用来将一些具有共同的属性或者设置的Page编成组的,以方便对这些属性进行管理。目前这样的属性包括localStorage的属性,IndexDBUser ScriptUser StyleSheet等。最常见的同PageGroup相关的操作是维护已访问链接(如addVisitedLink等接口)。根据地瓜的理解,假设WebKit内核之上架设多个应用(浏览器是一个应用),比较可能的是,一个应用独立一个PageGroup。这里同多tab页没有关系,多tab页属于同一个PageGroup。地瓜曾在mailing group上就这个问题咨询过,一位RIM的同学给我举了一个例子,比如一个基于WebKit的邮件程序,一方面他可能调用基于webkitbrowser来显示网页,另外他本身也基于webkit来显示一些邮件,这两个之间的setting有很大可能不一样,他们就使用不同的PageGroup

PageGroup中有这个Group已经安装并且使用的User ScriptUser StyleSheet的集合,一般在网页解析完毕后,这些User ScriptUser StyleSheet会插入到Document中。

PageGroup中还维护了Local StorageIndex DB相关的设置,比如它们的Path,上限等,通过GroupSettings类实现。

PageGroup创建以后,每次创建一个新的Page对象,会通过addPage接口加入到这个PageGroupm_pages中。

每次有导航行为发生的时候,会调用addVisitedLink来将url加入到已访问链接中。如果浏览器要跟踪已访问的接口,则在初始化的时候必须调用PageGroup::setShouldTrackVisitedLinks,且参数为true。此处shouldTrackVisitedLinks是一个静态的全局变量,也就是说,所有应用维护一样的行为(一个应用将其设置为false会影响到其它同样基于此核的应用)?

Page类中维护了PageGroup的指针,并提供了group接口,这是个lazy接口,如果m_group不存在,会调用InitGroup来创建一个。对于Page类来说,如果没有设置GroupName,则在初始化的时候会生成一个空GroupNamePageGroup,由m_singlePageGroup维护,并把指针赋给m_group,如果以非空的名字调用了setGroupName,则会重新创建PageGroup,此时这个PageGroupm_group来维护。

2.2
Setting

WebCore中的设置相关的类,浏览器应用的不少配置、选项同该类相关,Qt移植中,应用在创建Page对象后,会根据Page::settings来实例化QwebSetting

2.3
Chrome

原生窗口接口类,参考地瓜写的”WebKit中的ChromeChromeClient”

2.4
其它

SelectionController :负责管理Page中的选取操作,绝大部分选取操作是基于Frame的,只在FrameSelection为空的时候,对焦点游标的绘制工作才会使用到Page类的SelectionController

SharedGraphicsContext3D:共享3D图形上下文,为了优化2D显示而加入。在加速的2D canvas中,引入的DrawingBuffer的概念,SharedGraphicsContext3D提供了createDrawingBuffer来创建DrawingBuffer

DragController:拖拽控制器。Chrome的超级拖拽功能同这个有关?地瓜会在以后对此进行求证。

FocusController:焦点控制器。考虑到焦点会在各个frame之间切换,所以由Page类维护焦点控制器最合适不过。

ContextMenuController:右键下拉菜单控制器。

InspectorController:Inspector控制器,浏览器中的很多开发工具都同这个类相关。

GeolocationController:定位定位服务控制器。

DeviceMotionController:设备移动控制器

DeviceOrientationController:设备方向控制器

SpeechInputClient:语音输入Client

ProgressTracker:进度跟踪。

BackForwardController:前进后退操作控制。

Frame:一个Page由至少一个主帧和若干个其它子帧构成。

HistoryItem:历史记录。

PluginData:插件相关,未来可能同PluginDatabase类合并。主要是初始化Plugin的信息。

PluginHalter:用来控制Plugin的停止和重新开始。

RenderTheme:这个类提供了控件的渲染和绘制接口。Qt移植中,RenderThemeQtRenderTheme接口的具体实现。

EditorClient:同编辑功能相关,比如拷贝、剪切、删除等操作。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值