浏览器探究——webkit部分——解析HTML(2)解码和HTMLTokenizer的处理
接解析HTML起源篇
起源篇提到数据的处理会调用到如下的两个函数处
DocumentParser::appendBytes
DocumentParser::finish
一个是解析过程中的,一个是解析完成的。而解析开始时,就是起源篇讲的Document,RenderView,DocumentParser的创建,注意当前是html文件,所以创建的是HTMLDocument和HTMLDocumentParser。
测试页面:
<html>
<body>
<p>First name: </p>
<input type="text"name="fname" />
Last name: <input type="text"name="lname" />
</body>
</html>
DocumentParser::appendBytes
首先回顾一下调用到该函数的调用栈
#0 WebCore::DecodedDataDocumentParser::appendBytes
#1WebCore::DocumentWriter::addData
#2WebCore::DocumentLoader::commitData
#3android::FrameLoaderClientAndroid::committedLoad
#4WebCore::DocumentLoader::commitLoad
#5WebCore::DocumentLoader::receivedData
#6WebCore::MainResourceLoader::addData
#7WebCore::ResourceLoader::didReceiveData
#8WebCore::MainResourceLoader::didReceiveData
#9WebCore::ResourceLoader::didReceiveData
#10android::WebUrlLoaderClient::didReceiveData
注意DocumentParser本身并没有实现appendBytes方法,这里调用的是其祖先类DecodedDataDocumentParser的appendBytes。
该函数有参数DocumentWriter,即DocumentWriter调用该函数时把自己作为参数传入了。
首先利用DocumentWriter创建一个TextResourceDecoder,使用函数为DocumentWriter::createDecoderIfNeed。根据名字可见,如果需要才创建,那么什么时候是需要呢?先看下创建的TextResourceDecoder是由谁维护的,在DocumentWriter中有成员RefPtr<TextResourceDecoder> m_decoder;在DocumentWriter构造时并没有创建该TextResourceDecoder的实例,只有在执行DocumentWriter::createDecoderIfNeed时,如果m_decoder为空,则创建一个实例,如果非空,则直接返回。所以这里的IfNeed就指DocumentWriter::m_decoder是否为空了。
解码
TextResourceDecoder
当前第一次执行到这里,所以DocumentWriter::m_decoder为空,需要创建一个TextResourceDecoder,创建时会传入MimeType,TextEncoding等信息。创建的TextResourceDecoder会赋值给DocumentWriter::m_decoder。之后又做了些设置Encoding的操作。
再之后把这个新创建的TextResourceDecoder又设置给了Document(通过Frame找到Document)。看下Document的成员,也有一个RefPtr<TextResourceDecoder> m_decoder;这里把新创建的TextResourceDecoder又赋值给了Document::decoder。最后将创建的TextResourceDecoder返回,完成了DocumentWriter::createDecoderIfNeed。
回到DocumentParser::appendBytes。调用TextResourceDecoder::decode。
TextResourceDecoder::decode
当前是HTML页面,所以这里只看下对HTML的处理情况。
这里先调用了TextResourceDecoder::checkForHeadCharset,该函数是个检查HTML头信息中是否有编码的信息,一般HTML的页面中如果指定了编码信息,那么编码信息会放在<head>标签中。该函数就是做这样的检查的。
该函数中有个重要的操作是把收到的字符串转存到TextResourceDecoder:: m_buffer中。
每次新收到的字符串数据都会追加到这个TextResourceDecoder:: m_buffer中,用于TextResourceDecoder的处理。
之后会创建一个HTMLMetaCharsetParser,并赋值给TextResourceDecoder::m_charsetParser通过HTMLMetaCharsetParser::checkForMetaCharset方法来执行对编码的检测,如果检测到,则把获取到的编码TextEncoding类型设置给TextResourceDecoder。
在TextResourceDecoder中有成员TextEncoding m_encoding;和EncodingSource m_source;分别记录了Encodeing具体的类型和来源。
这个过程的调用栈情况:
#0WebCore::TextResourceD