转载出处:http://blog.csdn.net/awebkit
网页是如何正确显示出来而不会乱码的呢?本文就这个问题讨论一下
当我们调用loadURL之后,经过一系列的check,终于,我们到了MainResourceLoader,开始load->loadNow,在这里,我们发送了网络请求。
下面这段大致讲了网络部分的结构,熟悉这部分的可以直接忽略。
ResourceHandleManager作为网络部分的管理者,需要听命ResourceHandle这个决策者,而ResourceHandle有个秘书代为实现一切,这个秘书就是ResourceHandleInternal。
我们发送网络请求,就是把请求告诉ResourceHanlde,ResourceHandle调用ResourceHandle::create,往ResourceHandleManager里面添加一个job(ResourceHanlde)。ResourceHandleManager由timer驱动下载任务,下载完成后通知ResourceHandle,但是,ResourceHandle的工作太重了,就把这部分工作给了ResourceHandleClient。ResourceHandleClient就是负责下载的资源管理的。
ResouceHandleClient只是个接口,实现部分又有ResourceLoader来承接公共部分,ResourceLoader的子类MainResourceLoader和SubResourceLoader来承担具体的任务。
说了这么多废话,如果前面你都懂,下面开始正题了
网络把资源给了MainResourceLoader之后(didReceiveData),然后通知DocumentLoader(documentLoader()->receivedData),触发commitLoad,调用FrameLoaderClient的commitLoad( frameLoader->client()->committedLoad)
一般的FrameLoaderClient中的committedLoad如下流程
- void FrameLoaderClient::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)
- {
- if (!m_pluginView) {
- ASSERT(loader->frame());
- loader->commitData(data, length);
- Frame* coreFrame = loader->frame();
- if (coreFrame && coreFrame->document()->isMediaDocument())
- loader->cancelMainResourceLoad(coreFrame->loader()->client()->pluginWillHandleLoadError(loader->response()));
- }
- ...
- }
调用到DocumentLoader的commitData方法里面,在这里,就涉及到了编码选择问题,请看代码
- void DocumentLoader::commitData(const char* bytes, int length)
- {
-
- bool userChosen = true;
- String encoding = overrideEncoding();
- if (encoding.isNull()) {
- userChosen = false;
- encoding = response().textEncodingName();
- }
- m_writer.setEncoding(encoding, userChosen);
- ASSERT(m_frame->document()->parsing());
- m_writer.addData(bytes, length);
- }
我没有看到overrideEncoding在这里有什么用,所以,这时候,使用的是HTTP Response的TextEncodingName。然后,就告诉DocumentWriter接收数据。
DocumentWriter的addData会把任务分配给DocumentParser来解析。对于dom来说,这项任务又落在了DocumentParser的子类DecodedDataDocumentParser的身上。
我们来看看DecodedDataDocumentParser的appendBytes函数,如下
- void DecodedDataDocumentParser::appendBytes(DocumentWriter* writer , const char* data, int length, bool shouldFlush)
- {
- if (!length && !shouldFlush)
- return;
- TextResourceDecoder* decoder = writer->createDecoderIfNeeded();
- String decoded = decoder->decode(data, length);
- if (shouldFlush)
- decoded += decoder->flush();
- if (decoded.isEmpty())
- return;
- writer->reportDataReceived();
- append(decoded);
- }
在这里,我们终于看到了decode函数。稍等,我们看看decoder是如何创建出来的。
- TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
- {
- ...
- if (Settings* settings = m_frame->settings()) {
- m_decoder = TextResourceDecoder::create(m_mimeType,
- settings->defaultTextEncodingName(),
- settings->usesEncodingDetector());
- Frame* parentFrame = m_frame->tree()->parent();
- if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setHintEncoding(parentFrame->document()->decoder());
- } else
- m_decoder = TextResourceDecoder::create(m_mimeType, String());
- Frame* parentFrame = m_frame->tree()->parent();
- if (m_encoding.isEmpty()) {
- if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
- } else {
- m_decoder->setEncoding(m_encoding,
- m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
- }
- m_frame->document()->setDecoder(m_decoder.get());
这里,我们看到如果用户选择了编码,就按照用户的编码,如果没有选择,就使用HTTP header的编码。
再回到appendBytes中,最后调用append,把解码后的数据给了谁呢?给了HTMLDocumentParser,然后就是开始分析tag等。