Gecko处理HTML HTTP请求流程
(2) Document Loader调用NS_OpenURI传递请求文件,Necko(一个网络lib)检查url策略(这里就是http:)后寻找对应的nsIProtocolHandler(这里是nsHTTPHandler),然后向它申请一个nsIChannel(即nsHTTPChannel)。channel表示到server的一个连接,可以理解为是一条html数据流。
(3) webserver发来数据,nsIChannel调用DocumenLoader的OnStartRequest,因为此时channel已经知道了数据中的content type,DocumentLoader可以根据content type找对应的nsIDocumentLoaderFactory(nsLayoutDLF)处理"text/html"。然后Factory创建ContentViewer并发出创建nsIContentViewer的通知。多数情况下还要创建一个nsIDocument(nsHTMLDocument)绑定到ContentViewer。之后ContentViewer会嵌入到ContentViewerContainer当中。
(4) Document使用nsIParser解析输入数据流,HTML文档就是nsParser,本身已经实现了nsIStreamListener。nsIStreamListener返回到DocumentLoader并与nsIChannel的请求连接。
(5) Document(nsHTMLDocument)还创建了nsIContentSink(nsHTMLContentSink),连接parser和document,parser使用StreamListener解析数据流,转化成ContentSink中的nsIParserNodes。parser以8kb为单位从数据流读取数据,逐块解析并将解析出的nsIParserNodes传给ContentSink,如果parser发生阻塞,期间还会继续解析缓存数据。
(6) contentsink通过调用NS_NewHTMLXxxxElement()创建nsIContent节点描述document。各元素节点已包含了nsIHTMLContent接口和DOM接口。nsIContent::AppendChild()可以创建content tree,接收的参数aNotify通知document是否content model变化。content sink调用AppendChild时该参数始终为PR_FALSE。nsHTMLContentSink::WillInterrupt()和nsHTMLContentSink::DidBuildModel()执行时,content sink会调用NotifyBody()通知document关于content model的变化。parser处理每个8kb数据块都要执行WillInterrup。
(7) 因为presentation shell (nsPresShell) 已经在nsIDocument注册为一个DocumentObserver,所以Document/Content tree变化的时候也会收到通知,这样就可以通过nsCSSFrameConstructor创建和更新nsIFrame,参考用户agent样式单(ua.css)为每个content节点创建frames,当然除了那些displaytype是"none"的节点。一个content节点对应一个或多个nsIFrame,如果有几个frames都是由一个content node创建,第一个就称为"primary"节点,后面的那些frames可以用nsIFrame的GetNextInFlow()方法进行查找。nsHTMLContentSink::OpenBody()通过调用nsHTMLContentSink::StartLayout()完成首个流程 。
(8) 每个nsIFrame都包含了屏幕呈现的方法,PresShell调用nsIFrame::Paint()布局frames,通过传递presentation context和rendering context的引用进行绘制。rendering context是一个native类(nsGtkRenderingContext on unix),包含了绘制的方法。
出处
https://developer.mozilla.org/en-US/docs/The_life_of_an_HTML_HTTP_request