Webcore中文本資源編解碼
dlmu2001
本文描述的文本資源編解碼,針對的是字符串編解碼,如 UTF-8,GB2312 ,而非傳輸編解碼(如 gzip )。
關於字符串編碼的理論知識,如果你還不瞭解,可以參考 http://baike.baidu.com/view/1204863.htm 。
我們以一個最簡單的網頁爲例,假設服務器上有一個純鏈接的頁面,沒有任何派生資源( image , css , sound , subframe , javascript 等)。服務器傳送給我們的頁面,他們字符串編碼是各種各樣的,常見的有 utf8 和 gb2312 。如果我們用 utf8 的解碼方式去解 gb2312 的網頁,那麼網頁顯示出來的就是亂碼。所以, webcore 裏面,需要首先找出服務器提供的網頁的字符串編碼格式,然後調用對應的解碼接口進行解碼,輸出 webcore 的其它模塊接受的 unicode 方式的文本( String 類)。
那如何來確定網頁的字符串編碼呢,一般有如下幾種方式
1 )父親節點繼承過來的 charset 屬性,比如 Iframe 裏面的 charset ,如果不指定,則一般繼承自原生頁面(當然,前提是 subframe 和原生頁面的 domain 是一樣的)
2 ) HTTP 響應頭部中包含了 charset 字段
3 )如果有外部的 css ,也可能由外部 css 來指定 charset
4
)
HTML
的
head
元素裏面的
meta
標籤指定了字符串編碼,如
<head><meta http-equiv="Content-Type" content="text/html;charset=gb2312">
5
)如果是
XML
頁面,
XML
頭部中指定了
charset
,如
<?xml version="1.0" encoding="UTF-8"?>
對一個瀏覽器來說,可能還會支持用戶直接指定字符串編碼方式,自動識別。
WebCore 中同字符串解碼處理相關的文件主要是 TextResourceDecoder.h/TextResourceDecoder.cpp ,TextCodec.h/TextCodec.cpp, 以及不同平臺的字符串解碼的 porting (如 TextCodecICU.cpp,TextCodecQt .cpp,TextCodecUTF16.cpp 等),這裏以 TextCodecICU 的 porting 爲例來理解。
WebCore 中通過 DocumentWriter 類維護了一個 TextResourceDecoder 類的指針 m_decoder ,以此來實現對文本資源的解碼功能的調用和控制。
當網絡有數據到來的時候,會調用 DocumentWriter.cpp 的 createDecoderIfNeeded 函數,這裏可以看到一個 TextResourceDecoder 的創建,首先考慮的是設置中是否允許自動識別,其後是 HTTP 響應的 header 中是否有 charset 頭部( m_decoding ),如果此處調用了 TextResourceDecoder 類的 setEncoding 方法設置了編碼方式,則之後就不需要再去檢查 HTML 中的 meta 標籤等。
在創建了 decoder 以後,就可以對數據進行解碼了, DecodedDataDocumentParser 類的 appendBytes 函數調用了 TextResourceDecoder 的 decode 方法,對到來的數據進行解碼,由於數據是分段到了,所以分段解碼。如果數據來齊了,或者中斷了,則調用 TextResourceDecoder 的 flush 函數來結束解碼流程。
TextResourceDecoder 類主要實現兩個功能,一個是 charset 的獲取,包括 meta 中 charset 的獲取, xml 中 charset 的獲取, charset 的自動識別( KanjiCode 類)。另外一個是解碼組件的調用和維護。
解碼組件的維護是通過成員變量 m_codec 來完成的。在開始 decode 的時候,調用 newTextCodec 接口,根據 charset 類型,來創建一個解碼組件,然後調用解碼組件的 decode 方法完成解碼(該方法通過 TextCodec 類進行了封裝,通過 TextCodecICU 等類進行了實現)。解碼完成以後,則將 m_codec 釋放( clear )。需要注意的是,在 TextResourceDecoder 類的 flush 接口中,需要先進行 decode ,才進行 clear ,以免丟失數據。
最後說一下 TextEncodingRegistry.cpp 這個文件,從名字也可以看出來,它用來負責解碼控件的註冊和管理,相當於一個容器,來匹配編碼方式和對應的解碼組件。