http://blog.sina.com.cn/s/blog_71b5e2520100s1cr.html
Webkit文本资源编码选择
目录
1 默认编码....................................................................................2
1.1 HTML/XML文件..............................................................................3
1.2 CSS文件...................................................................................3
1.3 JS文件....................................................................................3
1.4 小结......................................................................................4
2 HTTP响应头..................................................................................4
2.1 请求HTML/XML页面..........................................................................4
2.2 请求CSS文件...............................................................................5
2.3 请求JS文件................................................................................5
2.4 小结......................................................................................5
3 页内编码....................................................................................5
3.1 检测BOM...................................................................................6
3.2 检测CSS编码...............................................................................6
3.3 检测头部编码..............................................................................6
3.4 编码检测器................................................................................7
3.5 小结...................... ......... ......... ..........................................7
4 总结........................................................................................8
本文描述了Webkit文本资源解码时,编码格式的选择问题。这里的文本资源是指HTML/XML、CSS,以及JS文件等。如果没有明确说明,本文提到的“文本解码器”均特指TextResourceDecoder类。
文本资源解码器由TextResourceDecoder类表示。该类主要是对文本资源进行编码检测,以确定最终的编码格式;而进行实际的文本解码是m_codec成员,其类型为TextCodec的。下面是该类的主要属性字段:
ContentType m_contentType;
TextEncoding m_encoding;
OwnPtr<TextCodec> m_codec;
EncodingSource m_source;
const char* m_hintEncoding;
bool m_usesEncodingDetector;
TextResourceDecoder决定编码格式时,其来源由EncodingSource表示:
下面分别介绍这些类型。
1 默认编码
创建TextResourceDecoder对象时,其构造函数需要三个参数,分别为文本资源的MIME类型,指定的编码格式,以及是否使用编码检测器。该构造函数根据文本的MIME类型和指定的编码格式设置一个默认的编码(参考:函数defaultEncoding),编码来源设置为DefaultEncoding。默认的编码的选择规则如下:
1.
2.
3.
下面详细介绍三种文文本类型的文件创建文本解码器时,传入的默认编码参数。
1.1 HTML/XML文件
从网络接收到数据后(参考:DecodedDataDocumentParse
创建TextResourceDecoder对象时,构造函数的参数设置如下:
1.
2.
此外,如果Settings对象不为空,那么设置该对象的线索编码(m_hintEncoding)为其父Frame的编码格式。(前提是,当前Frame与其父Frame具有相同的security origin)
1.2 CSS文件
解析HTML页面过程中,请求CSS外部资源时(HTMLLinkElement::process()),会传入编码参数,以便CachedCSSStyleSheet对象创建文本解码器。传入文本解码器构造函数的参数设置如下:
1.
2.
3.
1.3 JS文件
与CSS文件类似,请求JS资源时(ScriptElementData::requestScript),生成CachedScript对象,便会创建文本解码器。传入的文本解码器的参数设置如下:
1.
2.
3.
1.4 小结
创建文本资源解码器时,「默认编码」的设置:
1.
2.
3.
4.
PS:文档所在Frame的编码格式获取如下:
String DocumentWriter::encoding() const
{
}
2 HTTP响应头
HTTP响应头以Content-Type来指定所请求资源的MIME类型和编码格式,例如:Content-Type:text/html;charset=gb2312
。通常,
HTTP响应头指定的编码格式的优先级高于页面内指定的编码格式,低于用户选择的编码格式。因为网关可能会对页面进行重新编码,并将编码格式以响应头返回。但是,HTTP响应头并不总是会返回编码格式。
2.1 请求HTML/XML页面
PS: 接收到页面文档数据后函数receivedData先于createDecoderIfNeeded被调用!
在DocumentWriter::createDecoderIfNeeded()中:
1.
2.
3.
2.2 请求CSS文件
当网络层接收到响应头后,如果响应头返回了编码格式,那么调用CSS缓存对象的setEncoding函数替换默认的编码格式,设置EncodingFromHTTPHeader作为编码来源(具体参见:CachedCSSStyleSheet::setEncoding)。
2.3 请求JS文件
与CSS类似,调用JS缓存对象(CachedScript)的setEncoding函数替换默认的编码格式,设置编码来源为EncodingFromHTTPHeader。
2.4 小结
当接收到HTTP响应头后:
1.
2.
3 页内编码
这里的页内编码是指,文本资源文件中指定的编码格式,比如,XML 声明中encoding属性、HTML文件的meta标签指定的编码,以及CSS的@charset等。此外,JS文件只会检测BOM(Byte Order Mark)头部。
在调用文本解码器对数据解码时(TextResourceDecoder::decode),会对页内编码进行检测。
3.1 检测BOM
TextResourceDecoder::checkForBOM函数在资源文件的开头检测是否有UTF-16/32或者UTF-8的BOM标记。如果检测到BOM标记存在,那么更改当前的编码格式,并设置编码来源为AutoDetectedEncoding。在Webkit中BOM的优先级比用户选择的编码格式高。
3.2 检测CSS编码
如果文本资源文件是CSS,并且当前解码器的编码来源是DefaultEncoding或者是EncodingFromParentFrame(也就是说,如果检测到BOM的存在,便不会再进行CSS字符集的查找),那么将会对CSS文件进行页内编码检测,其实现逻辑在TextResourceDecoder::checkForCSSCharset函数中。如果检测到CSS文件中指定了某种编码格式,那么更改当前解码器的编码格式,并且设置编码来源为EncodingFromCSSCharset。
3.3 检测头部编码
如果文本资源文件是HTML或者XML,并且当前解码器的编码来源是DefaultEncoding或者是EncodingFromParentFrame(也就是说,如果检测到BOM的存在,便不会再进行头部编码检测),那么将会对该文件进行页内头部编码检测,其实现逻辑在TextResourceDecoder::checkForHeadCharset函数中。其处理逻辑如下:
1.
a)
b)
2.
a)
b)
PS:检测文本前1024字节,直到遇到head中不被允许的标签为止,而不是遇到head的结束标签就停止(在head中允许嵌套的标签有如下几个:SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE)。此外,忽略<title>,<script> 和<noscript>这样的标签。
3.4 编码检测器
使用编码检测器必须同时满足下面条件(shouldAutoDetect()):
1.
2.
PS:shouldAutoDetect()函数的注释如下:
//
//
//
//
//
//
//
//
//
如果shouldAutoDetect()条件满足:
1.
a)
2.
3.5 小结
对于页内编码检测:
1.
2.
a)
b)
3.
a)
b)
4 总结
Webkit编码选择优先级如下:
1.
2.
3.
4.
5.
6.
7.