#############################################
本文为极度寒冰原创,转载请注明出处
#############################################
webkit有一个预下载的功能,主要是对img,script,link,input的标签的内容进行预下载。
我们知道了预下载的下载过程,但是预下载的内容是怎么被读取的呢?
这部分准备用两天的时间进行研究。
读取一个预下载的内容,准备从img标签开始进行研究。原因是img的内容我们比较直观,相比较于script我们也更加的容易理解.
前面的分析可以得到,img的标签主要对应的是HTMLImage方面的内容,在html的目录下找到了这两个文件。HTMLImageLoader与HTMLImageElement
分析还是从我们熟悉的堆栈开始:
WebCore::HTMLDocumentParser::pumpTokenizer -> WebCore::HTMLTreeBuilder::constructTreeFromToken -> WebCore::HTMLTreeBuilder::constructTreeFromAtomicToken -> HTMLTreeBuilder::processToken -> WebCore::HTMLTreeBuilder::processStartTag -> WebCore::HTMLTreeBuilder::processStartTagForInBody
到这个标签为止,还是比较熟悉的. 但是接下来的几个stack,我们还得一个一个去研究.
首先processStartTagForInBody是告诉我们现在已经进入到了body的标签中,而body标签包含了当前的文档的所有内容(包括文本,超链接,图像,表格等等).
然后呢,在body里面的处理,会进行insertSelfClosingHTMLElement的处理。
这个insertSelfClosingHTMLElement一般都会出现在什么地方呢?
我们可以看到主要是出现在下面几个tag的处理中:
可以看到,在当前标签的tag为<area> <br> <embed> <img> <keygen> <wbr> <input> <param> <hr>的时候,我们都会调用到这个方法。
因为我们这边主要讨论的是image的情况,所以在这边也主要研究img的标签。
而insertSelfClosingHTMLElement的具体实现是怎么样的呢?
去除掉无关的注释和ASSERT判断后,我们可以看到这个函数的处理其实很简单。
createHTMLElement我们前面分析过,这个函数的主要作用是通过HTMLElementFactory和依据tagName,一起去创建一个当前的element。
而创建完element之后,element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission)就会进行setAttributeMap的操作。
setAttributeMap函数主要进行的就是Element中设置的相应的属性.
在这个函数中,当期间有属性的添加,修改,删除时都会使用到StyledElement::attributeChanged来进行通知并更新该属性的情况.
这边的话,当前属性如果改变或者解析到需要解析的标签的时候needToParse是置为true的,也就进入了这个判断。
parseMappedAttribute是一个虚函数,也就是在每一个需要实现的Element中都会进行实现。
这边我们跟踪的是一个img的标签,所以理所当然也就进入了一个HTMLImageElement::parseMappedAttribute的函数进行操作。
HTMLImageElement中,我们跟踪的网页是这么写的。
而且在一般的规则中,image的资源文件都是以src来作为标签。
所以我们就进入如下判断进行下一步的处理:
这样就进入了imageLoader的操作中。
到这边为止,我们也就看到了我们需要寻找的updateFromElement()的操作。
这个函数前面的文章已经有过了介绍,这边只是再次复习一下这边perload的操作,
这篇文章的分析就到此结束,大致讲述了一个img文件的加载过程。
当然,加载之后的处理是非常非常复杂的,接下来会继续进行分析。
我们知道了预下载的下载过程,但是预下载的内容是怎么被读取的呢?
这部分准备用两天的时间进行研究。
读取一个预下载的内容,准备从img标签开始进行研究。原因是img的内容我们比较直观,相比较于script我们也更加的容易理解.
前面的分析可以得到,img的标签主要对应的是HTMLImage方面的内容,在html的目录下找到了这两个文件。HTMLImageLoader与HTMLImageElement
分析还是从我们熟悉的堆栈开始:
#0 WebCore::ImageLoader::updateFromElement (this=0x2acef4ec) at external/webkit/Source/WebCore/loader/ImageLoader.cpp:163 #1 0x48d2dc6c in WebCore::HTMLImageElement::parseMappedAttribute (this=0x2acef4b0, attr=0x2ab94720) at external/webkit/Source/WebCore/html/HTMLImageElement.cpp:108 #2 0x48efb706 in WebCore::StyledElement::attributeChanged (this=0x2acef4b0, attr=0x2ab94720, preserveDecls=<value optimized out>) at external/webkit/Source/WebCore/dom/StyledElement.cpp:187 #3 0x48ef0d4a in WebCore::Element::setAttributeMap (this=0x2acef4b0, list=<value optimized out>, scriptingPermission=<value optimized out>) at external/webkit/Source/WebCore/dom/Element.cpp:844 #4 0x48fc5f7a in WebCore::HTMLConstructionSite::createHTMLElement (this=0x2ab4b60c, token=...) at external/webkit/Source/WebCore/html/parser/HTMLConstructionSite.cpp:380 #5 0x48fc6476 in WebCore::HTMLConstructionSite::insertSelfClosingHTMLElement (this=0x2ab4b60c, token=<value optimized out>) at external/webkit/Source/WebCore/html/parser/HTMLConstructionSite.cpp:296 #6 0x48f2f908 in WebCore::HTMLTreeBuilder::processStartTagForInBody (this=0x2ab4b5f8, token=...) at external/webkit/Source/WebCore/html/parser/HTMLTreeBuilder.cpp:929 #7 0x48f30c5a in WebCore::HTMLTreeBuilder::processStartTag (this=0x2ab4b5f8, token=...) at external/webkit/Source/WebCore/html/parser/HTMLTreeBuilder.cpp:1335 #8 0x48f323d4 in WebCore::HTMLTreeBuilder::constructTreeFromAtomicToken (this=0x2ab4b5f8, token=<value optimized out>) at external/webkit/Source/WebCore/html/parser/HTMLTreeBuilder.cpp:461 #9 0x48f3250a in WebCore::HTMLTreeBuilder::constructTreeFromToken (this=0x2ab4b5f8, rawToken=...) at external/webkit/Source/WebCore/html/parser/HTMLTreeBuilder.cpp:451 #10 0x48f26aba in WebCore::HTMLDocumentParser::pumpTokenizer (this=0x2ab94770, mode=WebCore::HTMLDocumentParser::AllowYield) at external/webkit/Source/WebCore/html/parser/HTMLDocumentParser.cpp:276 #11 0x48f26b4e in WebCore::HTMLDocumentParser::resumeParsingAfterYield (this=0x2ab94770) at external/webkit/Source/WebCore/html/parser/HTMLDocumentParser.cpp:192
WebCore::HTMLDocumentParser::pumpTokenizer -> WebCore::HTMLTreeBuilder::constructTreeFromToken -> WebCore::HTMLTreeBuilder::constructTreeFromAtomicToken -> HTMLTreeBuilder::processToken -> WebCore::HTMLTreeBuilder::processStartTag -> WebCore::HTMLTreeBuilder::processStartTagForInBody
到这个标签为止,还是比较熟悉的. 但是接下来的几个stack,我们还得一个一个去研究.
首先processStartTagForInBody是告诉我们现在已经进入到了body的标签中,而body标签包含了当前的文档的所有内容(包括文本,超链接,图像,表格等等).
然后呢,在body里面的处理,会进行insertSelfClosingHTMLElement的处理。
这个insertSelfClosingHTMLElement一般都会出现在什么地方呢?
我们可以看到主要是出现在下面几个tag的处理中:
if (token.name() == areaTag || token.name() == brTag || token.name() == embedTag || token.name() == imgTag || token.name() == keygenTag || token.name() == wbrTag) { m_tree.reconstructTheActiveFormattingElements(); m_tree.insertSelfClosingHTMLElement(token); m_framesetOk = false; return; } if (token.name() == inputTag) { RefPtr<Attribute> typeAttribute = token.getAttributeItem(typeAttr); m_tree.reconstructTheActiveFormattingElements(); m_tree.insertSelfClosingHTMLElement(token); if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden")) m_framesetOk = false; return; } if (token.name() == paramTag || token.name() == sourceTag || token.name() == trackTag) { m_tree.insertSelfClosingHTMLElement(token); return; } if (token.name() == hrTag) { processFakePEndTagIfPInButtonScope(); m_tree.insertSelfClosingHTMLElement(token); m_framesetOk = false; return; }
可以看到,在当前标签的tag为<area> <br> <embed> <img> <keygen> <wbr> <input> <param> <hr>的时候,我们都会调用到这个方法。
因为我们这边主要讨论的是image的情况,所以在这边也主要研究img的标签。
而insertSelfClosingHTMLElement的具体实现是怎么样的呢?
去除掉无关的注释和ASSERT判断后,我们可以看到这个函数的处理其实很简单。
void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken& token) { RefPtr<Element> element = attachToCurrent(createHTMLElement(token)); element->finishParsingChildren(); }
createHTMLElement我们前面分析过,这个函数的主要作用是通过HTMLElementFactory和依据tagName,一起去创建一个当前的element。
而创建完element之后,element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission)就会进行setAttributeMap的操作。
setAttributeMap函数主要进行的就是Element中设置的相应的属性.
在这个函数中,当期间有属性的添加,修改,删除时都会使用到StyledElement::attributeChanged来进行通知并更新该属性的情况.
// parseMappedAttribute() might create a CSSMappedAttributeDeclaration on the attribute. // Normally we would be concerned about reseting the parent of those declarations in StyledElement::didMoveToNewOwnerDocument(). // But currently we always clear its parent and node below when adding it to the decl table. // If that changes for some reason moving between documents will be buggy. // webarchive/adopt-attribute-styled-node-webarchive.html should catch any resulting crashes. if (needToParse) parseMappedAttribute(attr);
这边的话,当前属性如果改变或者解析到需要解析的标签的时候needToParse是置为true的,也就进入了这个判断。
parseMappedAttribute是一个虚函数,也就是在每一个需要实现的Element中都会进行实现。
这边我们跟踪的是一个img的标签,所以理所当然也就进入了一个HTMLImageElement::parseMappedAttribute的函数进行操作。
HTMLImageElement中,我们跟踪的网页是这么写的。
<h1 style="color:red"> Chao </h1> <img class="x" src="chao.jpg"> <p style="color:white">Chao's photo</p>
而且在一般的规则中,image的资源文件都是以src来作为标签。
所以我们就进入如下判断进行下一步的处理:
else if (attrName == srcAttr) m_imageLoader.updateFromElementIgnoringPreviousError();
这样就进入了imageLoader的操作中。
void ImageLoader::updateFromElementIgnoringPreviousError() { // Clear previous error. m_failedLoadURL = AtomicString(); updateFromElement(); }
到这边为止,我们也就看到了我们需要寻找的updateFromElement()的操作。
这个函数前面的文章已经有过了介绍,这边只是再次复习一下这边perload的操作,
void ImageLoader::updateFromElement() { .... //重要:获取 src属性的值 AtomicString attr = client()->sourceElement()->getAttribute(client()->sourceElement()->imageSourceAttributeName()); ... // Do not load any image if the 'src' attribute is missing or if it is // an empty string. CachedResourceHandle<CachedImage> newImage = 0; if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) { //重要:根据url(attr的值),创建一个request,通过该request获取图片 CachedResourceRequest request(ResourceRequest(document()->completeURL(sourceURI(attr)))); request.setInitiator(client()->sourceElement()); ..... if (m_loadManually) { bool autoLoadOtherImages = document()->cachedResourceLoader()->autoLoadImages(); <strong> </strong>document()->cachedResourceLoader()->setAutoLoadImages(false); newImage = new CachedImage(request.resourceRequest()); //创建image对象 newImage->setLoading(true); newImage->setOwningCachedResourceLoader(document()->cachedResourceLoader()); document()->cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage.get()); document()->cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages); } else newImage = document()->cachedResourceLoader()->requestImage(request); //直接获取一个cached的image对象 .... }
这篇文章的分析就到此结束,大致讲述了一个img文件的加载过程。
当然,加载之后的处理是非常非常复杂的,接下来会继续进行分析。