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 这个文件,从名字也可以看出来,它用来负责解码控件的注册和管理,相当于一个容器,来匹配编码方式和对应的解码组件。