Webkit文本资源编码选择

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       //文本资源类型:PlainText, HTML, XML, CSS
TextEncoding m_encoding           //规范化后的编码格式,如UTF8
OwnPtr<TextCodec> m_codec      //文本解码器,进行实际的文本编解码
EncodingSource m_source            //编码格式来源
const char* m_hintEncoding          //线索编码,用于自动检测
bool m_usesEncodingDetector        //是否使用编码检测器

TextResourceDecoder决定编码格式时,其来源由EncodingSource表示:

   enum EncodingSource {
       DefaultEncoding,                     //默认编码
       AutoDetectedEncoding,             //自动检测编码
       EncodingFromXMLHeader,       //来自于XML头部
       EncodingFromMetaTag,             //来自于Meta标签
       EncodingFromCSSCharset,        //来自于CSS的@charset
       EncodingFromHTTPHeader,       //来自于HTTP响应头
       UserChosenEncoding,               //用户选择编码
       EncodingFromParentFrame        //来自于父Frame
   };

下面分别介绍这些类型。

1  默认编码

创建TextResourceDecoder对象时,其构造函数需要三个参数,分别为文本资源的MIME类型,指定的编码格式,以及是否使用编码检测器。该构造函数根据文本的MIME类型和指定的编码格式设置一个默认的编码(参考:函数defaultEncoding),编码来源设置为DefaultEncoding。默认的编码的选择规则如下:

1.     如果文本资源类型为XML,那么设置默认编码为UTF8

2.     如果传入的编码名规范化后无效,那么设置默认编码为Latin1

3.     将传入的编码作为默认编码

 

下面详细介绍三种文文本类型的文件创建文本解码器时,传入的默认编码参数。

1.1  HTML/XML文件

从网络接收到数据后(参考:DecodedDataDocumentParser::appendBytes),调用函数DocumentWriter::createDecoderIfNeeded()创建文本解码器。

创建TextResourceDecoder对象时,构造函数的参数设置如下:

1.     从HTTP响应头获取MIME类型参数

2.     如果Settings对象不为空,那么从Settings中获取默认的文本编码,以及是否使用编码检测器参数;否则编码名设置为空,是否使用编码检测器的参数使用默认参数(false);

此外,如果Settings对象不为空,那么设置该对象的线索编码(m_hintEncoding)为其父Frame的编码格式。(前提是,当前Frame与其父Frame具有相同的security origin)

1.2  CSS文件

解析HTML页面过程中,请求CSS外部资源时(HTMLLinkElement::process()),会传入编码参数,以便CachedCSSStyleSheet对象创建文本解码器。传入文本解码器构造函数的参数设置如下:

1.     MIME类型参数为:"text/css"

2.     如果link标签的Charset属性不为空,那么传入构造函数的编码名为该属性值;否则传入该文档所在Frame的编码格式(DocumentWriter::encoding

3.     是否使用编码检测器:使用默认参数(false)

1.3  JS文件

与CSS文件类似,请求JS资源时(ScriptElementData::requestScript),生成CachedScript对象,便会创建文本解码器。传入的文本解码器的参数设置如下:

1.     MIME类型参数为:"application/javascript"

2.     如果Script标签的Charset属性不为空,那么传入构造函数的编码名为该属性值;否则传入该文档所在Frame的编码格式(DocumentWriter::encoding

3.     是否使用编码检测器:使用默认参数(false)

1.4  小结

创建文本资源解码器时,「默认编码」的设置:

1.     HTML/XML:如果是XML,那么默认编码为UTF8;否则,优先考虑Settings中设置的默认编码,如某些浏览器中设置的GBK

2.     CSS/JS:优先考虑所在标签指定的编码,其次是文档所在Frame的编码格式

3.     在传入编码规范化后无效的情况下,设置默认编码为Latin1

4.     编码来源为:DefaultEncoding

PS:文档所在Frame的编码格式获取如下:

 

String DocumentWriter::encoding() const

{

   if (m_encodingWasChosenByUser &&!m_encoding.isEmpty())

       return m_encoding;

   if (m_decoder &&m_decoder->encoding().isValid())

       return m_decoder->encoding().name();

   Settings* settings = m_frame->settings();

   return settings ?settings->defaultTextEncodingName() :String();

}

2  HTTP响应头

HTTP响应头以Content-Type来指定所请求资源的MIME类型和编码格式,例如:Content-Type:text/html;charset=gb2312。通常,HTTP响应头指定的编码格式的优先级高于页面内指定的编码格式,低于用户选择的编码格式。因为网关可能会对页面进行重新编码,并将编码格式以响应头返回。但是,HTTP响应头并不总是会返回编码格式。

2.1  请求HTML/XML页面

  当Webkit接收到页面数据后,会调用DocumentWriter的setEncoding函数进行编码格式设置(参考:FrameLoaderClientUC::receivedData),该设置包括编码名(m_encoding)和是否是用户显示指定编码格式(m_encodingWasChosenByUser)。其中,用户显示指定的编码格式的优先级高于HTTP响应头的编码格式。

PS: 接收到页面文档数据后函数receivedData先于createDecoderIfNeeded被调用!

在DocumentWriter::createDecoderIfNeeded()中:

1.     如果m_encoding为空,即用户没有显示指定编码格式,并且HTTP响应头也没有返回编码格式,那么将当前的文本解码器设置为父Frame的实际解码格式(具体代码为:parentFrame->document()->inputEncoding()),同时设置编码来源为EncodingFromParentFrame;

2.     否则,将m_encoding值设置为当前文本解码器的编码格式;同时,如果参数m_encodingWasChosenByUser为真,那么设置编码来源为UserChosenEncoding,否则设置为EncodingFromHTTPHeader;

3.     此外,将当前的文本解码器设置为对应Document的解码器

2.2  请求CSS文件

当网络层接收到响应头后,如果响应头返回了编码格式,那么调用CSS缓存对象的setEncoding函数替换默认的编码格式,设置EncodingFromHTTPHeader作为编码来源(具体参见:CachedCSSStyleSheet::setEncoding)。

2.3  请求JS文件

与CSS类似,调用JS缓存对象(CachedScript)的setEncoding函数替换默认的编码格式,设置编码来源为EncodingFromHTTPHeader。

2.4  小结

当接收到HTTP响应头后:

1.     CSS/JS:HTTP响应头返回编码的优先级比默认编码高

2.     HTML /XML:用户显示指定的编码格式高于HTTP响应头返回的编码格式,父Frame编码格式的优先级最低

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。WebkitBOM的优先级比用户选择的编码格式高

3.2  检测CSS编码                                                  

如果文本资源文件是CSS,并且当前解码器的编码来源是DefaultEncoding或者是EncodingFromParentFrame(也就是说,如果检测到BOM的存在,便不会再进行CSS字符集的查找),那么将会对CSS文件进行页内编码检测,其实现逻辑在TextResourceDecoder::checkForCSSCharset函数中。如果检测到CSS文件中指定了某种编码格式,那么更改当前解码器的编码格式,并且设置编码来源为EncodingFromCSSCharset。

3.3  检测头部编码

如果文本资源文件是HTML或者XML,并且当前解码器的编码来源是DefaultEncoding或者是EncodingFromParentFrame(也就是说,如果检测到BOM的存在,便不会再进行头部编码检测),那么将会对该文件进行页内头部编码检测,其实现逻辑在TextResourceDecoder::checkForHeadCharset函数中。其处理逻辑如下:

1.     文件开头是XML的声明

a)       如果是XML声明,并且包含有encoding属性,那么更改当前解码器的编码格式,并且设置编码来源为EncodingFromXMLHeader

b)      根据字符串“<?xml”占用的字节和顺序,确定编码为UTF16/UTF32的大端/小端编码

2.     否则,检测meta标签中的charset字符串

a)       如果是XML文件,则返回(Webkit中注释:在XHTML中http-equiv无效)

b)      如果包含有meta标签,并且指定由某种编码格式,那么那么更改当前解码器的编码格式,并且设置编码来源为EncodingFromMetaTag

PS:检测文本前1024字节,直到遇到head中不被允许的标签为止,而不是遇到head的结束标签就停止(head中允许嵌套的标签有如下几个:SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE)。此外,忽略<title>,<script> 和<noscript>这样的标签。

3.4  编码检测器

使用编码检测器必须同时满足下面条件(shouldAutoDetect()):

1.     m_usesEncodingDetector为真;对于HTML/XML文件,该条件是否为真,取决于settings是否设置为真;而对于CSS/JS,该条件总是为假

2.     编码来源为DefaultEncoding,或者编码来源为EncodingFromParentFrame且线索编码不为空

PS:shouldAutoDetect()函数的注释如下:

//   We use the encoding detector in two cases:

//   1.Encoding detector is turned ON and no other encoding sourceis

//     available (that is, it's DefaultEncoding).

//   2.Encoding detector is turned ON and the encoding is setto

//     the encoding of the parent frame, which is alsoauto-detected.

//   Notethat condition #2 is NOT satisfied unless parent-childframe

//  relationship is compliant to the same-origin policy. If they'refrom

//  different domains, |m_source| would not be set toEncodingFromParentFrame

//   inthe first place.

如果shouldAutoDetect()条件满足:

1.     当前解码器的编码为日文

a)       调用detectJapaneseEncoding函数检查是否需要设置具体的日文编码,并设置编码来源为AutoDetectedEncoding

2.     否则,调用detectTextEncoding函数,并将线索编码作为参数传入;该函数以统计学的方法检测给定文本可能的编码格式。

3.5  小结

对于页内编码检测:

1.     文件的BOM标记总是会被检测,优先级最高

2.     CSS/HTML/XML的页内编码是在一定条件下才会被检测,条件是:

a)       编码来源为DefaultEncoding

b)      或者,编码来源为EncodingFromParentFrame

3.     CSS/JS默认不允许使用编码检测器,HTML/XML在一定条件下允许使用

a)       Settings被设置为允许使用编码检测器

b)      编码来源为DefaultEncoding,或者编码来源为EncodingFromParentFrame且线索编码不为空

4  总结

Webkit编码选择优先级如下:

1.     BOM标记

2.     用户选择编码

3.     HTTP响应头返回编码

4.     页面内编码

5.     编码检测器

6.     父Frmae的编码

7.     默认编码


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REaDME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、资源1项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值