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.     默認編碼


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章