文章引用地址:http://blog.csdn.net/dlmu2001/article/details/5929820
本文描述的文本资源编解码,针对的是字符串编解码,如UTF-8,GB2312,而非传输编解码(如gzip)。
关于字符串编码的理论知识,如果你还不了解,可以参考http://baike.baidu.com/view/1204863.htm。
我们以一个最简单的网页为例,假设服务器上有一个纯链接的页面,没有任何派生资源(image,css,sound,subframe,javascript等)。服务器传送给我们的页面,他们字符串编码是各种各样的,常见的有utf8和gb2312。如果我们用utf8的解码方式去解gb2312的网页,那么网页显示出来的就是乱码。所以,webcore里面,需要首先找出服务器提供的网页的字符串编码格式,然后调用对应的解码接口进行解码,输出webcore的其它模块接受的unicode方式的文本(String类)。
那如何来确定网页的字符串编码呢,一般有如下几种方式
- 父亲节点继承过来的charset属性,比如Iframe里面的charset,如果不指定,则一般继承自原生页面(当然,前提是subframe和原生页面的domain是一样的)
- HTTP响应头部中包含了charset字段
- 如果有外部的css,也可能由外部css来指定charset
- HTML的head元素里面的meta标签指定了字符串编码,如<head><meta http-equiv="Content-Type" content="text/html;charset=gb2312">
- 如果是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这个文件,从名字也可以看出来,它用来负责解码控件的注册和管理,相当于一个容器,来匹配编码方式和对应的解码组件。