<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1021548603024561100</id><updated>2011-11-28T07:29:21.983+08:00</updated><category term='Gears'/><category term='安全'/><category term='移植'/><category term='Plugin'/><category term='生活随想'/><category term='插件'/><category term='SpiderMonkey'/><category term='CSS'/><category term='嵌入'/><category term='Javascript'/><category term='Add-on'/><category term='WebCore'/><category term='投资'/><category term='SVG'/><category term='布局'/><category term='Extension'/><category term='XUL'/><category term='XML'/><category term='Build'/><category term='WebKit'/><category term='线程'/><category term='Google'/><category term='外挂'/><category term='Port'/><category term='Mozilla相关'/><category term='SquirrelFish'/><category term='APR'/><category term='Xpconnect'/><category term='DOM'/><category term='View'/><category term='Render'/><category term='Graphics'/><category term='Chrome'/><category term='编译'/><category term='Http'/><category term='W3C标准'/><category term='HTML'/><category term='JavascriptCore'/><category term='NSPR'/><category term='Frame'/><category term='Xulrunner'/><category term='Parser'/><category term='XHTML'/><category term='V8'/><category term='调试'/><category term='扩展'/><category term='Embedding'/><category term='Gecko'/><title type='text'>Suk's Blog-Our Power,Our Gift,Our Heaven</title><subtitle type='html'>对本Blog原创的内容，请转载时保持本Blog连接。。。</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-3861620289886434619</id><published>2009-03-25T20:36:00.009+08:00</published><updated>2009-03-26T11:37:24.679+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活随想'/><category scheme='http://www.blogger.com/atom/ns#' term='投资'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><category scheme='http://www.blogger.com/atom/ns#' term='插件'/><title type='text'>浏览器大战正当时</title><content type='html'>最近关于浏览器的新闻真可谓满天飞，这不IE8终于面世啦；Chrome1.0正式版也早已推出，Chrome社区正忙乎2.0及linux版本呢；Safari可也没闲着，才不久也来了个Safari4.0beta版，引得大众一番轰动；Firefox可也不断的忙乎着升级，从3.0一步一步升到3.0.7哪，以目前的势头可没暂停终止的迹象。。。&lt;br /&gt;&lt;br /&gt;再说啦国内上网本可炒得不一乐乎，从供应商到硬件平台，甚至到用户的使用等等，可惜真正走到用户手中，或许还得要有些日子，其中一直让人好奇的是上网本究竟使用哪款浏览器内核，对用户而言仅仅上上网浏览浏览新闻、逛逛论坛、看看视频、参加参加网上社区就够了吗？有这样便宜的硬件平台及好用的浏览器吗？&lt;br /&gt;&lt;br /&gt;如此林林总总让人目不暇接，于是在沉寂了一段时间之后，想借此机会总结总结自己的一些使用体会及对浏览器今后发展的一些看法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、各款浏览器大比拼&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;IE8&lt;/li&gt;&lt;/ul&gt;     从IE8正式版本推出后的第一时间，就下载试用过它，经过一段时间的对比测试，第一时间使用的感受如下：&lt;br /&gt;    在浏览器大混战中IE8正奋力追赶，几乎没有独创或值得大说特说的新特性，几乎就是在模仿或抄袭其他浏览器受人欢迎的特性如多页签、多进程、web开发人员工具等；&lt;br /&gt;&lt;br /&gt;IE8虽然在很多方面有所改进但仍然是IE系列浏览器，关键方面没有质的飞跃，好的方面有持续支持已有的框架、风格、设置、扩展等，令人诟病以久的W3C标准支持及推动仍举步艰难，这不ACID3测试还是保持在30分左右的水平呢？&lt;br /&gt;&lt;br /&gt;经过一些测试发现其加载页面速度及占用资源方面，与Chrome相比仍然有一定的差距，总体而言Chrome要想超越IE系列浏览器关键要在扩展方式及应用方面向IE、Firefox学习，当然还要有用户推广方面更大的努力；&lt;br /&gt;&lt;br /&gt;IE8虽然看起来步伐不是很快，但在其拥有庞大的用户基础之上进行稳步推进是非常值得肯定的，特别是它保持了对原有扩展的支持的基础之上，实现了多进程及安全方面的加强。从目前看来要想IE浏览器使用WebKit内核简直就是痴人说梦，忽悠忽悠而已，因为微软仍然对Web采取封闭而非开放合作的态度。。。&lt;br /&gt;&lt;ul style="font-weight: bold;"&gt;&lt;li&gt;Chrome&lt;/li&gt;&lt;/ul&gt;Chrome浏览器自去年九月份推出以来就属当红炸鸡啦，赚足了眼球，当然Google及Chrome社区其实正不余遗力地加强Chrome浏览器的功能及满足用户的潜在需求及对广大网民的承诺，正与其一位开发人员所讲由于目前的浏览器太差，从而有想要开发浏览器的驱动力；&lt;br /&gt;&lt;br /&gt;到目前为止其稳定性相比测试版本有了较大的提升，加载速度方面也算佼佼者啦，唯一的缺憾在于其扩展的支持，从其实现架构及WebKit内核来讲要达到类似IE ActiveX或Firefox Extension那样的方便也许难度不小；&lt;br /&gt;&lt;br /&gt;令人值得称道的是其linux gtk版本或许不久就能面试啦，对linux用户来讲是一大福音；&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Safari&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Safari4.0beta版的发布有点出乎人们的意料，Apple在其网站&lt;a href="http://www.apple.com.cn/safari/whats-new.html"&gt;Safari全新特色&lt;/a&gt;上对其特性进行过一番"吹嘘"，通过仔细阅读其内容，发现Apple也似乎正努力的打造一款极具个性的Safari浏览器，其中从Chrome中学了不少东东如页签的位置、TopSite等，当然其中令人有趣的页签拖动还是独特的，还有类似的界面及操作风格延续了Apple的优良传统；&lt;br /&gt;&lt;br /&gt;虽然其JavascriptCore内核没变，但起了个商业上的名称nitro，一时真让人莫名其妙，也许只要Apple自己知道改名的真正原因；&lt;br /&gt;&lt;br /&gt;虽然其ACID3测试的得分在90分以上(Chrome80-90，Firefox70多一点)，但其在Windows上的资源使用情况就没有宣称的那么好啦，特别是拥有Adobe flash的页面上；其架构上仍然没有使用多进程，与Firefox一样，但其消耗内存及CPU可比Firefox高的多，并且还不稳定，也许是Beta版的原因吧，看样其要想在Windows上分一杯羹难度不少；&lt;br /&gt;&lt;br /&gt;那么Apple为什么还要"折腾"Safari哪？我想或许其算盘在Mac及iPhone上呢？Apple也许还担心哪天Chrome杀到Mac平台呢？要是现在不紧跟浏览器的发展，到那时Chrome壮大啦，自己又没有守住自己的领地哪滋味可就真不好受，再说Chrome使用的WebKit内核可是由Apple主导开发的呢？改个Javascript引擎的名字为Nitro，或许相比JavascriptCore、SFX起来，更好听，更像V8那样容易让人记住；&lt;br /&gt;&lt;br /&gt;WebKit的发展来源于Apple，当然也离不开Apple，其对W3C标准的支持及扩展付出了极大的努力，这一点让人钦佩，特别是其对ACID3测试所作的努力及Javascript引擎实现方式的突破；&lt;br /&gt;&lt;br /&gt;在这场浏览器大战中，没有Apple，没有WebKit，也就没有了大战的平台，虽然目前结果未知，但WebKit内核本身非常值得关注，也许WebKit内核的发展是大战成败的关键，有了Google、Apple、Adobe等的参与与使用，WebKit内核的市场份额经过大战之后肯定会得到大量的提升，其发展同样令人瞩目；&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Firefox&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Mozilla自从推出Firefox1.5，就逐步的从上一次失败的阴影中走出来，到了2008年推出Firefox3.0开始使用Gecko1.9，才让人真正的感觉到凤凰涅磐的滋味，那些家伙，狂热的技术追逐者，令世人刮目相看，其架构、其扩展性、其开放性、其开拓性，成为推动Web技术发展与应用的根本；&lt;br /&gt;&lt;br /&gt;正可谓Firefox是这场浏览器大战的导火索，由一群对技术孜孜不倦的家伙发起对Web发展及应用的号角；这不其倡导的多页签、xul、xbl、npapi、cavas等，在Firefox上得到充分的应用与展现，有些方面IE、WebKit还在苦苦的追逐呢；网上有人评论Firefox离开了Google财务的支持，也许即将面临死亡，听起来有些骇然，从商业角度讲或许他是对的，但Mozilla社区对Web技术的开拓创新等却不会那么轻易的死掉，只要他们坚持这条道同时考虑考虑用户感受，先锋不会再次成为先烈，饿死的或许只会是那不思进取，抱残守缺的家伙。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、浏览器发展方向&lt;/span&gt;&lt;br /&gt;浏览器的发展推动Web的发展与应用，同时Web的发展与应用促使浏览器更加的强壮，浏览器的发展离不开Web的发展，目前看来其发展方向应该在于：&lt;br /&gt;&lt;ul style="font-weight: bold;"&gt;&lt;li&gt;更加的标准化&lt;/li&gt;&lt;/ul&gt;也许IE被逼着卷入这场浏览器大战，不如说被逼着卷入标准化大战，Firefox、Chrome、Safari、Opera都自觉不自觉的坚持w3c标准，并且还不断的推动标准的发展，从目前的态势看Microsoft不得不应战，虽然极不情愿，也许大势所趋吧，识时务者为俊杰；&lt;br /&gt;&lt;br /&gt;Firefox、WebKit正不遗余力的推动html5 video等标签、增加工作线程、跨域名XmlHttpRequest等，或许未来的标准就此产生；&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;更加的开放&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;上面提及的几个浏览器大部分搭乘开源的顺风，实施开源，公开透明，行自由开放之风，这样Web的发展及应用或许更加的开放；&lt;br /&gt;&lt;br /&gt;&lt;ul style="font-weight: bold;"&gt;&lt;li&gt;更加的复杂&lt;/li&gt;&lt;/ul&gt;由于Web应用更加的复杂及多样性，对浏览器的要求及本地系统、硬件的要求越来越高，所以多进程的出现，从另一个侧面体现其复杂性及可靠性要求的提高。试想一个程序，它可使用来自世界各地形式各异的Web数据，同时尽可能的按照同样的方式展现给不同的用户，虽然有公共遵守的W3C标准，但要求其高效、可靠的完成，其实现本身的复杂性就可想而知了，如果Web数据进行更进一步的多样化，那其复杂度自然增加；&lt;br /&gt;&lt;br /&gt;&lt;ul style="font-weight: bold;"&gt;&lt;li&gt;小型设备化应用&lt;/li&gt;&lt;/ul&gt;由iPhone开启手机浏览互联网的新风，如火如荼的andriod、QtWebKit、Fennec、MiniOpera、UcWeb等正大力的拓展浏览器的嵌入式应用，上网本正是在这样的背景上进入人们的视眼，上网本还没火起来，曾经的维纳斯电视上网计划或许在不久的将来会真正的走进人们的客厅；这样看起来上面提到的浏览器大战似乎才刚刚开局呢。。。。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、如何把握浏览器开发及商业应用&lt;/span&gt;&lt;br /&gt;目前浏览器的开发主要体现在IE内核、Firefox Gecko内核、WebKit内核，从历史的角度看IE内核的扩展更加的容易，面对的PC用户庞大，但同样仅受限于windows平台使用；&lt;br /&gt;&lt;br /&gt;针对Gecko内核，最近几年的extension快速扩展及应用普及加速了Firefox的发展与应用，并且得到一些开发者及网民的好评，同时其可应用于Windows、Mac、Linux平台，其扩展性令人赞叹；&lt;br /&gt;&lt;br /&gt;而WebKit内核，发端应用于Mac平台Safari，名声大振于iPhone，Chrome的出现将其推到风口浪尖，其特性鲜明，虽然其移植性较好，可移植到不同平台，包括嵌入式应用，但其扩展性就没那么方便啦，有些平台对NPAPI插件的全方位支持也显得那么的难得，也许需要给他们一点时间吧，目前看来要想对其进行一定程度的开发难道还是不少。。。&lt;br /&gt;&lt;br /&gt;从以前的历史经验中我们都知道浏览器这样一个软件，受到广大用户的青睐，可没有哪家大公司直接从中获得过与其实际地位相符的利润，包括免费捆绑销售的IE及Netscape等等，从这点看来与Office相比太令人惭愧啦，可见开发浏览器可不那么好赚钱，商业模式不是那么直接，那么写写扩展是否能获取一定回报哪，看看以前IE ActiveX的流行，或许能让我们打开一片联想的天地。&lt;br /&gt;&lt;br /&gt;从更大的角度看，直接从浏览器本身来收取费用如Opera及以前的Netscape，是比较难的，关键得从应用服务来收费，如Firefox从内嵌Google搜索栏来获取收费，Adobe从嵌入的Flash插件来获取丰厚利润回报，但是一个好的扩展应用则需要对浏览器本身及其应用的充分理解。&lt;br /&gt;&lt;br /&gt;也许上网本及各式各样的嵌入设备的出现再加上捆绑免费的浏览器，正是浏览器获取应用及回报的另一途径。&lt;br /&gt;&lt;br /&gt;在浏览器扩展的同时及时提供优秀的Web应用或许是获取商业利润的又一方式，这或许是Google、IBM等大力推广云计算的良苦用心啦。&lt;br /&gt;&lt;br /&gt;面对如此林林总总的方式，作为一个开源浏览器的爱好者，你找到了利用浏览器或其技术实现利润收入的方式了吗？也许大家还有更好的方式，不免大家一起分享分享。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-3861620289886434619?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/3861620289886434619/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=3861620289886434619' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/3861620289886434619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/3861620289886434619'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2009/03/blog-post.html' title='浏览器大战正当时'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-4459952895852462674</id><published>2008-12-26T21:44:00.006+08:00</published><updated>2009-01-22T16:45:13.411+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='W3C标准'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='布局'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><title type='text'>WebKit网页布局实现之布局篇</title><content type='html'>在我们对WebKit网页布局实现所涉及的主要概念及数据结构有了一定的理解之后，让我们再来看看其布局过程的具体实现。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、FrameView::layout方法&lt;/span&gt;&lt;br /&gt;FrameView作为与View相关的类，其主要涉及与显示相关的内容，而其中对页面元素的布局至关重要，这也是浏览器的核心处理部分。&lt;br /&gt;&lt;br /&gt;我们都知道浏览器从Web服务器获得数据后，经解析会构建DOM树、Render树，然后进行布局处理，进而为渲染页面作好准备，其中的布局处理往往由FrameView::layout方法发起，让我们来具体看看其实现，一窥其主要实现过程。&lt;br /&gt;void FrameView::layout(bool allowSubtree)&lt;br /&gt;{&lt;br /&gt; if (d-&gt;m_midLayout)&lt;br /&gt;     return;&lt;br /&gt; // Always ensure our style info is up-to-date.  This can happen in situations where&lt;br /&gt; // the layout beats any sort of style recalc update that needs to occur.&lt;br /&gt;//进行CSSStyleSelector的更新处理，因为一旦CSS发生变化，布局的结果也可能发生相关变化，所以在开始布局之前，需要检查CSS是否发生变化，如果有则需要作相应调整，进而可能影响Render树等。&lt;br /&gt; bool subtree = d-&gt;m_layoutRoot;&lt;br /&gt; .......................................................................&lt;br /&gt; RenderObject* root = subtree ? d-&gt;m_layoutRoot : document-&gt;renderer();&lt;br /&gt; if (!root) {&lt;br /&gt;     // FIXME: Do we need to set m_size here?&lt;br /&gt;     d-&gt;m_layoutSchedulingEnabled = true;&lt;br /&gt;     return;&lt;br /&gt; }&lt;br /&gt; //布局的处理可能相互嵌套，这与发起布局处理的时机相关。&lt;br /&gt; d-&gt;m_nestedLayoutCount++;&lt;br /&gt; ScrollbarMode hMode = d-&gt;m_hmode;&lt;br /&gt; ScrollbarMode vMode = d-&gt;m_vmode;&lt;br /&gt;&lt;br /&gt; d-&gt;m_doFullRepaint = !subtree &amp;amp;&amp;amp; (d-&gt;m_firstLayout || static_cast&lt;renderview*&gt;(root)-&gt;printing());&lt;br /&gt;&lt;br /&gt; if (!subtree) {&lt;br /&gt;     // Now set our scrollbar state for the layout.&lt;br /&gt;     ScrollbarMode currentHMode = hScrollbarMode();&lt;br /&gt;     ScrollbarMode currentVMode = vScrollbarMode();&lt;br /&gt;     //对于初次布局，则需要设置FrameView的滚动条信息等&lt;br /&gt;     if (d-&gt;m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {&lt;br /&gt;         suppressScrollbars(true);&lt;br /&gt;         if (d-&gt;m_firstLayout) {&lt;br /&gt;             d-&gt;m_firstLayout = false;&lt;br /&gt;             d-&gt;m_firstLayoutCallbackPending = true;&lt;br /&gt;             d-&gt;m_lastLayoutSize = IntSize(width(), height());&lt;br /&gt;             d-&gt;m_lastZoomFactor = root-&gt;style()-&gt;zoom();&lt;br /&gt;&lt;br /&gt;             // Set the initial vMode to AlwaysOn if we're auto.&lt;br /&gt;             if (vMode == ScrollbarAuto)&lt;br /&gt;                 ScrollView::setVScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.&lt;br /&gt;             // Set the initial hMode to AlwaysOff if we're auto.&lt;br /&gt;             if (hMode == ScrollbarAuto)&lt;br /&gt;                 ScrollView::setHScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.&lt;br /&gt;         }&lt;br /&gt;     &lt;br /&gt;         if (hMode == vMode)&lt;br /&gt;             ScrollView::setScrollbarsMode(hMode);&lt;br /&gt;         else {&lt;br /&gt;             ScrollView::setHScrollbarMode(hMode);&lt;br /&gt;             ScrollView::setVScrollbarMode(vMode);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         suppressScrollbars(false, true);&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     IntSize oldSize = m_size;&lt;br /&gt;&lt;br /&gt;     m_size = IntSize(visibleWidth(), visibleHeight());&lt;br /&gt;&lt;br /&gt;     if (oldSize != m_size)&lt;br /&gt;         d-&gt;m_doFullRepaint = true;&lt;br /&gt; }&lt;br /&gt; //root往往为RenderView对象&lt;br /&gt; RenderLayer* layer = root-&gt;enclosingLayer();&lt;br /&gt; ......................................&lt;br /&gt; d-&gt;m_midLayout = true;&lt;br /&gt; beginDeferredRepaints();&lt;br /&gt; &lt;span style="font-weight: bold;"&gt;root-&gt;layout();&lt;/span&gt;&lt;br /&gt; endDeferredRepaints();&lt;br /&gt; d-&gt;m_midLayout = false;&lt;br /&gt; .......................................&lt;br /&gt; d-&gt;m_layoutSchedulingEnabled = true;&lt;br /&gt;&lt;br /&gt; if (!subtree &amp;amp;&amp;amp; !static_cast&lt;renderview*&gt;(root)-&gt;printing())&lt;br /&gt;     adjustViewSize();&lt;br /&gt;&lt;br /&gt; // Now update the positions of all layers.&lt;br /&gt;//对当前Render树布局完后，设置RenderLayer树的布局信息，其中d-&gt;m_doFullRepaint描述是否需要发起渲染处理。&lt;br /&gt; beginDeferredRepaints();&lt;br /&gt; layer-&gt;updateLayerPositions(d-&gt;m_doFullRepaint);///it's very important for RenderLayer to set m_x/m_y/m_width/m_height&lt;br /&gt; endDeferredRepaints();&lt;br /&gt; //因为在布局的过程中，可能进一步获得网页数据，则需要继续布局处理。&lt;br /&gt; if (needsLayout()) {&lt;br /&gt;     // Post-layout widget updates or an event handler made us need layout again.&lt;br /&gt;     // Lay out again, but this time defer widget updates and event dispatch until after&lt;br /&gt;     // we return.&lt;br /&gt;     ........................&lt;br /&gt;    &lt;span style="font-weight: bold;"&gt; layout();&lt;/span&gt;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;FrameView::layout方法，简单的说来就是发起对Render树中的每一个节点按照从父节点到子节点的方式进行x、y、width、height计算，当每一个树节点的位置及大小确定之后就可以进行后面的渲染。&lt;br /&gt;&lt;br /&gt;FrameView::layout往往会调用Render树根的layout方法即RenderView::layout。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、RenderView::layout方法&lt;/span&gt;&lt;br /&gt;void RenderView::layout()&lt;br /&gt;{&lt;br /&gt; if (printing())&lt;br /&gt;     m_minPrefWidth = m_maxPrefWidth = m_width;&lt;br /&gt;&lt;br /&gt; // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.&lt;br /&gt; bool relayoutChildren = !printing() &amp;amp;&amp;amp; (!m_frameView || m_width != viewWidth() || m_height != viewHeight());&lt;br /&gt; if (relayoutChildren)&lt;br /&gt;     setChildNeedsLayout(true, false);&lt;br /&gt;&lt;br /&gt; ASSERT(!m_layoutState);&lt;br /&gt; LayoutState state;&lt;br /&gt; // FIXME: May be better to push a clip and avoid issuing offscreen repaints.&lt;br /&gt; state.m_clipped = false;&lt;br /&gt; m_layoutState = &amp;state;&lt;br /&gt;&lt;br /&gt; if (needsLayout())&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;RenderBlock::layout();&lt;/span&gt;//类继承的好处，直接调用父类的layout&lt;br /&gt;&lt;br /&gt; // Ensure that docWidth() &gt;= width() and docHeight() &gt;= height().&lt;br /&gt; setOverflowWidth(m_width);&lt;br /&gt; setOverflowHeight(m_height);&lt;br /&gt;&lt;br /&gt; setOverflowWidth(docWidth());&lt;br /&gt; setOverflowHeight(docHeight());&lt;br /&gt;&lt;br /&gt; ASSERT(m_layoutStateDisableCount == 0);&lt;br /&gt; ASSERT(m_layoutState == &amp;amp;state);&lt;br /&gt; m_layoutState = 0;&lt;br /&gt; setNeedsLayout(false);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderBlock::layout()&lt;br /&gt;{&lt;br /&gt; // Update our first letter info now.&lt;br /&gt; updateFirstLetter();&lt;br /&gt; // Table cells call layoutBlock directly, so don't add any logic here.  Put code into&lt;br /&gt; // layoutBlock().&lt;br /&gt; &lt;span style="font-weight: bold;"&gt;layoutBlock(false);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; // It's safe to check for control clip here, since controls can never be table cells.&lt;br /&gt; if (hasControlClip()) {&lt;br /&gt;     // Because of the lightweight clip, there can never be any overflow from children.&lt;br /&gt;     m_overflowWidth = m_width;&lt;br /&gt;     m_overflowHeight = m_height;&lt;br /&gt;     m_overflowLeft = 0;&lt;br /&gt;     m_overflowTop = 0;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、RenderBlock::layoutBlock方法&lt;/span&gt;&lt;br /&gt;void RenderBlock::layoutBlock(bool relayoutChildren)&lt;br /&gt;{&lt;br /&gt; ......................................................&lt;br /&gt; &lt;span style="font-weight: bold;"&gt;calcWidth();//先计算宽度&lt;/span&gt;&lt;br /&gt; calcColumnWidth();&lt;br /&gt;&lt;br /&gt; m_overflowWidth = m_width;&lt;br /&gt; m_overflowLeft = 0;&lt;br /&gt; if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth())&lt;br /&gt;     relayoutChildren = true;&lt;br /&gt; clearFloats();&lt;br /&gt;&lt;br /&gt; int previousHeight = m_height;&lt;br /&gt; m_height = 0;&lt;br /&gt; m_overflowHeight = 0;&lt;br /&gt; ..................................................&lt;br /&gt; //这就是在布局基本概念中提到的Block-level元素的子节点要么是Block-level元素要么为Inline-level元素。&lt;br /&gt; if (childrenInline())&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;layoutInlineChildren&lt;/span&gt;(relayoutChildren, repaintTop, repaintBottom);&lt;br /&gt; else&lt;br /&gt;    &lt;span style="font-weight: bold;"&gt; layoutBlockChildren&lt;/span&gt;(relayoutChildren, maxFloatBottom);&lt;br /&gt;&lt;br /&gt; // Expand our intrinsic height to encompass floats.&lt;br /&gt; int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();&lt;br /&gt; if (floatBottom() &gt; (m_height - toAdd) &amp;amp;&amp;amp; (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() ||&lt;br /&gt;                                 (parent() &amp;amp;&amp;amp; parent()-&gt;isFlexibleBox() || m_hasColumns)))&lt;br /&gt;     m_height = floatBottom() + toAdd;&lt;br /&gt;&lt;br /&gt; // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as&lt;br /&gt; // we adjust for clean column breaks.&lt;br /&gt; int singleColumnBottom = layoutColumns();&lt;br /&gt;&lt;br /&gt; // Calculate our new height.//布局完子节点后确定父节点高度&lt;br /&gt; int oldHeight = m_height;&lt;br /&gt; &lt;span style="font-weight: bold;"&gt;calcHeight();&lt;/span&gt;&lt;br /&gt; ....................................................&lt;br /&gt; if (previousHeight != m_height)&lt;br /&gt;     relayoutChildren = true;&lt;br /&gt; ...................................................&lt;br /&gt; if ((isCell || isInline() || isFloatingOrPositioned() || isRoot()) &amp;amp;&amp;amp; !hasOverflowClip() &amp;amp;&amp;amp; !hasControlClip())&lt;br /&gt;     addVisualOverflow(floatRect());&lt;br /&gt; //另外布局属性为Fixed和absolute的元素&lt;br /&gt; layoutPositionedObjects(relayoutChildren || isRoot());&lt;br /&gt;&lt;br /&gt; // Always ensure our overflow width/height are at least as large as our width/height.&lt;br /&gt; m_overflowWidth = max(m_overflowWidth, m_width);&lt;br /&gt; m_overflowHeight = max(m_overflowHeight, m_height);&lt;br /&gt;&lt;br /&gt; ......................................................&lt;br /&gt;&lt;br /&gt; // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if&lt;br /&gt; // we overflow or not.&lt;br /&gt; if (hasOverflowClip())&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;m_layer-&gt;updateScrollInfoAfterLayout&lt;/span&gt;();//also is important..&lt;br /&gt;&lt;br /&gt; // Repaint with our new bounds if they are different from our old bounds.&lt;br /&gt; bool didFullRepaint = false;&lt;br /&gt; //布局后根据条件确定是否发起渲染处理&lt;br /&gt; if (checkForRepaint)&lt;br /&gt;     didFullRepaint = &lt;span style="font-weight: bold;"&gt;repaintAfterLayoutIfNeeded&lt;/span&gt;(oldBounds, oldOutlineBox);&lt;br /&gt; ..........................................................&lt;br /&gt;     // Make sure the rect is still non-empty after intersecting for overflow above&lt;br /&gt;     if (!repaintRect.isEmpty()) {&lt;br /&gt;         repaintRectangle(repaintRect); // We need to do a partial repaint of our content.&lt;br /&gt;         if (hasReflection())&lt;br /&gt;             layer()-&gt;reflection()-&gt;repaintRectangle(repaintRect);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt; setNeedsLayout(false);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、RenderBlock::layoutBlockChildren方法&lt;/span&gt;&lt;br /&gt;void RenderBlock::layoutBlockChildren(bool relayoutChildren, int&amp;amp; maxFloatBottom)&lt;br /&gt;{&lt;br /&gt; int top = borderTop() + paddingTop();&lt;br /&gt; int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();&lt;br /&gt;&lt;br /&gt; m_height = m_overflowHeight = top;&lt;br /&gt; //遍历子节点&lt;br /&gt; RenderObject* child = &lt;span style="font-weight: bold;"&gt;firstChild();&lt;/span&gt;&lt;br /&gt; while (child) {&lt;br /&gt;     if (legend == child) {&lt;br /&gt;         child = child-&gt;nextSibling();&lt;br /&gt;         continue; // Skip the legend, since it has already been positioned up in the fieldset's border.&lt;br /&gt;     }&lt;br /&gt;     .........................................&lt;br /&gt;     // Handle the four types of special elements first.  These include positioned content, floating content, compacts and&lt;br /&gt;     // run-ins.  When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.&lt;br /&gt;     bool handled = false;&lt;br /&gt;     RenderObject* next = handleSpecialChild(child, marginInfo, compactInfo, handled);&lt;br /&gt;     if (handled) { child = next; continue; }&lt;br /&gt;&lt;br /&gt;     // The child is a normal flow object.  Compute its vertical margins now.&lt;br /&gt;     child-&gt;calcVerticalMargins();&lt;br /&gt;     // Do not allow a collapse if the margin top collapse style is set to SEPARATE.&lt;br /&gt;&lt;br /&gt;     // Try to guess our correct y position.  In most cases this guess will&lt;br /&gt;     // be correct.  Only if we're wrong (when we compute the real y position)&lt;br /&gt;     // will we have to potentially relayout.&lt;br /&gt;     int yPosEstimate = estimateVerticalPosition(child, marginInfo);&lt;br /&gt;&lt;br /&gt;     // Cache our old rect so that we can dirty the proper repaint rects if the child moves.&lt;br /&gt;     IntRect oldRect(child-&gt;xPos(), child-&gt;yPos() , child-&gt;width(), child-&gt;height());&lt;br /&gt;   &lt;br /&gt;     // Go ahead and position the child as though it didn't collapse with the top.&lt;br /&gt;     view()-&gt;addLayoutDelta(IntSize(0, child-&gt;yPos() - yPosEstimate));&lt;br /&gt;     //先确定x、y。&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;child-&gt;setPos&lt;/span&gt;(child-&gt;xPos(), yPosEstimate);&lt;br /&gt;     ..........................................&lt;br /&gt;     bool childNeededLayout = child-&gt;needsLayout();&lt;br /&gt;     if (childNeededLayout)&lt;br /&gt;         &lt;span style="font-weight: bold;"&gt;child-&gt;layout()&lt;/span&gt;;//子节点进行布局处理&lt;br /&gt;     ...................................................&lt;br /&gt;     // Now place the child in the correct horizontal position&lt;br /&gt;     determineHorizontalPosition(child);&lt;br /&gt;     // Update our height now that the child has been placed in the correct position.&lt;br /&gt;     m_height += child-&gt;height();&lt;br /&gt;     if (child-&gt;style()-&gt;marginBottomCollapse() == MSEPARATE) {&lt;br /&gt;         m_height += child-&gt;marginBottom();&lt;br /&gt;         marginInfo.clearMargin();&lt;br /&gt;     }&lt;br /&gt;     .........................................................&lt;br /&gt;     // Update our overflow in case the child spills out the block.&lt;br /&gt;     ..........................................................&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;child = child-&gt;nextSibling();&lt;/span&gt;&lt;br /&gt; }&lt;br /&gt; // Now do the handling of the bottom of the block, adding in our bottom border/padding and&lt;br /&gt; // determining the correct collapsed bottom margin information.&lt;br /&gt; handleBottomOfBlock(top, bottom, marginInfo);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、RenderBlock::layoutInlineChildren方法&lt;/span&gt;&lt;br /&gt;这个方法相当复杂，其作用就是布局文字、图像等，对文字行高确定、断行等处理，同时还包括 文字从左到右或从右到左的布局处理。具体可以参考bidi.cpp中的源码实现。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、调用FrameView::layout方法的时机&lt;/span&gt;&lt;br /&gt;由于从Web服务器获取的网页数据不可能一次性完成，往往需要边获取数据，边布局，然后渲染，这样才可能获得良好的用户感受。&lt;br /&gt;&lt;br /&gt;所以一旦获得主要数据如css数据及body等标签后，就可以开始布局，布局完后会根据当前条件决定是否将布局的数据渲染出来，或者继续布局处理后来获取的数据，这样也增加了布局处理过程的复杂度。&lt;br /&gt;&lt;br /&gt;而调用layout方法的时机也至关重要，因为layout本身就可能需要花费大量的时间如&lt;span style="font-weight: bold;"&gt;layoutBlockChildren、&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;layoutInlineChildren&lt;/span&gt;等处理，其往往与网页的内容有关，而网页的内容却由网页开发者来确定，对浏览器来讲是千变万化的，这就对layout方法的实现及调用时机提出更高的要求，同时确定了其复杂性。&lt;br /&gt;&lt;br /&gt;调用layout的时机主要有获得一定DOM文档数据后调用Document::updateLayout()、需要重新使用CSS数据时调用Document::recalcStyle()、改变窗口大小后调用Frame::forceLayout()等来实现。。。&lt;br /&gt;&lt;br /&gt;&lt;/renderview*&gt;&lt;/renderview*&gt;&lt;span style="font-weight: bold;"&gt;七、总结&lt;/span&gt;&lt;br /&gt;其实WebKit涉及网页布局方面的layout方法蛮复杂的，如其他RenderObject子类也会根据自身情况重载实现layout，还有对float、fixed、absolute、inline元素等的处理，但其主要逻辑就象上面所提，这里只是汇总一下主要流程及概念，针对每一个具体标签或RenderObject的布局实现则需要更深一步的了解，希望大家能对了解WebKit的网页布局过程有一个清晰而准确的认识。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;八、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://webkit.org/"&gt;The WebKit Open Source Project&lt;/a&gt;&lt;renderview*&gt;&lt;renderview*&gt;&lt;br /&gt;&lt;/renderview*&gt;&lt;/renderview*&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-4459952895852462674?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/4459952895852462674/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=4459952895852462674' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4459952895852462674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4459952895852462674'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/12/webkit_26.html' title='WebKit网页布局实现之布局篇'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-5994415612904236069</id><published>2008-12-18T20:38:00.023+08:00</published><updated>2009-01-22T16:45:45.823+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='W3C标准'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='布局'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><title type='text'>WebKit网页布局实现之主要数据结构篇之二</title><content type='html'>从&lt;a href="http://ourpgh.blogspot.com/2008/11/webkit_28.html"&gt;上一篇&lt;/a&gt;&lt;a href="http://ourpgh.blogspot.com/2008/11/webkit_28.html"&gt;WebKit网页布局实现之主要数据结构篇&lt;/a&gt;中,我们对WebKit网页布局所涉及的主要数据结构有了初步的了解，认识到Render树的构成及CSS属性的描述RenderStyle等，对主要 RenderObject基类及子类有了一定的了解，但在构成Render树时所涉及的一些关键方法还未具体描述，同时还有其他一些为布局及渲染所准备的数据结构也需要有更深入的理解，下面将进一步的了解相关数据结构及相关方法。&lt;br /&gt;&lt;br /&gt;一、&lt;span style="font-weight: bold;"&gt;继续Render树的构成&lt;br /&gt;1、子类RenderButton&lt;br /&gt;&lt;/span&gt;RenderButton代表html中input标签type为button时对应的Render树节点，它直接继承自RenderFlexibleBox；&lt;br /&gt;RenderFlexibleBox代表能按居中、左对齐、右对齐等水平或垂直方向布局子节点的树节点；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderButton主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gp8441q4aEg/SUuQ6CYiISI/AAAAAAAAADk/jqX5LDjNhks/s1600-h/webkit-RenderButton.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 285px; height: 360px;" src="http://4.bp.blogspot.com/_gp8441q4aEg/SUuQ6CYiISI/AAAAAAAAADk/jqX5LDjNhks/s400/webkit-RenderButton.jpg" alt="" id="BLOGGER_PHOTO_ID_5281474314768621858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图一&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;其中m_buttonText为button上的文字对应的树节点，而m_inner为添加m_buttonText时创建的匿名对象，以便于居中等处理等。这些成员的创建来自于方法updateFromElement；&lt;br /&gt;void RenderButton::updateFromElement()&lt;br /&gt;{&lt;br /&gt;// If we're an input element, we may need to change our button text.&lt;br /&gt;if (element()-&gt;hasTagName(inputTag)) {&lt;br /&gt;HTMLInputElement* input = static_cast&lt;htmlinputelement*&gt;(element());&lt;br /&gt;String value = input-&gt;valueWithDefault();&lt;br /&gt;setText(value);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;void RenderButton::setText(const String&amp;amp; str)&lt;br /&gt;{&lt;br /&gt;..........................&lt;br /&gt;m_buttonText = new (renderArena()) RenderTextFragment(document(), str.impl());&lt;br /&gt;m_buttonText-&gt;setStyle(style());&lt;br /&gt;addChild(m_buttonText);&lt;br /&gt;......................&lt;br /&gt;}&lt;br /&gt;void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)&lt;br /&gt;{&lt;br /&gt;if (!m_inner) {&lt;br /&gt;// Create an anonymous block.&lt;br /&gt;m_inner = createAnonymousBlock();&lt;br /&gt;m_inner-&gt;style()-&gt;setBoxFlex(1.0f);&lt;br /&gt;RenderFlexibleBox::addChild(m_inner);&lt;br /&gt;}&lt;br /&gt;m_inner-&gt;addChild(newChild, beforeChild);&lt;br /&gt;}&lt;br /&gt;在缺省的html.css中对应button的css属性如下：&lt;br /&gt;input[type="button"] {&lt;br /&gt;-webkit-appearance: push-button;&lt;br /&gt;white-space: pre&lt;br /&gt;}&lt;br /&gt;input[type="button"]{&lt;br /&gt;-webkit-box-align: center;&lt;br /&gt;text-align: center;&lt;br /&gt;cursor: default;&lt;br /&gt;color: ButtonText;&lt;br /&gt;padding: 2px 6px 3px 6px;&lt;br /&gt;border: 2px outset ButtonFace;&lt;br /&gt;background-color: ButtonFace;&lt;br /&gt;-webkit-box-sizing: border-box&lt;br /&gt;}&lt;br /&gt;这 些css属性通过CSSStyleSelector::applyProperty方法来设定其成员m_RenderStyle对应的值，其中包含 m_style-&gt;setAppearance(PushButtonAppearance);尤其值得关注，其初步决定了button是如何画出 来的。。&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;2、子类RenderTextControl&lt;/span&gt;&lt;br /&gt;RenderTextControl代表html中input标签type为text或textarea标签对应的Render树节点，它直接继承自RenderBlock；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderTextControl主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gp8441q4aEg/SUubGir1sYI/AAAAAAAAADs/WFInJkb0KR0/s1600-h/webkit-RenderTextControl.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 323px; height: 349px;" src="http://1.bp.blogspot.com/_gp8441q4aEg/SUubGir1sYI/AAAAAAAAADs/WFInJkb0KR0/s400/webkit-RenderTextControl.jpg" alt="" id="BLOGGER_PHOTO_ID_5281485524714238338" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图二&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其中成员m_multiLine以描述是textarea或text input；m_innerText为其中包括的文字对应的树节点；当作搜索按钮时&lt;/htmlinputelement*&gt;m_cancelButton/m_resultsButton为&lt;htmlinputelement*&gt;对应的树节点；&lt;/htmlinputelement*&gt;这些成员的创建来自于方法updateFromElement；&lt;br /&gt;void RenderTextControl::updateFromElement()&lt;br /&gt;{&lt;br /&gt;HTMLFormControlElement* element = static_cast&lt;htmlformcontrolelement*&gt;(node());&lt;br /&gt;&lt;br /&gt;createSubtreeIfNeeded();&lt;br /&gt;&lt;br /&gt;...................................&lt;br /&gt;&lt;br /&gt;m_innerText-&gt;renderer()-&gt;style()-&gt;setUserModify(element-&gt;isReadOnlyControl() || element-&gt;disabled() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);&lt;br /&gt;&lt;br /&gt;if ((!element-&gt;valueMatchesRenderer() || m_multiLine) &amp;amp;&amp;amp; !m_placeholderVisible) {&lt;br /&gt;String value;&lt;br /&gt;if (m_multiLine)&lt;br /&gt;value = static_cast&lt;htmltextareaelement*&gt;(element)-&gt;value();&lt;br /&gt;else&lt;br /&gt;value = static_cast&lt;htmlinputelement*&gt;(element)-&gt;value();&lt;br /&gt;if (value.isNull())&lt;br /&gt;value = "";&lt;br /&gt;else&lt;br /&gt;value = value.replace('\\', backslashAsCurrencySymbol());&lt;br /&gt;if (value != text() || !m_innerText-&gt;hasChildNodes()) {&lt;br /&gt;if (value != text()) {&lt;br /&gt;if (Frame* frame = document()-&gt;frame())&lt;br /&gt;frame-&gt;editor()-&gt;clearUndoRedoOperations();&lt;br /&gt;}&lt;br /&gt;ExceptionCode ec = 0;&lt;br /&gt;m_innerText-&gt;setInnerText(value, ec);&lt;br /&gt;if (value.endsWith("\n") || value.endsWith("\r"))&lt;br /&gt;m_innerText-&gt;appendChild(new HTMLBRElement(document()), ec);&lt;br /&gt;m_dirty = false;&lt;br /&gt;m_userEdited = false;&lt;br /&gt;}&lt;br /&gt;....................................&lt;br /&gt;}&lt;br /&gt;....................................&lt;br /&gt;}&lt;br /&gt;void RenderTextControl::createSubtreeIfNeeded()&lt;br /&gt;{&lt;br /&gt;............................................&lt;br /&gt;if (!m_innerText) {&lt;br /&gt;m_innerText = new HTMLTextFieldInnerTextElement(document(), m_innerBlock ? 0 : node());&lt;br /&gt;RenderTextControlInnerBlock* textBlockRenderer = new (renderArena()) RenderTextControlInnerBlock(m_innerText.get());&lt;br /&gt;m_innerText-&gt;setRenderer(textBlockRenderer);&lt;br /&gt;m_innerText-&gt;setAttached();&lt;br /&gt;m_innerText-&gt;setInDocument(true);&lt;br /&gt;&lt;br /&gt;RenderStyle* parentStyle = style();&lt;br /&gt;if (m_innerBlock)&lt;br /&gt;parentStyle = m_innerBlock-&gt;renderer()-&gt;style();&lt;br /&gt;RenderStyle* textBlockStyle = createInnerTextStyle(parentStyle);&lt;br /&gt;textBlockRenderer-&gt;setStyle(textBlockStyle);&lt;br /&gt;&lt;br /&gt;// Add text block renderer to Render tree&lt;br /&gt;if (m_innerBlock) {&lt;br /&gt;m_innerBlock-&gt;renderer()-&gt;addChild(textBlockRenderer);&lt;br /&gt;ExceptionCode ec = 0;&lt;br /&gt;// Add text block to the DOM&lt;br /&gt;m_innerBlock-&gt;appendChild(m_innerText, ec);&lt;br /&gt;} else&lt;br /&gt;RenderBlock::addChild(textBlockRenderer);&lt;br /&gt;}&lt;br /&gt;.................................&lt;br /&gt;}&lt;br /&gt;在缺省的html.css中对应标签的css属性如下：&lt;br /&gt;textarea {&lt;br /&gt;-webkit-appearance: textarea;&lt;br /&gt;background-color: white;&lt;br /&gt;border: 1px solid;&lt;br /&gt;-webkit-rtl-ordering: logical;&lt;br /&gt;-webkit-user-select: text;&lt;br /&gt;-webkit-box-orient: vertical;&lt;br /&gt;resize: auto;&lt;br /&gt;cursor: auto;&lt;br /&gt;}&lt;br /&gt;input, input[type="password"], input[type="search"], isindex {&lt;br /&gt;-webkit-appearance: textfield;&lt;br /&gt;padding: 1px;&lt;br /&gt;background-color: white;&lt;br /&gt;border: 2px inset;&lt;br /&gt;-webkit-rtl-ordering: logical;&lt;br /&gt;-webkit-user-select: text;&lt;br /&gt;cursor: auto;&lt;br /&gt;}&lt;br /&gt;其中-webkit-appearance属性分别为textarea、textfield；&lt;br /&gt;&lt;htmlinputelement*&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、子类RenderListBox&lt;br /&gt;&lt;/span&gt;&lt;/htmlinputelement*&gt;RenderListBox代表html中select标签对应的Render树节点，它直接继承自RenderBlock；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderListBox主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gp8441q4aEg/SUug46FYcpI/AAAAAAAAAD0/QwFM4NfCe7w/s1600-h/webkit-RenderListBox.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 323px; height: 232px;" src="http://1.bp.blogspot.com/_gp8441q4aEg/SUug46FYcpI/AAAAAAAAAD0/QwFM4NfCe7w/s400/webkit-RenderListBox.jpg" alt="" id="BLOGGER_PHOTO_ID_5281491887546987154" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图三&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其相关成员同样通过方法updateFromElement来设置初值；&lt;br /&gt;&lt;/htmlinputelement*&gt;&lt;/htmltextareaelement*&gt;&lt;/htmlformcontrolelement*&gt;在缺省的html.css中对应标签的css属性如下：&lt;br /&gt;select {&lt;br /&gt;-webkit-appearance: menulist;&lt;br /&gt;-webkit-box-sizing: border-box;&lt;br /&gt;-webkit-box-align: center;&lt;br /&gt;border: 1px solid;&lt;br /&gt;..............................................................&lt;br /&gt;}&lt;htmlformcontrolelement*&gt;&lt;htmltextareaelement*&gt;&lt;htmlinputelement*&gt;&lt;htmlinputelement*&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;4、子类RenderTheme&lt;br /&gt;&lt;/span&gt;&lt;/htmlinputelement*&gt;&lt;/htmlinputelement*&gt;&lt;/htmltextareaelement*&gt;&lt;/htmlformcontrolelement*&gt;RenderTheme在html标签中没有对应的页面元素，其作用主要用于如何渲染按钮、输入框、列表框等，其实现往往有一定平台相关性。&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderTheme主要数据成员及方法&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/SUukyl2He3I/AAAAAAAAAD8/DTejdxKGuCE/s1600-h/webkit-RenderTheme.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 213px; height: 400px;" src="http://3.bp.blogspot.com/_gp8441q4aEg/SUukyl2He3I/AAAAAAAAAD8/DTejdxKGuCE/s400/webkit-RenderTheme.jpg" alt="" id="BLOGGER_PHOTO_ID_5281496177081547634" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图四&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;RenderTheme 往往提供一个接口，不同的图形库对其中不同的方法如paintbutton、paintcheckbox、painttextfield等进行了实现；其中 paint方法则根据appearance属性的不同以分别调用不同的paintxxx方法，其示例代码如下：&lt;br /&gt;bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo&amp;amp; paintInfo, const IntRect&amp;amp; r)&lt;br /&gt;{&lt;br /&gt;........................................&lt;br /&gt;if (paintInfo.context-&gt;paintingDisabled())&lt;br /&gt;return false;&lt;br /&gt;// Call the appropriate paint method based off the appearance value.&lt;br /&gt;switch (o-&gt;style()-&gt;appearance()) {&lt;br /&gt;case CheckboxAppearance:&lt;br /&gt;return paintCheckbox(o, paintInfo, r);&lt;br /&gt;case RadioAppearance:&lt;br /&gt;return paintRadio(o, paintInfo, r);&lt;br /&gt;case PushButtonAppearance:&lt;br /&gt;case SquareButtonAppearance:&lt;br /&gt;case DefaultButtonAppearance:&lt;br /&gt;case ButtonAppearance:&lt;br /&gt;return paintButton(o, paintInfo, r);&lt;br /&gt;case MenulistAppearance:&lt;br /&gt;return paintMenuList(o, paintInfo, r);&lt;br /&gt;break;&lt;br /&gt;....................................................&lt;br /&gt;default:&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;return true; // We don't support the appearance, so let the normal background/border paint.&lt;br /&gt;}&lt;br /&gt;其中的appearance就是上面RenderButton、RenderTextControl、RenderListBox中提到的属性，至于 html中涉及到的类似标签或属性如radio、checkbox等等，其相关代码基本类似，至于不同的平台如Qt、Gtk、Win、Mac等究竟是如何画按钮、下拉框、列表框、多选框、单选框等等，则需详细参考RenderThemeQt/RenderThemeGtk/RenderThemeWin /RenderThemeMac等中的实现。&lt;br /&gt;&lt;br /&gt;通过上述的了解我们应该对html中form标签内的输入框、按钮、下拉框等实现有了一定的认识。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5、子类RenderTable、RenderTableRow、RenderTableCol、RenderTableCell&lt;/span&gt;&lt;br /&gt;这一组子类主要对应与html中table标签相关的树节点；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Table标签相关类主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/SUutXacolCI/AAAAAAAAAEE/ROAmM8V4xqo/s1600-h/webkit-RenderTable.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 297px; height: 400px;" src="http://3.bp.blogspot.com/_gp8441q4aEg/SUutXacolCI/AAAAAAAAAEE/ROAmM8V4xqo/s400/webkit-RenderTable.jpg" alt="" id="BLOGGER_PHOTO_ID_5281505605770056738" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图五&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;RenderTable主要通过addChild方法来维护对RenderTableCell、RenderTableCol、RenderTableRow等对象的管理及维护；&lt;br /&gt;void RenderTableCell::updateFromElement()&lt;br /&gt;{&lt;br /&gt;Node* node = element();&lt;br /&gt;if (node &amp;amp;&amp;amp; (node-&gt;hasTagName(tdTag) || node-&gt;hasTagName(thTag))) {&lt;br /&gt;HTMLTableCellElement* tc = static_cast&lt;htmltablecellelement*&gt;(node);&lt;br /&gt;int oldRSpan = m_rowSpan;&lt;br /&gt;int oldCSpan = m_columnSpan;&lt;br /&gt;&lt;br /&gt;m_columnSpan = tc-&gt;colSpan();&lt;br /&gt;m_rowSpan = tc-&gt;rowSpan();&lt;br /&gt;if ((oldRSpan != m_rowSpan || oldCSpan != m_columnSpan) &amp;amp;&amp;amp; style() &amp;amp;&amp;amp; parent()) {&lt;br /&gt;setNeedsLayoutAndPrefWidthsRecalc();&lt;br /&gt;if (section())&lt;br /&gt;  section()-&gt;setNeedsCellRecalc();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderTableCol::updateFromElement()&lt;br /&gt;{&lt;br /&gt;int oldSpan = m_span;&lt;br /&gt;Node* node = element();&lt;br /&gt;if (node &amp;amp;&amp;amp; (node-&gt;hasTagName(colTag) || node-&gt;hasTagName(colgroupTag))) {&lt;br /&gt;HTMLTableColElement* tc = static_cast&lt;htmltablecolelement*&gt;(node);&lt;br /&gt;m_span = tc-&gt;span();&lt;br /&gt;} else&lt;br /&gt;m_span = !(style() &amp;amp;&amp;amp; style()-&gt;display() == TABLE_COLUMN_GROUP);&lt;br /&gt;if (m_span != oldSpan &amp;amp;&amp;amp; style() &amp;amp;&amp;amp; parent())&lt;br /&gt;setNeedsLayoutAndPrefWidthsRecalc();&lt;br /&gt;}&lt;br /&gt;RenderTableRow通过方法layout和paint方法来布局管理RenderTableCell对象；&lt;br /&gt;这一组子类主要实现人们熟知的表格布局，具体的实现可具体参考相关类实现；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;6、子类RenderFrame&lt;/span&gt;&lt;br /&gt;RenderFrame代表html中标签frame对应的Render树节点，其继承关系如下：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderFrame类继承关系&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/SUvCBDHN7cI/AAAAAAAAAEU/hWrW6uxMrrw/s1600-h/webkit-RenderFrame.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 292px; height: 400px;" src="http://3.bp.blogspot.com/_gp8441q4aEg/SUvCBDHN7cI/AAAAAAAAAEU/hWrW6uxMrrw/s400/webkit-RenderFrame.jpg" alt="" id="BLOGGER_PHOTO_ID_5281528311293275586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图六&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;其中属性m_widget、m_view代表frame对应的widget及frameview，通过其中setwidget方法来设置m_widget属性，m_view属性则在对象创建的时候设置为当前document对应的frameview。&lt;br /&gt;&lt;br /&gt;其中html中的embed/object插件标签对应的Render树节点为RenderPartObject对象。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;7、构建Render树&lt;/span&gt;&lt;br /&gt;从上一篇中我们了解到构建Render树的基本实现流程如下：void Element::attach()=&gt;createRendererIfNeeded()=&gt;createRenderer；以前我们着重了解过createRenderer，现在我们回头再来看看createRendererIfNeeded()，以更深入的了解是如何构建Render树。&lt;br /&gt;void Node::createRendererIfNeeded()&lt;br /&gt;{&lt;br /&gt;if (!document()-&gt;shouldCreateRenderers())&lt;br /&gt;return;&lt;br /&gt;Node *parent = parentNode();&lt;br /&gt;RenderObject *parentRenderer = &lt;span style="font-weight: bold;"&gt;parent-&gt;renderer()&lt;/span&gt;;&lt;br /&gt;if (parentRenderer &amp;amp;&amp;amp; parentRenderer-&gt;&lt;span style="font-weight: bold;"&gt;canHaveChildren&lt;/span&gt;()&lt;br /&gt;#if ENABLE(SVG)&lt;br /&gt;&amp;amp;&amp;amp; parent-&gt;childShouldCreateRenderer(this)&lt;br /&gt;#endif&lt;br /&gt;) {&lt;br /&gt;RenderStyle* style = &lt;span style="font-weight: bold;"&gt;styleForRenderer&lt;/span&gt;(parentRenderer);&lt;br /&gt;if (rendererIsNeeded(style)) {&lt;br /&gt;   if (RenderObject* r = createRenderer(document()-&gt;renderArena(), style)) {&lt;br /&gt;       if (!parentRenderer-&gt;isChildAllowed(r, style))&lt;br /&gt;           r-&gt;destroy();&lt;br /&gt;       else {&lt;br /&gt;           setRenderer(r);&lt;br /&gt;           renderer()-&gt;&lt;span style="font-weight: bold;"&gt;setAnimatableStyle&lt;/span&gt;(style);&lt;br /&gt;           parentRenderer-&gt;&lt;span style="font-weight: bold;"&gt;addChild&lt;/span&gt;(renderer(), nextRenderer());&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;style-&gt;deref(document()-&gt;renderArena());&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;RenderStyle* Element::styleForRenderer(RenderObject* parentRenderer)&lt;br /&gt;{&lt;br /&gt;return document()-&gt;styleSelector()-&gt;styleForElement(this);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderObject::setAnimatableStyle(RenderStyle* style)&lt;br /&gt;{&lt;br /&gt;if (!isText() &amp;amp;&amp;amp; m_style &amp;amp;&amp;amp; style)&lt;br /&gt;style = animation()-&gt;updateImplicitAnimations(this, style);&lt;br /&gt;&lt;br /&gt;setStyle(style);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;从createRendererIfNeeded中我们可以了解到创建完RenderObject子类对象后，会为其设置RenderStyle属性，然后在该DOM Node的父节点对应的RenderObject中添加刚新建的RenderObject，这样以构建Render树。&lt;br /&gt;&lt;br /&gt;但是在setStyle的过程中可能会调用createAnonymousFlow或createAnonymousBlock来创建匿名对象，其中RenderBox的setStyle方法如下：&lt;br /&gt;void RenderBox::setStyle(RenderStyle* newStyle)&lt;br /&gt;{&lt;br /&gt;bool wasFloating = isFloating();&lt;br /&gt;bool hadOverflowClip = hasOverflowClip();&lt;br /&gt;RenderStyle* oldStyle = style();&lt;br /&gt;if (oldStyle)&lt;br /&gt;oldStyle-&gt;ref();&lt;br /&gt;&lt;br /&gt;RenderObject::setStyle(newStyle);&lt;br /&gt;....................................................................&lt;br /&gt;setInline(newStyle-&gt;isDisplayInlineType());&lt;br /&gt;&lt;br /&gt;switch (newStyle-&gt;position()) {&lt;br /&gt;case AbsolutePosition:&lt;br /&gt;case FixedPosition:&lt;br /&gt;    setPositioned(true);&lt;br /&gt;    break;&lt;br /&gt;default:&lt;br /&gt;    setPositioned(false);&lt;br /&gt;&lt;br /&gt;    if (newStyle-&gt;isFloating())&lt;br /&gt;        setFloating(true);&lt;br /&gt;&lt;br /&gt;    if (newStyle-&gt;position() == RelativePosition)&lt;br /&gt;        setRelPositioned(true);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// We also handle  and , whose overflow applies to the viewport.&lt;br /&gt;if (!isRoot() &amp;amp;&amp;amp; (!isBody() || !document()-&gt;isHTMLDocument()) &amp;amp;&amp;amp; (isRenderBlock() || isTableRow() || isTableSection())) {&lt;br /&gt;// Check for overflow clip.&lt;br /&gt;if (newStyle-&gt;overflowX() != OVISIBLE) {&lt;br /&gt;    if (!hadOverflowClip)&lt;br /&gt;        // Erase the overflow&lt;br /&gt;        repaint();&lt;br /&gt;    setHasOverflowClip();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;..............................................&lt;br /&gt;if (&lt;span style="font-weight: bold;"&gt;requiresLayer()&lt;/span&gt;) {&lt;br /&gt;if (!m_layer) {&lt;br /&gt;    if (wasFloating &amp;amp;&amp;amp; isFloating())&lt;br /&gt;        setChildNeedsLayout(true);&lt;br /&gt;    m_layer = new (renderArena()) RenderLayer(this);&lt;br /&gt;    setHasLayer(true);&lt;br /&gt;    m_layer-&gt;insertOnlyThisLayer();&lt;br /&gt;    if (parent() &amp;amp;&amp;amp; !needsLayout() &amp;amp;&amp;amp; containingBlock())&lt;br /&gt;        m_layer-&gt;updateLayerPositions();&lt;br /&gt;}&lt;br /&gt;} else if (m_layer &amp;amp;&amp;amp; !isRoot() &amp;amp;&amp;amp; !isRenderView()) {&lt;br /&gt;.......................................................&lt;br /&gt;}&lt;br /&gt;..................................................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool RenderObject::requiresLayer()&lt;br /&gt;{&lt;br /&gt;return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;isRoot() const { return document()-&gt;documentElement() == node(); }&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;isPositioned() const { return m_positioned; } // absolute or fixed positioning&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;isRelPositioned() const { return m_relPositioned; } // relative positioning&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;isTransparent() const { return style()-&gt;opacity() &lt;&gt;&lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;hasOverflowClip() const { return m_hasOverflowClip; }&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;hasTransform() const { return m_hasTransform; }&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;hasMask() const { return style() &amp;amp;&amp;amp; style()-&gt;hasMask(); }&lt;br /&gt;bool &lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;RenderObject::&lt;/span&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;hasReflection() const { return m_hasReflection; }&lt;br /&gt;&lt;br /&gt;通过上面的了解我们知道在setStyle时符合一定条件的RenderObject会创建RenderLayer对象，那么究竟什么是RenderLayer类，其有什么作用，下面作初步的介绍。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、RenderLayer树&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、类RenderLayer&lt;/span&gt;&lt;br /&gt;RenderLayer类其实是一个非常复杂并且很重要的类，其主要数据成员如下：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderLayer类主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/SUz3D2LlZTI/AAAAAAAAAEk/0_QjJRWBczQ/s1600-h/webkit-RenderLayer.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 189px; height: 400px;" src="http://3.bp.blogspot.com/_gp8441q4aEg/SUz3D2LlZTI/AAAAAAAAAEk/0_QjJRWBczQ/s400/webkit-RenderLayer.jpg" alt="" id="BLOGGER_PHOTO_ID_5281868108454520114" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图六&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;RenderLayer类主要与处理分层布局、渲染页面元素等相关如处理z-index、opacity等，只有符合一个条件的RenderObject才会创建RenderLayer对象，并且将这些RenderLayer对象组织成一颗树。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、构建RenderLayer树&lt;/span&gt;&lt;br /&gt;通过方法&lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;span&gt;insertOnlyThisLayer来组织这颗RenderLayer树。&lt;/span&gt;&lt;br /&gt;void RenderLayer::insertOnlyThisLayer()&lt;br /&gt;{&lt;br /&gt;if (!m_parent &amp;amp;&amp;amp; renderer()-&gt;parent()) {&lt;br /&gt;   // We need to connect ourselves when our renderer() has a parent.&lt;br /&gt;   // Find our enclosingLayer and add ourselves.&lt;br /&gt;   RenderLayer* parentLayer = renderer()-&gt;parent()-&gt;enclosingLayer();&lt;br /&gt;   RenderLayer* beforeChild = parentLayer-&gt;reflectionLayer() != this ? renderer()-&gt;parent()-&gt;findNextLayer(parentLayer, renderer()) : 0;&lt;br /&gt;   if (parentLayer)&lt;br /&gt;       parentLayer-&gt;addChild(this, beforeChild);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Remove all descendant layers from the hierarchy and add them to the new position.&lt;br /&gt;for (RenderObject* curr = renderer()-&gt;firstChild(); curr; curr = curr-&gt;nextSibling())&lt;br /&gt;   curr-&gt;moveLayers(m_parent, this);&lt;br /&gt;&lt;br /&gt;// Clear out all the clip rects.&lt;br /&gt;clearClipRects();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)&lt;br /&gt;{&lt;br /&gt;RenderLayer* prevSibling = beforeChild ? beforeChild-&gt;previousSibling() : lastChild();&lt;br /&gt;if (prevSibling) {&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;        child-&gt;setPreviousSibling(prevSibling);&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;        prevSibling-&gt;setNextSibling(child);&lt;/span&gt;&lt;br /&gt;} else&lt;br /&gt;   setFirstChild(child);&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;    if (beforeChild) {&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;        beforeChild-&gt;setPreviousSibling(child);&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;        child-&gt;setNextSibling(beforeChild);&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;    } else&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;        setLastChild(child);&lt;/span&gt;  &lt;span style="font-weight: bold;"&gt;    child-&gt;setParent(this);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;if (child-&gt;isOverflowOnly())&lt;br /&gt;   dirtyOverflowList();&lt;br /&gt;&lt;br /&gt;if (!child-&gt;isOverflowOnly() || child-&gt;firstChild()) {&lt;br /&gt;   // Dirty the z-order list in which we are contained.  The stackingContext() can be null in the&lt;br /&gt;   // case where we're building up generated content layers.  This is ok, since the lists will start&lt;br /&gt;   // off dirty in that case anyway.&lt;br /&gt;   RenderLayer* stackingContext = child-&gt;stackingContext();&lt;br /&gt;   if (stackingContext)&lt;br /&gt;       stackingContext-&gt;dirtyZOrderLists();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;child-&gt;updateVisibilityStatus();&lt;br /&gt;if (child-&gt;m_hasVisibleContent || child-&gt;m_hasVisibleDescendant)&lt;br /&gt;   childVisibilityChanged(true);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*&amp;amp; newObject,&lt;br /&gt;                 RenderLayer*&amp;amp; beforeChild)&lt;br /&gt;{&lt;br /&gt;if (obj-&gt;hasLayer()) {&lt;br /&gt;   if (!beforeChild &amp;amp;&amp;amp; newObject) {&lt;br /&gt;       // We need to figure out the layer that follows newObject.  We only do&lt;br /&gt;       // this the first time we find a child layer, and then we update the&lt;br /&gt;       // pointer values for newObject and beforeChild used by everyone else.&lt;br /&gt;       beforeChild = newObject-&gt;parent()-&gt;findNextLayer(parentLayer, newObject);&lt;br /&gt;       newObject = 0;&lt;br /&gt;   }&lt;br /&gt;   parentLayer-&gt;addChild(obj-&gt;layer(), beforeChild);&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for (RenderObject* curr = obj-&gt;firstChild(); curr; curr = curr-&gt;nextSibling())&lt;br /&gt;   addLayers(curr, parentLayer, newObject, beforeChild);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)&lt;br /&gt;{&lt;br /&gt;if (!parentLayer)&lt;br /&gt;   return;&lt;br /&gt;&lt;br /&gt;RenderObject* object = newObject;&lt;br /&gt;RenderLayer* beforeChild = 0;&lt;br /&gt;WebCore::addLayers(this, parentLayer, object, beforeChild);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderObject::removeLayers(RenderLayer* parentLayer)&lt;br /&gt;{&lt;br /&gt;if (!parentLayer)&lt;br /&gt;   return;&lt;br /&gt;&lt;br /&gt;if (hasLayer()) {&lt;br /&gt;   parentLayer-&gt;removeChild(layer());&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for (RenderObject* curr = firstChild(); curr; curr = curr-&gt;nextSibling())&lt;br /&gt;   curr-&gt;removeLayers(parentLayer);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)&lt;br /&gt;{&lt;br /&gt;if (!newParent)&lt;br /&gt;   return;&lt;br /&gt;&lt;br /&gt;if (hasLayer()) {&lt;br /&gt;   if (oldParent)&lt;br /&gt;       oldParent-&gt;removeChild(layer());&lt;br /&gt;   newParent-&gt;addChild(layer());&lt;br /&gt;   return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for (RenderObject* curr = firstChild(); curr; curr = curr-&gt;nextSibling())&lt;br /&gt;   curr-&gt;moveLayers(oldParent, newParent);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;通过上面一组方法我们可以了解到拥有RenderLayer对象的RenderObject对象，按照Render树中最近的原则将含有的RenderLayer对象依Render树对应的父子关系组织RenderLayer树，RenderLayer对象的存在是依附于RenderObject对象而存在。&lt;br /&gt;&lt;br /&gt;RenderView对象拥有对应的RenderLayer对象，同时其作为RenderLayer树根。&lt;br /&gt;&lt;htmltablecellelement*&gt;&lt;htmltablecolelement*&gt;&lt;span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、RenderLayer树与Render树的关系&lt;/span&gt;&lt;br /&gt;通过RenderContainer::addChild方法回过头再来具体看看Render树自身的构成。&lt;br /&gt;void RenderContainer::&lt;span style="font-weight: bold;"&gt;addChild&lt;/span&gt;(RenderObject* newChild, RenderObject* beforeChild)&lt;br /&gt;{&lt;br /&gt;bool needsTable = false;&lt;br /&gt;//检查是否为Table的情况&lt;br /&gt;if (needsTable) {&lt;br /&gt;......................................................&lt;br /&gt;} else {&lt;br /&gt;    // just add it...&lt;br /&gt;    insertChildNode(newChild, beforeChild);&lt;br /&gt;}&lt;br /&gt;.........................................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RenderContainer::&lt;span style="font-weight: bold;"&gt;insertChildNode&lt;/span&gt;(RenderObject* child, RenderObject* beforeChild, bool fullInsert)&lt;br /&gt;{&lt;br /&gt;if (!beforeChild) {&lt;br /&gt;    &lt;span style="font-weight: bold;"&gt;appendChildNode(child);&lt;/span&gt;&lt;br /&gt;    return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;while (beforeChild-&gt;parent() != this &amp;amp;&amp;amp; beforeChild-&gt;parent()-&gt;isAnonymousBlock())&lt;br /&gt;    beforeChild = beforeChild-&gt;parent();&lt;br /&gt;&lt;br /&gt;if (beforeChild == m_firstChild)&lt;br /&gt;    m_firstChild = child;&lt;br /&gt;&lt;br /&gt;RenderObject* prev = beforeChild-&gt;previousSibling();&lt;br /&gt;child-&gt;setNextSibling(beforeChild);&lt;br /&gt;beforeChild-&gt;setPreviousSibling(child);&lt;br /&gt;if(prev) prev-&gt;setNextSibling(child);&lt;br /&gt;child-&gt;setPreviousSibling(prev);&lt;br /&gt;&lt;br /&gt;child-&gt;setParent(this);&lt;br /&gt;&lt;br /&gt;if (fullInsert) {&lt;br /&gt;    // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children&lt;br /&gt;    // and don't have a layer attached to ourselves.&lt;br /&gt;    RenderLayer* layer = 0;&lt;br /&gt;    if (child-&gt;firstChild() || child-&gt;hasLayer()) {&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;            layer = enclosingLayer();&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;            child-&gt;addLayers(layer, child);&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // if the new child is visible but this object was not, tell the layer it has some visible content&lt;br /&gt;    // that needs to be drawn and layer visibility optimization can't be used&lt;br /&gt;    if (style()-&gt;visibility() != VISIBLE &amp;amp;&amp;amp; child-&gt;style()-&gt;visibility() == VISIBLE &amp;amp;&amp;amp; !child-&gt;hasLayer()) {&lt;br /&gt;        if (!layer)&lt;br /&gt;            layer = enclosingLayer();&lt;br /&gt;        if (layer)&lt;br /&gt;            layer-&gt;setHasVisibleContent(true);&lt;br /&gt;    }&lt;br /&gt;    ...........................................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;child-&gt;setNeedsLayoutAndPrefWidthsRecalc();&lt;br /&gt;if (!normalChildNeedsLayout())&lt;br /&gt;    setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.&lt;br /&gt;.................................................................&lt;br /&gt;}&lt;br /&gt;通过上面代码的了解我们知道通过addChild不仅维护Render树的构成，同时会将拥有的RenderLayer树构建起来。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、RenderLayer树的作用&lt;/span&gt;&lt;br /&gt;RenderLayer树的构建为渲染阶段处理z-index、opacity、overflow、scrollbar等打下一定的基础，在我们了解渲染的处理过程时我们再来深入的了解。&lt;br /&gt;&lt;br /&gt;在这里我们初步的了解到在构建Render树的同时会维护一颗RenderLayer树，为分层布局、渲染作准备。&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、总结&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;其 实WebKit涉及网页布局方面的数据结构还有关于SVG方面的，但通过上面的理解，如果对SVG感兴趣的话，应该对理解SVG有一定的参考作用。 当然数据结构方面还有相当多的内容未提及，这里只是列出一些关键类或结构，以便有个整体的抽象认识，希望能对了解WebKit的网页布局渲染有一定的基础性作用。&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://webkit.org/"&gt;The WebKit Open Source Project&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/htmltablecolelement*&gt;&lt;/htmltablecellelement*&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-5994415612904236069?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/5994415612904236069/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=5994415612904236069' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/5994415612904236069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/5994415612904236069'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/12/webkit.html' title='WebKit网页布局实现之主要数据结构篇之二'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_gp8441q4aEg/SUuQ6CYiISI/AAAAAAAAADk/jqX5LDjNhks/s72-c/webkit-RenderButton.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-6613553001846908264</id><published>2008-11-29T13:41:00.001+08:00</published><updated>2009-01-22T16:46:04.726+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='W3C标准'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='布局'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><title type='text'>WebKit网页布局实现之主要数据结构篇</title><content type='html'>在有了对CSS网页布局标准及相关概念的认识之后，我们可以更加深入的理解WebKit究竟是如何实现其网页布局，同时实现对CSS布局标准的支持。&lt;br /&gt;毕竟标准归标准，要高效的实现这些标准，不同的实现肯定有其不同的实现方式，就像不同的Web服务器对HTTP协议标准的实现有所不同一样，当然不同的实现也会增加一些自身特有的属性。&lt;br /&gt;下面我们从数据结构的角度来了解WebKit中为实现网页布局所设计的主要类结构及其主要方法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、Render树的构成&lt;/span&gt;&lt;br /&gt;在我们编写网页及使用JS的时候，大概都知道DOM树及其主要构成，了解到DOM树的构建其实质是对一个html或xml文件的内容采取树结构的方式来组织及描述，不同的标签及其在文档中的位置决定了其在整颗DOM树的地位及属性，针对具体DOM树的构成及不同树节点的描述，可以参考有关DOM的相关标准等，以后有机会我们也会单独来了解。&lt;br /&gt;&lt;br /&gt;也许对于Render树大家就不那么了解了，简单的说来，它是对DOM树更进一步的描述，其描述的内容主要与布局渲染等CSS相关属性如left、top、width、height、color、font等有关，因为不同的DOM树结点可能会有不同的布局渲染属性，甚至布局时会按照标准动态生成一些匿名节点，所以为了更加方便的描述布局及渲染，WebKit内核又生成一颗Render树来描述DOM树的布局渲染等特性，当然DOM树与Render树不是一一对应，但可以相互关联，下面分别描述其主要节点：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、基类RenderObject&lt;/span&gt;&lt;br /&gt;RenderObject作为所有Render树节点的基类，完全类似与DOM树中的Node基类，它是构成Render树的基础，作用非比寻常，其中包含了构成Render树所可能涉及到的一些基本属性及方法，内容相当多，其主要数据成员及方法分别如下：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderObject主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gp8441q4aEg/STDlvpHE7QI/AAAAAAAAACY/GPGCeS-0hCY/s1600-h/webkit-RenderObject.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 268px;" src="http://1.bp.blogspot.com/_gp8441q4aEg/STDlvpHE7QI/AAAAAAAAACY/GPGCeS-0hCY/s400/webkit-RenderObject.jpg" alt="" id="BLOGGER_PHOTO_ID_5273967770302999810" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;图一&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其中成员m_parent、m_previous、m_next为构建Render树设置好关联基础；&lt;br /&gt;m_Node则为DOM树中对应的节点；&lt;br /&gt;m_style成员则描述该节点对应的各种CSS基本属性数据，下面会单独介绍；&lt;br /&gt;至于其他的诸如m_positioned、m_isText、m_inline、m_floating、m_replaced等则描述其特性，就像CSS标准对不同元素的属性分类定义一样，从字面上我们就可以上一节&lt;a href="http://ourpgh.blogspot.com/2008/11/webkit.html"&gt;WebKit网页布局实现之基本概念及标准篇&lt;/a&gt;中可以找到它们这么定义的踪影。&lt;br /&gt;&lt;br /&gt;成员m_needsPositionedMovementLayout、m_normalChildNeedsLayout、m_posChildNeedsLayout、m_needsLayout等主要用来描述该RenderObject是否确实需要重新布局；&lt;br /&gt;当一个新的RenderObject对象插入到Render树的时候，它会设置其m_needsLayout属性为true，同时会根据该RenderObject对象在祖先RenderObject看来是一个positioned(拥有positiong:absolute或fixed属性)状态的孩子，如是则将相应祖先RenderObject对象的属性m_posChildNeedsLayout设置为true;&lt;br /&gt;&lt;br /&gt;如果是一个in-flow(positon:static或relative)状态的孩子，则将相应祖先RenderObject对象的属性m_normalChildNeedsLayout设置为true;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;主要方法：&lt;br /&gt;&lt;/span&gt;//与是否需要layout相关&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout ||m_posChildNeedsLayout; }&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;bool selfNeedsLayout() const { return m_needsLayout; }&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;bool posChildNeedsLayout() const { return m_posChildNeedsLayout; }&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;bool normalChildNeedsLayout() const { return m_normalChildNeedsLayout; }&lt;br /&gt;&lt;br /&gt;//与基本属性相关&lt;br /&gt;bool isFloating() const { return m_floating; }&lt;br /&gt;bool isPositioned() const { return m_positioned; } // absolute or fixed positioning&lt;br /&gt;bool isRelPositioned() const { return m_relPositioned; } // relative positioning&lt;br /&gt;bool isText() const  { return m_isText; }&lt;br /&gt;bool isInline() const { return m_inline; }  // inline object&lt;br /&gt;bool isCompact() const { return style()-&gt;display() == COMPACT; } // compact object&lt;br /&gt;bool isRunIn() const { return style()-&gt;display() == RUN_IN; } // run-in object&lt;br /&gt;bool isDragging() const { return m_isDragging; }&lt;br /&gt;bool isReplaced() const { return m_replaced; } // a "replaced" element (see CSS)&lt;br /&gt;&lt;br /&gt;//与外部DOM关联相关&lt;br /&gt;RenderView* view() const;&lt;br /&gt;// don't even think about making this method virtual!&lt;br /&gt;Node* element() const { return m_isAnonymous ? 0 : m_node; }&lt;br /&gt;Document* document() const { return m_node-&gt;document(); }&lt;br /&gt;void setNode(Node* node) { m_node = node; }&lt;br /&gt;Node* node() const { return m_node; }&lt;br /&gt;&lt;br /&gt;// RenderObject tree manipulation&lt;br /&gt;//////////////////////////////////////////&lt;br /&gt;virtual bool canHaveChildren() const;&lt;br /&gt;virtual bool isChildAllowed(RenderObject*, RenderStyle*) const { return true; }&lt;br /&gt;virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0);&lt;br /&gt;virtual void removeChild(RenderObject*);&lt;br /&gt;virtual bool createsAnonymousWrapper() const { return false; }&lt;br /&gt;&lt;br /&gt;// raw tree manipulation&lt;br /&gt;virtual RenderObject* removeChildNode(RenderObject*, bool fullRemove = true);&lt;br /&gt;virtual void appendChildNode(RenderObject*, bool fullAppend = true);&lt;br /&gt;virtual void insertChildNode(RenderObject* child, RenderObject* before, bool fullInsert = true);&lt;br /&gt;// Designed for speed.  Don't waste time doing a bunch of work like layer updating and repainting when we know that our&lt;br /&gt;// change in parentage is not going to affect anything.&lt;br /&gt;virtual void moveChildNode(RenderObject*);&lt;br /&gt;&lt;br /&gt;virtual void paint(PaintInfo&amp;amp;, int tx, int ty);&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;* This function should cause the Element to calculate its&lt;br /&gt;* width and height and the layout of its content&lt;br /&gt;*&lt;br /&gt;* when the Element calls setNeedsLayout(false), layout() is no&lt;br /&gt;* longer called during relayouts, as long as there is no&lt;br /&gt;* style sheet change. When that occurs, m_needsLayout will be&lt;br /&gt;* set to true and the Element receives layout() calls&lt;br /&gt;* again.&lt;br /&gt;*/&lt;br /&gt;virtual void layout() = 0;&lt;br /&gt;&lt;br /&gt;其中很多方法如paint()、layout()等是虚拟的，不同的子类可以重载它；&lt;br /&gt;&lt;br /&gt;其中方法container() 、containingBlock()、paint()、layout()很值得大家深入研究；&lt;br /&gt;&lt;br /&gt;总的说来RenderObject基类定义一些通用属性、方法，以便维护、布局、渲染Render树。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、子类RenderBox&lt;/span&gt;&lt;br /&gt;RenderBox代表描述CSS标准中的Box Model，它继承自RenderObject;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderBox主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gp8441q4aEg/STI0hndXzRI/AAAAAAAAACo/235It2macnY/s1600-h/webkit-RenderBox.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 346px;" src="http://2.bp.blogspot.com/_gp8441q4aEg/STI0hndXzRI/AAAAAAAAACo/235It2macnY/s400/webkit-RenderBox.jpg" alt="" id="BLOGGER_PHOTO_ID_5274335865736776978" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图二&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其主要重载了部分继承而来的方法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、子类RenderContainer&lt;/span&gt;&lt;br /&gt;RenderContainer类用来描述可以拥有子RenderObject成员的容器类，它继承自RenderBox；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderContainer主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gp8441q4aEg/STI3vlzZYsI/AAAAAAAAACw/mj3AIO4ivB8/s1600-h/webkit-RenderContainer.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 285px; height: 171px;" src="http://4.bp.blogspot.com/_gp8441q4aEg/STI3vlzZYsI/AAAAAAAAACw/mj3AIO4ivB8/s400/webkit-RenderContainer.jpg" alt="" id="BLOGGER_PHOTO_ID_5274339404345336514" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图三&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其主要重载了RenderObject提供的维护Render树新增、删除树节点等方面的方法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、子类RenderFlow&lt;/span&gt;&lt;br /&gt;RenderFlow主要用来描述CSS标准中提到的能进行inline-flow、block-flow相关处理的Render树结点，它继承自RenderContainer；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderFlow主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gp8441q4aEg/STI6g2NMnmI/AAAAAAAAAC4/3KzwHKzvcTM/s1600-h/webkit-RenderFlow.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 210px; height: 400px;" src="http://4.bp.blogspot.com/_gp8441q4aEg/STI6g2NMnmI/AAAAAAAAAC4/3KzwHKzvcTM/s400/webkit-RenderFlow.jpg" alt="" id="BLOGGER_PHOTO_ID_5274342449585364578" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图四&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其主要方法包括在flow的过程中创建、关联匿名对象等；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5、子类RenderBlock&lt;/span&gt;&lt;br /&gt;RenderBlock代表CSS标准中的block-level元素，它继承自RenderFlow；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderBlock主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/STI8aHva4_I/AAAAAAAAADA/nftii215H-Q/s1600-h/webkit-RenderBlock.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 285px; height: 278px;" src="http://3.bp.blogspot.com/_gp8441q4aEg/STI8aHva4_I/AAAAAAAAADA/nftii215H-Q/s400/webkit-RenderBlock.jpg" alt="" id="BLOGGER_PHOTO_ID_5274344533056480242" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图五&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;它维护了一组由它定位的positioned树节点，以及有关overflow方面的设置；&lt;br /&gt;其主要重载了RenderObject继承下来的layout、paint等方法；&lt;br /&gt;&lt;br /&gt;因为html中的body、div、p等标签对应RenderBlock类对象，其在Render树具有非常重要的地位，其layout、paint等方法的实现，往往是WebKit整个布局、渲染处理的发起中心，内容比较多并且复杂，以后有机会详解。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;6、子类RenderInline&lt;/span&gt;&lt;br /&gt;RenderInline代表inline-level元素，其继承自RenderFlow，主要重载了RenderObject关于inline-flow方面处理的方法，提供了splitFlow、splitInlines等处理自动换行的方法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;7、子类RenderText&lt;/span&gt;&lt;br /&gt;RenderText代表对html中Text node对应的Render树节点，它直接继承自RenderObject；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderText主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gp8441q4aEg/STJAyKNv_pI/AAAAAAAAADI/WJZkUotWYgQ/s1600-h/webkit-RenderText.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 376px; height: 400px;" src="http://4.bp.blogspot.com/_gp8441q4aEg/STJAyKNv_pI/AAAAAAAAADI/WJZkUotWYgQ/s400/webkit-RenderText.jpg" alt="" id="BLOGGER_PHOTO_ID_5274349344083934866" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图六&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;它提供关于处理文字方面如显示文字、行高计算、整个Text node对应的宽度等；它没有重载layout方法，因为它自身的定位往往由RenderBlock、RenderInline父对象来处理；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;8、子类RenderImage&lt;/span&gt;&lt;br /&gt;RenderImage代表html中img标签对应的树节点，它继承自RenderBox；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderImage继承关系及主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/STJDirzQkvI/AAAAAAAAADQ/VfVs_jms9pc/s1600-h/webkit-RenderImg.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 304px; height: 379px;" src="http://3.bp.blogspot.com/_gp8441q4aEg/STJDirzQkvI/AAAAAAAAADQ/VfVs_jms9pc/s400/webkit-RenderImg.jpg" alt="" id="BLOGGER_PHOTO_ID_5274352376756605682" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图七&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其主要提供关于图片显示、大小设置等方面的处理，其中paintReplaced方法将其图片显示出来；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;9、子类RenderView&lt;/span&gt;&lt;br /&gt;RenderView对应整个html文档对象的树节点，可看成是Render树的根，它继承自RenderBlock；&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;RenderView主要数据成员&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gp8441q4aEg/STJFsYAaLQI/AAAAAAAAADY/MongbjDPXKs/s1600-h/webkit-RenderView.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 350px; height: 400px;" src="http://4.bp.blogspot.com/_gp8441q4aEg/STJFsYAaLQI/AAAAAAAAADY/MongbjDPXKs/s400/webkit-RenderView.jpg" alt="" id="BLOGGER_PHOTO_ID_5274354742264999170" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;图八&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;其中m_frameview成员对应整个文档对应的FrameView，而m_widgets则包括了该文档可能包含的plugin插件等对应的Render树节点；&lt;br /&gt;&lt;br /&gt;RenderView对象作为Render树的根，它往往随着Document对象的创建而创建，它的layout、paint方法的发起往往是整颗Render树布局、渲染处理的开始；其中也包含了对选择处理。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;10、其他&lt;/span&gt;&lt;br /&gt;整个Render树中涉及的树节点类型，还有很多如RenderButton、RenderTable、RenderMedia等；并且各个类的方法及数据成员非常多，这里只是初步列出主要的类及其主要方法，特别是可能涉及到布局、渲染方方面的方法，以便我们能从中大致WebKit布局、渲染所涉及的基本内容及方法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、CSS属性的描述&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、RenderStyle类&lt;/span&gt;&lt;br /&gt;RenderObject对象的m_style成员为RenderStyle类对象，它往往用来描述一个RenderObject所可能涉及的CSS属性数据(如left、top、align、color、font等等)，其数据成员往往对应于CSS中定义的所有属性项，内容非常的庞杂，简单的说来就是将CSS标准中的所有属性按照一定分类定义到一个数据结构中。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、RenderStyle类主要方法&lt;/span&gt;&lt;br /&gt;为了获取、设置CSS属性所对应的值，RenderStyle类提供了所有的获取、设置CSS属性的方法如：&lt;br /&gt;void setDisplay(EDisplay v) {  noninherited_flags._effectiveDisplay = v; }&lt;br /&gt;void setOriginalDisplay(EDisplay v) {  noninherited_flags._originalDisplay = v; }&lt;br /&gt;void setPosition(EPosition v) {  noninherited_flags._position = v; }&lt;br /&gt;void setFloating(EFloat v) {  noninherited_flags._floating = v; }&lt;br /&gt;&lt;br /&gt;void setLeft(Length v)  {  SET_VAR(surround,offset.left,v) }&lt;br /&gt;void setRight(Length v) {  SET_VAR(surround,offset.right,v) }&lt;br /&gt;void setTop(Length v)   {  SET_VAR(surround,offset.top,v) }&lt;br /&gt;void setBottom(Length v){  SET_VAR(surround,offset.bottom,v) }&lt;br /&gt;&lt;br /&gt;void setWidth(Length v)  { SET_VAR(box,width,v) }&lt;br /&gt;void setHeight(Length v) { SET_VAR(box,height,v) }&lt;br /&gt;等等。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、RenderObject及子类对象的生成&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、CSSParser&lt;/span&gt;&lt;br /&gt;CSSParser类顾名思义，主要用来解析文本中各种CSS属性，并且有效的组织在一个RenderStyle对象中。&lt;br /&gt;其主要方法parseValue、applyProperty的部分代码示例如下：&lt;br /&gt;bool CSSParser::parseValue(int propId, bool important)&lt;br /&gt;{&lt;br /&gt;.....................................................&lt;br /&gt; case CSSPropertyFloat:            &lt;br /&gt; // left | right | none | inherit + center for buggy CSS&lt;br /&gt;     if (id == CSSValueLeft || id == CSSValueRight ||&lt;br /&gt;          id == CSSValueNone || id == CSSValueCenter)&lt;br /&gt;         valid_primitive = true;&lt;br /&gt;     break;&lt;br /&gt;&lt;br /&gt; case CSSPropertyClear:                // none | left | right | both | inherit&lt;br /&gt;     if (id == CSSValueNone || id == CSSValueLeft ||&lt;br /&gt;          id == CSSValueRight|| id == CSSValueBoth)&lt;br /&gt;         valid_primitive = true;&lt;br /&gt;     break;&lt;br /&gt; &lt;br /&gt; case CSSPropertyWebkitBoxAlign:&lt;br /&gt;     if (id == CSSValueStretch || id == CSSValueStart || id == CSSValueEnd ||&lt;br /&gt;         id == CSSValueCenter || id == CSSValueBaseline)&lt;br /&gt;         valid_primitive = true;&lt;br /&gt;     break;&lt;br /&gt;.....................................................&lt;br /&gt; case CSSPropertyWebkitBoxPack:&lt;br /&gt;     if (id == CSSValueStart || id == CSSValueEnd ||&lt;br /&gt;         id == CSSValueCenter || id == CSSValueJustify)&lt;br /&gt;         valid_primitive = true;&lt;br /&gt;     break;    &lt;br /&gt;....................................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void CSSStyleSelector::applyProperty(int id, CSSValue *value)&lt;br /&gt;{&lt;br /&gt; case CSSPropertyOpacity:&lt;br /&gt;     HANDLE_INHERIT_AND_INITIAL(opacity, Opacity)&lt;br /&gt;     if (!primitiveValue || primitiveValue-&gt;primitiveType() != CSSPrimitiveValue::CSS_NUMBER)&lt;br /&gt;         return; // Error case.&lt;br /&gt;     // Clamp opacity to the range 0-1&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;m_style&lt;/span&gt;-&gt;setOpacity(min(1.0f, max(0.0f, primitiveValue-&gt;getFloatValue())));&lt;br /&gt;     return;&lt;br /&gt; case CSSPropertyWebkitBoxAlign:&lt;br /&gt; {&lt;br /&gt;     HANDLE_INHERIT_AND_INITIAL(boxAlign, BoxAlign)&lt;br /&gt;     if (!primitiveValue)&lt;br /&gt;         return;&lt;br /&gt;     EBoxAlignment boxAlignment = *primitiveValue;&lt;br /&gt;     if (boxAlignment != BJUSTIFY)&lt;br /&gt;         &lt;span style="font-weight: bold;"&gt;m_style&lt;/span&gt;-&gt;setBoxAlign(boxAlignment);&lt;br /&gt;     return;&lt;br /&gt; }&lt;br /&gt;...................................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、CSSStyleSelector类&lt;/span&gt;&lt;br /&gt;CSSStyleSelector类其作用是基于所有用户的stylesheets集合为一个给定的DOM Element创建出其对应的RenderStyle对象。其主要功能由方法RenderStyle* styleForElement(Element*, RenderStyle* parentStyle = 0, bool allowSharing = true, bool resolveForRootDefault = false);来实现。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、构建Render树&lt;/span&gt;&lt;br /&gt;在构建DOM树的过程中，Dom Element对象创建完后，往往通过attach方法来创建RenderObject对象，进而构建Render树。&lt;br /&gt;其基本实现流程如下：void Element::attach()=&gt;createRendererIfNeeded()=&gt;createRenderer；&lt;br /&gt;&lt;br /&gt;RenderObject* Element::&lt;span style="font-weight: bold;"&gt;createRenderer&lt;/span&gt;(RenderArena* arena, RenderStyle* style)&lt;br /&gt;{&lt;br /&gt; if (document()-&gt;documentElement() == this &amp;amp;&amp;amp; style-&gt;display() == NONE) {&lt;br /&gt;     // Ignore display: none on root elements.  Force a display of block in that case.&lt;br /&gt;     RenderBlock* result = new (arena) RenderBlock(this);&lt;br /&gt;     if (result)&lt;br /&gt;         result-&gt;setAnimatableStyle(style);&lt;br /&gt;     return result;&lt;br /&gt; }&lt;br /&gt; return &lt;span style="font-weight: bold;"&gt;RenderObject::createObject&lt;/span&gt;(this, style);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;RenderObject* &lt;span style="font-weight: bold;"&gt;RenderObject::createObject&lt;/span&gt;(Node* node, RenderStyle* style)&lt;br /&gt;{&lt;br /&gt; Document* doc = node-&gt;document();&lt;br /&gt; RenderArena* arena = doc-&gt;renderArena();&lt;br /&gt;&lt;br /&gt; const ContentData* contentData = style-&gt;contentData();&lt;br /&gt; if (contentData &amp;amp;&amp;amp; !contentData-&gt;m_next &amp;amp;&amp;amp; contentData-&gt;m_type == CONTENT_OBJECT &amp;amp;&amp;amp; doc != node) {&lt;br /&gt;     RenderImageGeneratedContent* image = new (arena) RenderImageGeneratedContent(node);&lt;br /&gt;     image-&gt;setStyle(style);&lt;br /&gt;     if (StyleImage* styleImage = contentData-&gt;m_content.m_image)&lt;br /&gt;         image-&gt;setStyleImage(styleImage);&lt;br /&gt;     return image;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; RenderObject* o = 0;&lt;br /&gt;&lt;br /&gt; switch (style-&gt;display()) {//往往在CSSStyleSelector::styleForElement或CSSStyleSelector::adjustRenderStyle时//调用setDisplay()以确定其display属性。&lt;br /&gt;     case NONE:&lt;br /&gt;         break;&lt;br /&gt;     case &lt;span style="font-weight: bold;"&gt;INLINE&lt;/span&gt;:&lt;br /&gt;         o = new (arena) &lt;span style="font-weight: bold;"&gt;RenderInline&lt;/span&gt;(node);&lt;br /&gt;         break;&lt;br /&gt;     case &lt;span style="font-weight: bold;"&gt;BLOCK&lt;/span&gt;:&lt;br /&gt;         o = new (arena) &lt;span style="font-weight: bold;"&gt;RenderBlock&lt;/span&gt;(node);&lt;br /&gt;         break;&lt;br /&gt;     case &lt;span style="font-weight: bold;"&gt;INLINE_BLOCK&lt;/span&gt;:&lt;br /&gt;         o = new (arena) &lt;span style="font-weight: bold;"&gt;RenderBlock&lt;/span&gt;(node);&lt;br /&gt;         break;&lt;br /&gt;     case LIST_ITEM:&lt;br /&gt;         o = new (arena) RenderListItem(node);&lt;br /&gt;         break;&lt;br /&gt;     case RUN_IN:&lt;br /&gt;     case COMPACT:&lt;br /&gt;         o = new (arena) RenderBlock(node);&lt;br /&gt;         break;&lt;br /&gt;     case TABLE:&lt;br /&gt;     case INLINE_TABLE:&lt;br /&gt;         o = new (arena) RenderTable(node);&lt;br /&gt;         break;&lt;br /&gt;     case TABLE_ROW_GROUP:&lt;br /&gt;     case TABLE_HEADER_GROUP:&lt;br /&gt;     case TABLE_FOOTER_GROUP:&lt;br /&gt;         o = new (arena) RenderTableSection(node);&lt;br /&gt;         break;&lt;br /&gt;     case TABLE_ROW:&lt;br /&gt;         o = new (arena) RenderTableRow(node);&lt;br /&gt;         break;&lt;br /&gt;     case TABLE_COLUMN_GROUP:&lt;br /&gt;     case TABLE_COLUMN:&lt;br /&gt;         o = new (arena) RenderTableCol(node);&lt;br /&gt;         break;&lt;br /&gt;     case TABLE_CELL:&lt;br /&gt;         o = new (arena) RenderTableCell(node);&lt;br /&gt;         break;&lt;br /&gt;     case TABLE_CAPTION:&lt;br /&gt;         o = new (arena) RenderBlock(node);&lt;br /&gt;         break;&lt;br /&gt;     case BOX:&lt;br /&gt;     case INLINE_BOX:&lt;br /&gt;         o = new (arena) RenderFlexibleBox(node);&lt;br /&gt;         break;&lt;br /&gt; }&lt;br /&gt; return o;&lt;br /&gt;}&lt;br /&gt;这样就不同的DOM树节点结合不同的显示属性，创建出不同的RenderObject子类对象，进而形成一个Render树。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;其实WebKit涉及网页布局方面的数据结构远不止这些，其中有的也比较复杂，这里只是列出自己认为较为重要的一小部分，希望能对了解WebKit的网页布局渲染有一定的基础性作用。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://webkit.org/"&gt;The WebKit Open Source Project&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-6613553001846908264?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/6613553001846908264/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=6613553001846908264' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6613553001846908264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6613553001846908264'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/11/webkit_28.html' title='WebKit网页布局实现之主要数据结构篇'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_gp8441q4aEg/STDlvpHE7QI/AAAAAAAAACY/GPGCeS-0hCY/s72-c/webkit-RenderObject.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-5366353944686248282</id><published>2008-11-22T21:38:00.002+08:00</published><updated>2009-01-22T16:46:28.640+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='W3C标准'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='布局'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><title type='text'>WebKit网页布局实现之基本概念及标准篇</title><content type='html'>作为一个广受好评的浏览器引擎，其网页布局的质量(包括速度、效率、符合标准度等)往往是其关键，那么WebKit究竟是如何布局网页上的所有元素(包括滚动条、文字、图片、按钮、下拉框等)呢？其主要数据结构及流程都包括哪些呢？其布局的基本概念及标准都有哪些呢？下面分别介绍WebKit对其实现及运用。我们首先从关于布局的基本概念及标准的认识开始。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、CSS布局相关标准介绍&lt;/span&gt;&lt;br /&gt;其实我们对要素的布局都有不同程度的了解如我们使用Office时经常使用对一段文字的居中、靠左等操作，复杂一点有设置编号及文字与图片的环绕对应关系等，其实布局的关键在于确定页面元素的显示位置及大小，而页面中主要包括有文字、图片、按钮等页面元素，为了有效的组织布局这些页面元素，一些专家学者经过多年的摸索，总结并设计了布局这些元素所涉及的一些规则及标准，这就是CSS标准。&lt;br /&gt;&lt;br /&gt;其中&lt;a href="http://www.w3.org/TR/CSS21/visudet.html#containing-block-details" name="q0"&gt;Visual formatting model details&lt;/a&gt;对其主要规则进行过具体描述，通过下面相关总结和汇总希望能对其主要要点有一定的认识与理解。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、布局页面的基本概念&lt;/span&gt;&lt;br /&gt;要在一块指定的画布(或窗口)上布局一些要素，往往需要按从上到下或从左到右(或从右到左)的规则来布局这些元素，而有些元素则可以包含其他元素，当作布局容器来使用。其中浏览网页的原生窗口就可看作一个布局容器的根。&lt;br /&gt;&lt;br /&gt;由于页面内容的大小可能超过原生窗口提供的显示区域的大小，CSS中称页面上当前显示出来的区域为ViewPort，这个ViewPort相对页面的原始位置可通过滚动条来调整；&lt;br /&gt;&lt;br /&gt;CSS标准中定义了html中的一些标签所对应的元素可当成容器使用的，以建立坐标定位所包含的元素如p、div，CSS中称这样的元素为block-level元素，相邻的block-level元素往往从上到下垂直排列；&lt;br /&gt;&lt;br /&gt;而其他象i、a、b、span等标签及text node对应的元素则缺省为inline-level元素，inline-level元素不能用来定位其他元素，但可以包含其他同为inline-level元素，相邻的inline-level元素，往往按照从左到右或从右到左的水平方向排列；&lt;br /&gt;&lt;br /&gt;block-level元素所包含的元素往往要么全为block-level元素要么全为inline-level元素，在一定条件下布局时可能会产生匿名block-level元素；&lt;br /&gt;&lt;br /&gt;而页面上的每一个元素必须对应一个布局容器称之为Containing Block，只有block-level元素可以成为Containing Block；&lt;br /&gt;&lt;br /&gt;一个Containing Block元素究竟包含哪些子元素或者某一元素的Containing Block元素究竟是谁，由其自身position属性及其在文档层次结构中所处的位置所确定，下一节会描述相关内容；&lt;br /&gt;&lt;br /&gt;而每一个元素至少包含一个Box模型即由margin、border、padding、content width/height等属性所能描述的矩形区域；而这块区域相对于布局容器的坐标top、left，往往由布局容器按照block-flow、inline-flow等规则布局该元素时确定；&lt;br /&gt;&lt;br /&gt;CSS中将布局block-level元素的过程称为block-flow；将布局inline-level相关元素的过程称为line-flow；&lt;br /&gt;&lt;br /&gt;而CSS对html中诸如标签frame、image、object、embed、form等对应的元素称为replaced元素，它表示这些元素的内部布局不由Css来定义，而由浏览器来实现，而这些元素从外部来看相当于block-level元素，但可通过设置display:inline将其从外部看设为inline-level元素；&lt;br /&gt;&lt;br /&gt;不同的html标签元素可以通过display:inline、display:block、display:inline-block等方式来调整其缺省block-level或inline-level属性；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、如何确定页面元素显示位置&lt;/span&gt;&lt;br /&gt;一个html标签元素的position属性可以设置为static、relative、fixed、absolute、inherit等，所有元素缺省为static，其Containing Block布局容器元素为最近的祖先block-level元素，其属性left、top、right、bottom不起作用；&lt;br /&gt;&lt;br /&gt;position属性为relative的元素同static属性元素一样，但其left、top等属性可以有效，其坐标相对于布局容器而言；&lt;br /&gt;&lt;br /&gt;position属性为absolute的元素的布局容器元素是最近的除了其属性不为static的祖先block-level元素；&lt;br /&gt;&lt;br /&gt;position属性为fiexed的元素的布局容器元素是往往是根布局容器，但其定位坐标需要根据ViewPort的位置作相应调整；&lt;br /&gt;&lt;br /&gt;一旦确定了其Containing Block布局容器，同时结合其自身的block-level或inline-level特性，布局时根据block flow和inline flow规则就可确定其起始位置，其中inline-level元素可在其布局容器提供的区域内自动换行；而block-level元素可在其布局容器提供的区域内自动换一个段落。&lt;br /&gt;&lt;br /&gt;另外float属性为left或right元素较为特殊，则不遵守上面的规则，该元素让在其高度范围内的其他元素始终在其左边或右边。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、如何确定页面元素大小&lt;/span&gt;&lt;br /&gt;对于有定义其宽高的页面元素，则按照其定义的宽高来确定其大小，而对于象text node这样的inline-level则需要结合其字体大小及文字的多少等来确定其对应的宽高；如果页面元素所确定的宽高超过了布局容器Containing Block所能提供的宽高，同时其overflow属性为visible或auto，则会提供滚动条来保证可以显示其所有内容。&lt;br /&gt;&lt;br /&gt;除非定义了页面元素的宽高，一般说来页面元素的宽高是在布局的时候通过相关计算得出来的。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、如何理解z-index的使用&lt;/span&gt;&lt;br /&gt;页面元素z-index属性的出现，引入了页面元素三维布局的思路，提出分层的概念，具有同一z-index属性的所有元素按照上面提到的二维布局方式(确定其位置及大小)来布局，而不同z-index所代表的层的元素有可能被其他层的元素所覆盖。每一个页面元素只能处在一个z-index所对应的层中，所有元素缺省z-index为0。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、总结&lt;/span&gt;&lt;br /&gt;CSS布局标准的内容相当多，有的还相当复杂，这里只是初步的了解其基本原则及要素，也未必在各种条件下都成立，希望能为我们能从WebKit代码去了解WebKit究竟是如何布局页面元素作一定准备而已，如果要想对CSS标准有更深入的具体理解，只有不断的练习及阅读理解CSS布局标准文档。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;七、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets"&gt;CSS Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/CSS21/"&gt;CSS Specification&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.w3.org/TR/css3-box/"&gt;CSS basic box model&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.w3.org/TR/CSS21/visudet.html#containing-block-details" name="q0"&gt;Visual formatting model details&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-5366353944686248282?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/5366353944686248282/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=5366353944686248282' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/5366353944686248282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/5366353944686248282'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/11/webkit.html' title='WebKit网页布局实现之基本概念及标准篇'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-8074850708663343789</id><published>2008-10-29T20:58:00.000+08:00</published><updated>2008-11-02T20:39:03.192+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><title type='text'>也谈WebKit、Gecko使用图形库</title><content type='html'>阅读了&lt;a href="http://blog.chromium.org/2008/10/graphics-in-google-chrome.html"&gt;Graphics in Google Chrome&lt;/a&gt;之后，觉得作为浏览器内核WebKit、Gecko，为了能高效美观的显示页面的内容，选择适当的图形库非常重要。如果图形库选择不当，往往会导致页面上显示的文字、图片不美观，看起来总让人觉得别扭，更为糟糕的是排列布局出现紊乱，简直无法阅览。&lt;br /&gt;&lt;br /&gt;从浏览器发展的历史来看，IE系列浏览器的网页布局、文字图片显示的美观程度还是相当高的，也许这与Microsoft图形显示方面的功力相关，到目前为止linux桌面显示还是与传统的windows桌面显示有相当的差距。&lt;br /&gt;&lt;br /&gt;相比较Firefox1.5，Firefox3.0图形显示方面也有相当大的进步，这应该归功于完全采取Cario图形库来显示页面，目前应当完全达到了IE6的显示效果。可见图形显示的好与坏，直接决定了一款浏览器的质量以及用户接受程度。那究竟什么是图形库？其主要功能是什么？目前WebKit、Gecko可使用哪些图形库？它们在浏览器中是如何发挥其应有的作用呢？&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、图形库概述及其主要功能&lt;/span&gt;&lt;br /&gt;A graphics library is a program designed to aid in rendering computer graphics to a monitor. This typically involves providing optimized versions of functions that handle common rendering tasks.&lt;br /&gt;&lt;br /&gt;This can be done purely in software and running on the CPU, common in embedded systems, or being hardware accelerated by a GPU, more common in PCs. By employing these functions, a program can assemble an image to be output to a monitor. This relieves the programmer of the task of creating and optimizing these functions, and allows them to focus on building the graphics program.&lt;br /&gt;&lt;br /&gt;目前主要的图形库有：&lt;br /&gt;windows提供的GDI/GDI+、DirectX、OpenGL；&lt;br /&gt;支持X的有Cario、GTK、QT、OpenGL；&lt;br /&gt;其他的还有Skia(google提供)、Quartz 2D(apple提供)、wxWidget等；&lt;br /&gt;&lt;br /&gt;一般说来图形库只提供绘画图形，渲染文字、图片等，不管是2D还是3D，其往往不提供消息处理，简单的说来就是如何高效的在一块指定的画布上将线条、文字、图片显示出来，其中往往涉及字体、颜色等；典型的图形库如GDI/GDI+、Cario、DirectX、Quartz 2D等；&lt;br /&gt;&lt;br /&gt;而按钮、菜单、窗口等图形组件往往是基于图形库的基础上绘画出来的并有相对固定形状，同时一般具有消息处理功能；相关实现有GTK、QT、wxWidget、windows组件等；&lt;br /&gt;&lt;br /&gt;其中GTK、QT、wxWidget、Skia等不仅提供图形组件，同时提供图形库的功能；而Cario则是一个纯粹的图形库，类似与Quartz 2D，目前GTK2则完全基于Cario来实现；&lt;br /&gt;&lt;br /&gt;由于浏览器页面元素的数量存在不确定性，将页面上的一些元素对应成图形组件可能导致一个页面使用组件过多的问题(早期的IE就曾出现使用GDI对象过多的现象)。因此尽可能的将一个页面的所有元素显示在一个图形组件上，至于其显示交给图形库来处理，其消息响应交互交给DOM及原生窗口消息循环来完成。&lt;br /&gt;&lt;br /&gt;从这里我们可以进一步的确认图形库在浏览器中的重要性，以及随着用户需求的增加及硬件的提升，浏览器中使用3D效果应该是一个大的方向。&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;二、Gecko中使用图形库Cario&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、Cario概述&lt;/span&gt;&lt;br /&gt;Cairo is a 2D graphics library with support for multiple output devices. Currently supported output targets include the &lt;span style="font-weight: bold;"&gt;X Window System&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;Quartz&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;Win32&lt;/span&gt;, image buffers, PostScript, PDF, and SVG file output. Experimental backends include OpenGL (through &lt;a href="http://www.freedesktop.org/wiki/Software/glitz"&gt;glitz&lt;/a&gt;), XCB, BeOS, OS/2, and DirectFB.&lt;br /&gt;&lt;br /&gt;Cairo is designed to produce consistent output on all output media while taking advantage of display hardware acceleration when available (eg. through the X Render Extension).&lt;br /&gt;&lt;br /&gt;其主要优点在于其在X、Win32、Quartz的基础上统一了图形库的操作方式，同时支持PS、PDF、SVG、PNG/JPEG等图像格式的输出，极大的方便页面的再次利用，在glitz的支持下支持部分3D效果。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、Cario在Gecko中的使用&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;首先&lt;/span&gt;提供一个gfxASurface抽象类，代表一块可以作画的画布；提供一个gfxContext类，它用来管理究竟如何作画，如画圆形、旋转，维护画布的状态、当前颜色、路径等，其往往需要一个gfxASurface子类实例来初始化；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;其次&lt;/span&gt;不同的图形输出实现不同的gfxASurface子类如gfxWindowsSurface、gfxXlibSurface、gfxQuartzSurface、gfxGlitzSurface、gfxQuartzPDFSurface、gfxPSSurface等；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;其次&lt;/span&gt;提供一个DeviceContextImpl类实现nsIDeviceContext接口，以描述指定原生Widget相关的字体属性及创建可以在该原生Widget上作画的nsIRenderingContext接口实现；&lt;br /&gt;&lt;br /&gt;而nsThebesRenderingContext类实现了nsIRenderingContext接口，以供外部(如不同的DOM Node页面元素对应的不同Frame)在其上显示文字、图像、作图形等;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;然后&lt;/span&gt;当解析、布局完DOM页面元素后需要画出不同的页面元素时则由DeviceContextImpl类实例来创建nsThebesRenderingContext类实现，并初始化它，其初始化代码如下：&lt;br /&gt;nsThebesRenderingContext::Init(nsIDeviceContext* aContext, nsIWidget *aWidget)&lt;br /&gt;{&lt;br /&gt;nsThebesDeviceContext *thebesDC = static_cast&lt;nsthebesdevicecontext*&gt;(aContext);&lt;br /&gt;&lt;br /&gt;mDeviceContext = aContext;&lt;br /&gt;mWidget = aWidget;&lt;br /&gt;&lt;br /&gt;mThebes = &lt;span style="font-weight: bold;"&gt;new gfxContext&lt;/span&gt;(aWidget-&gt;&lt;span style="font-weight: bold;"&gt;GetThebesSurface()&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;return (CommonInit());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;nsThebesRenderingContext类中包含：&lt;br /&gt;nsRefPtr&lt;gfxcontext&gt; mThebes;&lt;br /&gt;nsCOMPtr&lt;nsiwidget&gt; mWidget;&lt;br /&gt;而mThebes初始时需要的gfxASurface子类实例则由原生的Widget的GetThebesSurface()方法来实现，针对不同的图形输出实现返回不同的gfxASurface子类如gfxWindowsSurface、gfxXlibSurface、gfxQuartzSurface、gfxGlitzSurface的实例；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;最后&lt;/span&gt;将nsThebesRenderingContext类实现实例返回，由不同的Frame自身决定如何在提供的画布上画出其表示的内容。&lt;br /&gt;&lt;br /&gt;至于不同的Frame应该怎么画(显示)由其本身及CSS来决定，而nsIRenderingContext接口提供了所有可能用到的作画方式，具体每一个方法的含义需详细了解。&lt;br /&gt;&lt;br /&gt;nsIRenderingContext接口提供了一组方法，向外部提供了图形库能实现的功能，其相当于一个中间层，从图形库的角度看，通过这个接口向外部提供了其能提供的功能；从需要图形功能的外部看，可不关心具体图形库的实现，而直接通过该接口使用图形库能提供的功能。&lt;br /&gt;&lt;br /&gt;让我们来看看&lt;/nsiwidget&gt;&lt;/gfxcontext&gt;&lt;/nsthebesdevicecontext*&gt;nsIRenderingContext接口究竟有哪些主要方法？&lt;br /&gt;// RenderingContext interface&lt;br /&gt;class nsIRenderingContext : public nsISupports&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;.........................................................................&lt;br /&gt;/**&lt;br /&gt;* Initialize the RenderingContext&lt;br /&gt;* @param aContext the device context to use.&lt;br /&gt;* @param aWidget the widget to hook up to&lt;br /&gt;* @result The result of the initialization, NS_Ok if no errors&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD Init(nsIDeviceContext* aContext, nsIWidget *aWidget) = 0;&lt;br /&gt;/**&lt;br /&gt;* Get the DeviceContext that this RenderingContext was initialized&lt;br /&gt;* with.  This function addrefs the device context.  Though it might&lt;br /&gt;* be better if it just returned it directly, without addrefing.&lt;br /&gt;* @result the device context&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD GetDeviceContext(nsIDeviceContext *&amp;amp; aDeviceContext) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Sets the forground color for the RenderingContext&lt;br /&gt;* @param aColor The color to set the RenderingContext to&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD SetColor(nscolor aColor) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Get the forground color for the RenderingContext&lt;br /&gt;* @return The current forground color of the RenderingContext&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD GetColor(nscolor &amp;amp;aColor) const = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Sets the font for the RenderingContext&lt;br /&gt;* @param aFont The font to use in the RenderingContext&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD SetFont(const nsFont&amp;amp; aFont, nsIAtom* aLangGroup) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Sets the font for the RenderingContext&lt;br /&gt;* @param aFontMetric The font metrics representing the&lt;br /&gt;*        font to use in the RenderingContext&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD SetFont(nsIFontMetrics *aFontMetrics) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Get the current fontmetrics for the RenderingContext&lt;br /&gt;* @return The current font of the RenderingContext&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD GetFontMetrics(nsIFontMetrics *&amp;amp;aFontMetrics) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;*  Add in a translate to the RenderingContext's transformation matrix&lt;br /&gt;* @param aX The horizontal translation&lt;br /&gt;* @param aY The vertical translation&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD Translate(nscoord aX, nscoord aY) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;*  Add in a scale to the RenderingContext's transformation matrix&lt;br /&gt;* @param aX The horizontal scale&lt;br /&gt;* @param aY The vertical scale&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD Scale(float aSx, float aSy) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Draw a line&lt;br /&gt;* @param aXO starting horiztonal coord in twips&lt;br /&gt;* @param aY0 starting vertical coord in twips&lt;br /&gt;* @param aX1 end horiztonal coord in twips&lt;br /&gt;* @param aY1 end vertical coord in twips&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Draw a rectangle&lt;br /&gt;* @param aRect The rectangle to draw&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD DrawRect(const nsRect&amp;amp; aRect) = 0;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Draw a string in the RenderingContext&lt;br /&gt;* @param aString The string to draw&lt;br /&gt;* @param aLength The length of the aString&lt;br /&gt;* @param aX Horizontal starting point of baseline&lt;br /&gt;* @param aY Vertical starting point of baseline.&lt;br /&gt;* @param aSpacing inter-character spacing to apply&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD &lt;span style="font-weight: bold;"&gt;DrawString&lt;/span&gt;(const char *aString, PRUint32 aLength,&lt;br /&gt;                     nscoord aX, nscoord aY,&lt;br /&gt;                     const nscoord* aSpacing = nsnull) = 0;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;* Tiles an image over an area&lt;br /&gt;* @param aImage       Image to tile&lt;br /&gt;* @param aXImageStart x location where the origin (0,0) of the image starts&lt;br /&gt;* @param aYImageStart y location where the origin (0,0) of the image starts&lt;br /&gt;* @param aTargetRect  area to draw to&lt;br /&gt;* @param aSubimageRect the subimage (in tile space) which we expect to&lt;br /&gt;* sample from; may be null to indicate that the whole image is&lt;br /&gt;* OK to sample from&lt;br /&gt;*/&lt;br /&gt;NS_IMETHOD &lt;span style="font-weight: bold;"&gt;DrawTile&lt;/span&gt;(imgIContainer *aImage,&lt;br /&gt;                   nscoord aXImageStart, nscoord aYImageStart,&lt;br /&gt;                   const nsRect * aTargetRect,&lt;br /&gt;                   const nsIntRect * aSubimageRect) = 0;&lt;br /&gt;...............................................................................&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;其中DrawString、DrawTile方法最常用，其分别对应如何显示文字及图像。&lt;br /&gt;针对图形库显示文字的基本原理可以参考&lt;a href="http://hackyourway.net/2008/07/30/font-technology-and-freetype/"&gt;Font technology and Freetype&lt;/a&gt;及&lt;a href="http://freetype.sourceforge.net/freetype2/docs/glyphs/index.html"&gt;FreeType Glyph Conventions&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;至于图形库如何显示不同格式的图像可参考如&lt;a href="http://en.wikipedia.org/wiki/Graphics_Interchange_Format"&gt;gif&lt;/a&gt;、&lt;a href="http://en.wikipedia.org/wiki/Jpeg"&gt;jpeg&lt;/a&gt;、&lt;a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics"&gt;png&lt;/a&gt;等。&lt;br /&gt;&lt;br /&gt;Gecko对Cario的使用还体现在对canvas标签的实现，具体可参考nsCanvasRenderingContext2D.cpp、nsHTMLCanvasElement.cpp等。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、WebKit中使用图形库&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、WebKit支持的图形库&lt;/span&gt;&lt;br /&gt;目前WebKit支持的图形库包括Cairo、Gtk、Qt、Wx、Cg、Mac、Skia等，虽然不同的图形库能支持不同的平台，但其在不同平台上的显示效果也不尽相同。至于在一个指定的平台上究竟使用何种库，则显示出很大的灵活性。就目前来看，在windows平台上可选的图形库有Cairo、Qt、Wx、Cg、Skia等，其中&lt;a href="http://blog.chromium.org/2008/10/graphics-in-google-chrome.html"&gt;Graphics in Google Chrome&lt;/a&gt;阐述了Chrome关于图形库的选择。&lt;br /&gt;&lt;br /&gt;其实从WebKit的角度来看，它通过提供一组与Gecko中nsIRenderingContext类似的公共图形接口，而不同的图形库则根据自身的不同实现了这些公共图形接口，以提供给WebCore元素使用，从而可以让WebKit支持不同的图形库。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、WebKit支持不同图形库的实现&lt;/span&gt;&lt;br /&gt;在WebKit中提供了一个GraphicsContext类，其中包括所有的图形接口，完全类似nsIRenderingContext，针对不同平台的特性，其定义中包含一些不同平台特有的&lt;br /&gt;宏及元素定义。&lt;br /&gt;&lt;br /&gt;在目录webcore\platform\graphics\下的子目录Cairo、Cg、Gtk、Mac、Qt、Win、Wx分别提供了GraphicsContext类部分方法的实现，而公共的实现则在webcore\platform\graphics\GraphicsContext.cpp中提供。&lt;br /&gt;&lt;br /&gt;其中我们非常值得关注的方法有drawText与drawImage，其实现如下：&lt;br /&gt;void GraphicsContext::drawText(const TextRun&amp;amp; run, const IntPoint&amp;amp; point, int from, int to)&lt;br /&gt;{&lt;br /&gt;  if (paintingDisabled())&lt;br /&gt;      return;&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;font().drawText&lt;/span&gt;(this, run, point, from, to);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void GraphicsContext::drawImage(Image* image, const FloatRect&amp;amp; dest, const FloatRect&amp;amp; src, CompositeOperator op, bool useLowQualityScale)&lt;br /&gt;{&lt;br /&gt;  if (paintingDisabled() || !image)&lt;br /&gt;      return;&lt;br /&gt;&lt;br /&gt;  float tsw = src.width();&lt;br /&gt;  float tsh = src.height();&lt;br /&gt;  float tw = dest.width();&lt;br /&gt;  float th = dest.height();&lt;br /&gt;   &lt;br /&gt;  if (tsw == -1)&lt;br /&gt;      tsw = image-&gt;width();&lt;br /&gt;  if (tsh == -1)&lt;br /&gt;      tsh = image-&gt;height();&lt;br /&gt;&lt;br /&gt;  if (tw == -1)&lt;br /&gt;      tw = image-&gt;width();&lt;br /&gt;  if (th == -1)&lt;br /&gt;      th = image-&gt;height();&lt;br /&gt;&lt;br /&gt;  if (useLowQualityScale) {&lt;br /&gt;      save();&lt;br /&gt;      setUseLowQualityImageInterpolation(true);&lt;br /&gt;  }&lt;br /&gt; &lt;span style="font-weight: bold;"&gt; image-&gt;draw&lt;/span&gt;(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op);&lt;br /&gt;  if (useLowQualityScale)&lt;br /&gt;      restore();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;最终的实现转交给类Font、Image的方法drawText、draw来实现，而不同实现如Cairo、Cg、Gtk、Mac、Qt、Win、Wx则会针对类Font、Image分别提供部分对应的实现，而公共的实现则在webcore\platform\graphics\Font.cpp及Image.cpp中提供。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、不同平台GraphicsContext实例创建及使用&lt;/span&gt;&lt;br /&gt;GraphicsContext创建的时机往往在对应平台的WebView获得Paint消息事件时，进而将该GraphicsContext类实例传递给FrameView及其不同的RenderObject实例，由不同的RenderObject实例来决定究竟如何来显示自身的内容，而GraphicsContext类实例提供了各种的显示文字、图形、图像的方法以供RenderObject实例调用。其调用关系基本上与Gecko中的不同Frame对象使用nsIRenderingContext接口方法类似。&lt;br /&gt;&lt;br /&gt;创建GraphicsContext实例的示例如下：&lt;br /&gt;//Gtk&lt;br /&gt;static gboolean webkit_web_view_expose_event(GtkWidget* widget, GdkEventExpose* event)&lt;br /&gt;{&lt;br /&gt;  WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);&lt;br /&gt;  WebKitWebViewPrivate* priv = webView-&gt;priv;&lt;br /&gt;&lt;br /&gt;  Frame* frame = core(webView)-&gt;mainFrame();&lt;br /&gt;  GdkRectangle clip;&lt;br /&gt;  gdk_region_get_clipbox(event-&gt;region, &amp;amp;clip);&lt;br /&gt;  cairo_t* cr = gdk_cairo_create(event-&gt;window);&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;GraphicsContext ctx(cr);&lt;/span&gt;&lt;br /&gt;  ctx.setGdkExposeEvent(event);&lt;br /&gt;  if (frame-&gt;contentRenderer() &amp;amp;&amp;amp; frame-&gt;view()) {&lt;br /&gt;      frame-&gt;view()-&gt;layoutIfNeededRecursive();&lt;br /&gt;&lt;br /&gt;      if (priv-&gt;transparent) {&lt;br /&gt;          cairo_save(cr);&lt;br /&gt;          cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);&lt;br /&gt;          cairo_paint(cr);&lt;br /&gt;          cairo_restore(cr);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      frame-&gt;view()-&gt;paint(&amp;amp;ctx, clip);&lt;br /&gt;  }&lt;br /&gt;  cairo_destroy(cr);&lt;br /&gt;&lt;br /&gt;  return FALSE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//win&lt;br /&gt;void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect&amp;amp; dirtyRect)&lt;br /&gt;{&lt;br /&gt;  LOCAL_GDI_COUNTER(0, __FUNCTION__);&lt;br /&gt;&lt;br /&gt;  RECT rect = dirtyRect;&lt;br /&gt;&lt;br /&gt;#if FLASH_BACKING_STORE_REDRAW&lt;br /&gt;  HDC dc = ::GetDC(m_viewWindow);&lt;br /&gt;  OwnPtr&lt;hbrush&gt; yellowBrush = CreateSolidBrush(RGB(255, 255, 0));&lt;br /&gt;  FillRect(dc, &amp;amp;rect, yellowBrush.get());&lt;br /&gt;  GdiFlush();&lt;br /&gt;  Sleep(50);&lt;br /&gt;  paintIntoWindow(bitmapDC, dc, dirtyRect);&lt;br /&gt;  ::ReleaseDC(m_viewWindow, dc);&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;  FillRect(bitmapDC, &amp;amp;rect, (HBRUSH)GetStockObject(WHITE_BRUSH));&lt;br /&gt;  if (frameView &amp;amp;&amp;amp; frameView-&gt;frame() &amp;amp;&amp;amp; frameView-&gt;frame()-&gt;contentRenderer()) {&lt;br /&gt;      &lt;span style="font-weight: bold;"&gt;GraphicsContext gc(bitmapDC);&lt;/span&gt;&lt;br /&gt;      gc.save();&lt;br /&gt;      gc.clip(dirtyRect);&lt;br /&gt;      frameView-&gt;paint(&amp;amp;gc, dirtyRect);&lt;br /&gt;      gc.restore();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//wx&lt;br /&gt;void wxWebView::OnPaint(wxPaintEvent&amp;amp; event)&lt;br /&gt;{&lt;br /&gt;  if (m_beingDestroyed || !m_impl-&gt;frame-&gt;view() || !m_impl-&gt;frame)&lt;br /&gt;      return;&lt;br /&gt;&lt;br /&gt;  wxAutoBufferedPaintDC dc(this);&lt;br /&gt;&lt;br /&gt;  if (IsShown() &amp;amp;&amp;amp; m_impl-&gt;frame &amp;amp;&amp;amp; m_impl-&gt;frame-&gt;document()) {&lt;br /&gt;#if USE(WXGC)&lt;br /&gt;      wxGCDC gcdc(dc);&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;      if (dc.IsOk()) {&lt;br /&gt;          wxRect paintRect = GetUpdateRegion().GetBox();&lt;br /&gt;&lt;br /&gt;          WebCore::IntSize offset = m_impl-&gt;frame-&gt;view()-&gt;scrollOffset();&lt;br /&gt;#if USE(WXGC)&lt;br /&gt;          gcdc.SetDeviceOrigin(-offset.width(), -offset.height());&lt;br /&gt;#endif&lt;br /&gt;          dc.SetDeviceOrigin(-offset.width(), -offset.height());&lt;br /&gt;          paintRect.Offset(offset.width(), offset.height());&lt;br /&gt;&lt;br /&gt;#if USE(WXGC)&lt;br /&gt;          WebCore::GraphicsContext* gc = &lt;span style="font-weight: bold;"&gt;new WebCore::GraphicsContext(&amp;amp;gcdc);&lt;/span&gt;&lt;br /&gt;#else&lt;br /&gt;          WebCore::GraphicsContext* gc = &lt;span style="font-weight: bold;"&gt;new WebCore::GraphicsContext((wxWindowDC*)&amp;amp;dc);&lt;/span&gt;&lt;br /&gt;#endif&lt;br /&gt;          if (gc &amp;amp;&amp;amp; m_impl-&gt;frame-&gt;contentRenderer()) {&lt;br /&gt;              if (m_impl-&gt;frame-&gt;view()-&gt;needsLayout())&lt;br /&gt;                  m_impl-&gt;frame-&gt;view()-&gt;layout();&lt;br /&gt;&lt;br /&gt;              m_impl-&gt;frame-&gt;paint(gc, paintRect);&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//Qt&lt;br /&gt;void QWebFrame::render(QPainter *painter, const QRegion &amp;amp;clip)&lt;br /&gt;{&lt;br /&gt;  if (!d-&gt;frame-&gt;view() || !d-&gt;frame-&gt;contentRenderer())&lt;br /&gt;      return;&lt;br /&gt;&lt;br /&gt;  d-&gt;frame-&gt;view()-&gt;layoutIfNeededRecursive();&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;GraphicsContext ctx(painter);&lt;/span&gt;&lt;br /&gt;  QVector&lt;qrect&gt; vector = clip.rects();&lt;br /&gt;  WebCore::FrameView* view = d-&gt;frame-&gt;view();&lt;br /&gt;  for (int i = 0; i &lt;&gt;paint(&amp;amp;ctx, vector.at(i));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*!&lt;br /&gt;Render the frame into \a painter.&lt;br /&gt;*/&lt;br /&gt;void QWebFrame::render(QPainter *painter)&lt;br /&gt;{&lt;br /&gt;  if (!d-&gt;frame-&gt;view() || !d-&gt;frame-&gt;contentRenderer())&lt;br /&gt;      return;&lt;br /&gt;&lt;br /&gt;  d-&gt;frame-&gt;view()-&gt;layoutIfNeededRecursive();&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;GraphicsContext ctx(painter);&lt;/span&gt;&lt;br /&gt;  WebCore::FrameView* view = d-&gt;frame-&gt;view();&lt;br /&gt;  view-&gt;paint(&amp;amp;ctx, view-&gt;frameGeometry());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、WebKit 3D Port实现&lt;/span&gt;&lt;br /&gt;在&lt;a href="http://trac.webkit.org/wiki/clutter"&gt;Clutter WebKit port&lt;/a&gt;中提供了WebKit 对3D Port的支持与实现，其实现类似于Gtk+/Cairo图形库的实现，但其3D效果仅实现在Port层，没有对页面上的元素如文字、图像实现3D效果支持。&lt;br /&gt;&lt;br /&gt;这里只是简单的了解WebKit中如何整合不同的图形库及其与WebCore的交互。要想更加深入的了解页面上的文字、图形、图像究竟是如何显示出来的，则需要更进一步的针对不同平台库进行学习与了解。&lt;br /&gt;&lt;br /&gt;WebKit中也支持canvas标签，该标签提供的接口与Gecko能提供的几乎一致，其具体实现可参考webcore\html \CanvasRenderingContext2D.cpp，结合GraphicsContext类的实现，应该能对canvas标签的实现有充分的理 解。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;其实关于图形库及其使用的内容非常的多，而对浏览器内核来讲能对图形库进行高效使用也是非常重要的一部分，所以在这里所谈到的内容也许只是一些皮毛，但希望能在此开阔一下了解浏览器内核特别是图形库使用方面的思路。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、参考资源&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Rendering_%28computer_graphics%29"&gt;Wiki Rendering (computer graphics)&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Cairo_%28graphics%29"&gt;Wiki Cairo&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://cairographics.org/"&gt;Cairo HomePage&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Qt_%28toolkit%29"&gt;Wiki Qt&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/GTK%2B"&gt;Wiki GTK+&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/WxWidgets"&gt;Wiki wxWidgets&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Graphics_Device_Interface"&gt;Wiki GDI&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/DirectX"&gt;Wiki DirectX&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Quartz_2D"&gt;Wiki Quartz 2D&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/OpenGL"&gt;Wiki OpenGL&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/OpenGL_ES"&gt;Wiki OpenGL ES&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Graphics_Interchange_Format"&gt;Wiki gif&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Jpeg"&gt;Wiki jpeg&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics"&gt;Wiki png&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.clutter-project.org/"&gt;&lt;br /&gt;Clutter Toolkit&lt;/a&gt;&lt;br /&gt;&lt;a href="http://hackyourway.net/2008/07/30/font-technology-and-freetype/"&gt;Font technology and Freetype&lt;/a&gt;&lt;nsthebesdevicecontext*&gt;&lt;gfxcontext&gt;&lt;nsiwidget&gt;&lt;br /&gt;&lt;/nsiwidget&gt;&lt;/gfxcontext&gt;&lt;/nsthebesdevicecontext*&gt;&lt;/qrect&gt;&lt;/hbrush&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-8074850708663343789?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/8074850708663343789/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=8074850708663343789' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/8074850708663343789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/8074850708663343789'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/10/webkitgecko.html' title='也谈WebKit、Gecko使用图形库'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-4168771290942533668</id><published>2008-10-18T15:58:00.000+08:00</published><updated>2008-10-18T20:01:32.778+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='调试'/><title type='text'>Javascript调试工具</title><content type='html'>Javascript作为一门脚本语言，最近受到人们越来越多的关注，例如Chrome推出V8、Mozilla推出TracMonky、WebKit推出SquirrelFish等等Javascript引擎，使得Javascript实现的性能不断的得到提升，甚至更有Microsoft高级开发人员认为Silverlight的对手竟然是Javascript，而不是Flash，还有诸如Gears、prototype、dojo、jquery等JS库的大力发展，可见Javascript的应用前景相当光明。&lt;br /&gt;&lt;br /&gt;但是其复杂性也会越来越高，Web开发人员遇到大量的Javascript往往会觉得头痛，甚至觉得Javascript比较诡异而又神奇，从而难以彻底掌握应用好。不过要掌握好Javascript的应用，其调试是个不得不提的话题，很早以前Microsoft就推出了Script Debugger工具，但Web开发人员使用起来还不是特别的方便，作为一个Web开发应用平台的推动者，Mozilla社区却为我们提供了更优秀的Javascript Debugger工具Venkman、Firebug，它们的出现极大的方便了Javascript的调试，让开发人员爱不释手，将它们比着Web开发的瑞士军刀一点都不为过。&lt;br /&gt;&lt;br /&gt;今天我们从Venkman、Firebug的使用入手，进而分析其实现原理，同时了解了解WebKit内核的Javascript调试工具及其实现原理。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、安装使用Venkman、Firebug&lt;/span&gt;&lt;br /&gt;如果你还没使用过它们，现在就该动手了。赶快去Mozilla Addon中心下载&lt;a href="https://addons.mozilla.org/zh-CN/firefox/addon/216"&gt;JavaScript Debugger Venkman&lt;/a&gt;、&lt;a href="https://addons.mozilla.org/zh-CN/firefox/addon/1843"&gt;Firebu&lt;/a&gt;&lt;a href="https://addons.mozilla.org/zh-CN/firefox/addon/1843"&gt;g&lt;/a&gt;吧。作为Firefox的extension，Venkman、Firebug不管是下载、安装、更新及使用，都已经与Firefox进行有机结合，使用起来非常的方便。&lt;br /&gt;&lt;br /&gt;作为调试工具，其基本的功能不外乎设置断点、Step-in、Step-out、Step-over、Continue、查看参数及调用堆栈等。操作上与用VS调试C/C++代码几乎一致，但考虑各自特点的不同，下面总结一下个人对这两个工具的使用感受：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、&lt;/span&gt;Firebug非常适合普通的Web开发人员，它可以非常方便、直观的查看html、js、dom等详细内容，查看js执行效率以及网络获取状态等，更值得称赞的是调试时动态更改html、js、dom的内容后，浏览效果会及时显现，从而大大的提供修改、调试效率。&lt;br /&gt;&lt;br /&gt;网上一篇&lt;a href="http://www.ooso.net/index.php/archives/294"&gt;《初识Firebug 全文 — firebug的使用》&lt;/a&gt;很值得刚接触者参考参考。&lt;br /&gt;有关Firebug更加详细的内容请参考&lt;a href="http://getfirebug.com/"&gt;Firebug网站&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、&lt;/span&gt;Venkman非常适合与Firefox开发相关的开发者如extension开发者等，虽然它的使用没有Firebug那么的直观方便动态更改内容，但其提供了完整的命令行调试模式，这一点与python的pdb很类似；更为突出的是它可以调试Firefox本身以及各种extensions(即chrome源文件，这一点目前Firebug还难以方便的处理)，同时提供方便的过滤功能。有了Venkman，开发研究Firefox(当然包括各种有特色的extension及js库等)也就得心应手。&lt;br /&gt;&lt;br /&gt;其中&lt;a href="http://www.svendtofte.com/code/learning_venkman/index.php"&gt;Learning the JavaScript debugger Venkman&lt;/a&gt;对Venkman有非常详细的介绍，很值得好好阅读阅读。&lt;br /&gt;&lt;br /&gt;有关Venkman更加详细的使用请参考其&lt;a href="http://www.mozilla.org/projects/venkman/"&gt;&lt;/a&gt;&lt;a href="http://www.mozilla.org/projects/venkman/"&gt;HomePage&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、&lt;/span&gt;使用Venkman、Firebug调试Javascript有时会出现一些异常，没有象用Vs、gdb调试C/C++那样的稳定，也许与其本身的实现有些相关，毕竟是调试脚本语言。下面了解一下其实现也许能解除你的一些困惑。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、Venkman实现&lt;/span&gt;&lt;br /&gt;Venkman作为一个extension，其实现完全基于js+xul等相关技术实现。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、&lt;/span&gt;UI&lt;br /&gt;考虑所调试内容的多样性，Venkman UI方面的实现充分的利用了Gecko中的Overlay、XBL等技术要素，同时其显示的项目及其菜单等都是动态生成，界面风格类似于VS，各个显示区域可动态调整、组装。&lt;br /&gt;&lt;br /&gt;可以具体关注一下Venkman-bindings.xml、Venkman.xul、Venkman-overlay.xul等实现；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、调试逻辑控制&lt;/span&gt;&lt;br /&gt;整个Gecko内核调试逻辑控制由一个实现了接口Components.interfaces.jsdIDebuggerService，CTRID为 "@mozilla.org/js/jsd/debugger-service;1"的XPCOM组件，其提供的主要接口如下：&lt;br /&gt;interface jsdIDebuggerService : nsISupports&lt;br /&gt;{&lt;br /&gt;...........................................&lt;br /&gt;    /**&lt;br /&gt;     * Called when an error or warning occurs.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIErrorHook     errorHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called when a jsdIScript is created or destroyed.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIScriptHook    scriptHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called when the engine encounters a breakpoint.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIExecutionHook breakpointHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called when the engine encounters the debugger keyword.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIExecutionHook debuggerHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called when the errorHook returns false.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIExecutionHook debugHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called before the next PC is executed.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIExecutionHook interruptHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called when an exception is thrown (even if it will be caught.)&lt;br /&gt;     */&lt;br /&gt;    attribute jsdIExecutionHook throwHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called before and after a toplevel script is evaluated.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdICallHook topLevelHook;&lt;br /&gt;    /**&lt;br /&gt;     * Called before and after a function is called.&lt;br /&gt;     */&lt;br /&gt;    attribute jsdICallHook functionHook;&lt;br /&gt;    attribute unsigned long flags;&lt;br /&gt;    attribute boolean initAtStartup;&lt;br /&gt;    readonly attribute boolean isOn;&lt;br /&gt;    /**&lt;br /&gt;     * Turn on the debugger. &lt;br /&gt;     */&lt;br /&gt;    void on ();&lt;br /&gt;    [noscript] void onForRuntime (in JSRuntime rt);&lt;br /&gt;    void off ();&lt;br /&gt;    readonly attribute unsigned long pauseDepth;&lt;br /&gt;    unsigned long pause();&lt;br /&gt;    unsigned long unPause();&lt;br /&gt;    /**&lt;br /&gt;     * Force the engine to perform garbage collection.&lt;br /&gt;     */&lt;br /&gt;    void GC();&lt;br /&gt;    void DumpHeap(in string fileName);&lt;br /&gt;    void clearProfileData();&lt;br /&gt;    /**&lt;br /&gt;     * Adds an execution hook filter. */&lt;br /&gt;    void insertFilter (in jsdIFilter filter, in jsdIFilter after);&lt;br /&gt;    /**&lt;br /&gt;     * Same as insertFilter, except always add to the end of the list.&lt;br /&gt;     */&lt;br /&gt;    void appendFilter (in jsdIFilter filter);&lt;br /&gt;....................................................&lt;br /&gt;    void enumerateContexts (in jsdIContextEnumerator enumerator);&lt;br /&gt;    void enumerateScripts (in jsdIScriptEnumerator enumerator);&lt;br /&gt;    void clearAllBreakpoints ();&lt;br /&gt;    jsdIValue wrapValue (/*in jsvalue value*/);&lt;br /&gt;   &lt;br /&gt;    /**&lt;br /&gt;     * Push a new network queue, and enter a new UI event loop.&lt;br /&gt;     */&lt;br /&gt;    unsigned long enterNestedEventLoop (in jsdINestCallback callback);&lt;br /&gt;    /**&lt;br /&gt;     * Exit the current nested event loop after the current iteration completes,&lt;br /&gt;     * and pop the network event queue.&lt;br /&gt;     */&lt;br /&gt;    unsigned long exitNestedEventLoop ();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;调试过程主要控制流程如下：&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、&lt;/span&gt;由Debugger(如Venkman)发起调试开始，调用DebuggerService.on方法，DebuggerService创建JSDContext，与当前JSRuntimer建立联系，并将DebuggerService中方法设置为当前JSRuntimer的&lt;span style="font-weight: bold;"&gt;globalDebugHooks&lt;/span&gt;对应元素的Hook(即设置回调函数指针)；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、&lt;/span&gt;Debugger将DebuggerService中的errorHook、scriptHook、breakpointHook、debuggerHook、debugHook、interruptHook、throwHook等Hook设置成Debugger提供的方法；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、&lt;/span&gt;当JS引擎执行解析、调用JS脚本时，发现其&lt;span style="font-weight: bold;"&gt;globalDebugHooks&lt;/span&gt;中有对应回调Hook，如每解析完一个JS Function时就会调用newScriptHook，进而由DebuggerService调用Debugger提供的scriptHook，Debugger的scriptHook会根据JS引擎提供的文件名、函数名、行号等，读出对应文件显示出来；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、&lt;/span&gt;当在指定文件对应行设置一个断点时，Debugger由DebuggerService调用JS引擎向指定的函数调用Frame中设置Trap操作码；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5、&lt;/span&gt;一旦JS引擎执行到Trap操作码，则会调用其&lt;span style="font-weight: bold;"&gt;globalDebugHooks&lt;/span&gt;中对应的回调Hook，进而调用DebuggerService breakpointHook，从而调用Debugger的debugTrap，其中会根据当时的调用上下文调用DebuggerService的DebuggerService的EnterNestedEventLoop方法，它往往会维护一个嵌套计数，然后作事件处理循环，其主要代码如下：&lt;br /&gt;jsdService::EnterNestedEventLoop (jsdINestCallback *callback, PRUint32 *_rval)&lt;br /&gt;{&lt;br /&gt;    // Nesting event queues is a thing of the past.  Now, we just spin the&lt;br /&gt;    // current event loop.&lt;br /&gt;    nsresult rv;&lt;br /&gt;    nsCOMPtr&lt;nsijscontextstack&gt;&lt;br /&gt;        stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &amp;amp;rv));&lt;br /&gt;    if (NS_FAILED(rv))        return rv;&lt;br /&gt;    PRUint32 nestLevel = ++mNestedLoopLevel;&lt;br /&gt;    nsCOMPtr&lt;nsithread&gt; thread = do_GetCurrentThread();&lt;br /&gt;    if (NS_SUCCEEDED(stack-&gt;Push(nsnull))) {&lt;br /&gt;        if (callback) {&lt;br /&gt;            Pause(nsnull);&lt;br /&gt;            rv = callback-&gt;OnNest();&lt;br /&gt;            UnPause(nsnull);&lt;br /&gt;        }&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;        while (NS_SUCCEEDED(rv) &amp;amp;&amp;amp; mNestedLoopLevel &gt;= nestLevel) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;            if (!NS_ProcessNextEvent(thread))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;                rv = NS_ERROR_UNEXPECTED;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;        }&lt;/span&gt;&lt;br /&gt;        JSContext* cx;&lt;br /&gt;        stack-&gt;Pop(&amp;amp;cx);&lt;br /&gt;        NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");&lt;br /&gt;    }&lt;br /&gt;    else  rv = NS_ERROR_FAILURE;&lt;br /&gt;    NS_ASSERTION (mNestedLoopLevel &lt;= nestLevel,&lt;br /&gt;                  "nested event didn't unwind properly");&lt;br /&gt;    if (mNestedLoopLevel == nestLevel)&lt;br /&gt;        --mNestedLoopLevel;&lt;br /&gt;    *_rval = mNestedLoopLevel;&lt;br /&gt;    return rv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;其中的事件处理循环很关键，在处理事件时被调试的JS脚本无法继续进行执行(即Block)，而Debugger仍然可以处理UI事件，如显示当前CallFrame、查看变量值等；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;6、&lt;/span&gt;当遇到断点时，用户通过Step-in或Step-out等触发JS引擎调用CallHook等，进而根据嵌套计数跳出上面的处理循环，而进入另一个循环或调试结束。&lt;br /&gt;&lt;br /&gt;说明：整个过程与传统的windbg、gdb与OS、硬件协同完成Debug过程的实现非常类似，只不过这里的JS引擎相当与OS，它们都非常清楚源文件与具体执行点之间的对应和当时的上下文信息；一样由debugger来提供一些Hook给JS引擎或OS，当JS引擎或OS遇到Trap指令或异常等，它们会及时调用debugger提供的Hook，以由debugger给出下一步执行的决定。&lt;br /&gt;&lt;br /&gt;但它们之间有个最大的不同在于JS debugger与运行的被debug的JS脚本都处于同一浏览器进程中；而windbg、gdb调试程序时debugger与被debug的程序往往处于不同的进程。&lt;br /&gt;&lt;br /&gt;这里就导致JS debugger中需要过滤的问题，因为不可能在同一进程中调试自己(如用Venkman调试Venkman或用Firebug调试Firebug)，这个过滤的动作往往由debugger来决定什么样的源文件可以设置断点、可对其函数进行Step-in、Step-out等，Venkman与Firebug的过滤机制不一样，导致Firebug不能调试chrome类的源文件。&lt;br /&gt;&lt;br /&gt;Firebug有关调试方面的实现与Venkman很类似，一样需要利用DebuggerService来实现交互，有时间可具体参考参考。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、WebKit Javascript调试实现&lt;/span&gt;&lt;br /&gt;其实现逻辑与Gecko差不多，首先由Javascript实现提供一个Debugger接口类(相关于Gecko中的DebugHook)，然后由一个实现了该Debugger接口的JavaScriptDebugServer来控制调试窗口与被调试页面之间的关系。&lt;br /&gt;&lt;br /&gt;一旦JS引擎遇到解析完JS函数、设置的断点、开始函数调用、结束函数调用等则通知(或回调)调试窗口，以控制下一步的操作。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://trac.webkit.org/wiki/Drosera"&gt;Drosera-Webkit-Trac&lt;/a&gt;对其中的设计有一定的说明。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;对一个开发人员来讲，不管是Web开发、还是Java、C/C++开发，乃至内核、驱动开发等，调试是一门必须掌握的技术，因为它不仅能让你提高工作效率，同时能让你更加深入的了解掌握计算机技术；如果能更一步的了解调试工作原理，则会让你如虎添翼。有空可以看看《软件调试》、《How debuggers work》等。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/venkman/"&gt;Venkman HomePage&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.svendtofte.com/code/learning_venkman/index.php"&gt;Learning the JavaScript debugger Venkman&lt;/a&gt;&lt;br /&gt;&lt;a href="http://getfirebug.com/"&gt;Firebug HomePage&lt;/a&gt;&lt;br /&gt;&lt;a href="http://trac.webkit.org/wiki/Drosera"&gt;Drosera-Webkit-Trac&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Debugger"&gt;Wiki Debugger&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/GNU_Debugger"&gt;Wiki GNU_Debugger(GDB)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/WinDbg" title="WinDbg"&gt;Wiki WinDbg&lt;/a&gt;&lt;br /&gt;&lt;a href="http://advdbg.org/"&gt;Advanced Debugging(高端调试)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-4168771290942533668?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/4168771290942533668/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=4168771290942533668' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4168771290942533668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4168771290942533668'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/10/javascript.html' title='Javascript调试工具'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-1507126609855828414</id><published>2008-10-15T18:40:00.000+08:00</published><updated>2008-10-16T09:36:57.616+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Gears'/><category scheme='http://www.blogger.com/atom/ns#' term='Extension'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='扩展'/><category scheme='http://www.blogger.com/atom/ns#' term='插件'/><title type='text'>认识了解Gears</title><content type='html'>前一段时间对Google Chrome有过简单的认识与了解，在&lt;a href="http://ourpgh.blogspot.com/2008/09/google-chrome.html"&gt;体验新鲜出炉的Google Chrome浏览器&lt;/a&gt;中提到Google的&lt;a style="font-weight: bold;" href="http://www.google.com/googlebooks/chrome/index.html"&gt;Google Chrome Comic&lt;/a&gt;，其中提出通过Gears来扩展Web应用，但究竟什么是Gears以及其如何来扩展浏览器等，一直令人好奇。通过了解Gears应该可以了解Google将来究竟主推怎样的方式来扩展Web应用，当然包括Chrome浏览器及Android等，因为个人一直认为Gecko内核对扩展的支持非常方便、灵活、实用(具体可参考与Gecko相关的文档)，但对基于WebKit内核的扩展相对来说不是那么的方便与直接，为了满足探究感，让我们开始了解Gears之旅吧。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是Gears?&lt;/span&gt;&lt;br /&gt;Gears is an open source project that enables more powerful web applications, by adding new features to web browsers.&lt;br /&gt;&lt;br /&gt;目前主要提供一组JS API以供Web应用使用，对应Web开发者来说其类似于prototype、dojo、jquery等JS库，但其实现是通过扩展浏览器来实现(不仅仅包含js代码还包含二进制代码等)。&lt;br /&gt;&lt;br /&gt;主要的API模块有：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;   A Database module (powered by SQLite) that can store data locally.&lt;/li&gt;&lt;li&gt;   A WorkerPool module that provides parallel execution of JavaScript code.&lt;/li&gt;&lt;li&gt;   A LocalServer module that caches and serves application resources (HTML, JavaScript, images, etc).&lt;/li&gt;&lt;li&gt;   A Desktop module that lets web applications interact more naturally with the desktop.&lt;/li&gt;&lt;li&gt;   A Geolocation module that lets web applications detect the geographical location of their users.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;通过&lt;a href="http://code.google.com/p/gears/"&gt;Google Gears&lt;/a&gt;可以了解Gears的发展及目前开发状态等，其中有些已实现或打算实现的API还是非常有意思的如Geolocation、Audio、Camera等，一旦这些API能完善好的话确实非常有利于Web应用的扩展，比如说录音、摄像等。&lt;br /&gt;&lt;br /&gt;如果对扩展Web应用如开发RIA等有兴趣的话，可以好好考虑哪些应用或业务，可以或需要扩展到Web上来，通过了解Gears，说不定Gears能给您很大的启发。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、如何利用Gears?&lt;/span&gt;&lt;br /&gt;利用Gears，首先需要用户安装Gears如对Firefox来讲就是一个extension，对Chrome、Safari来讲是一个符合NPAPI的插件，对IE来讲就是一个ActiveX；其次利用Gears API开发相关应用页面，以供最终用户使用。&lt;br /&gt;&lt;br /&gt;也许对最终用户来讲稍嫌麻烦，需要额外安装程序，但如果Gears能象Flash一样实用、好用，那时就不再会觉得很麻烦啦。&lt;br /&gt;&lt;br /&gt;对开发者来讲利用Gears相对就简单啦。在页面包含&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt;script src="gears_init.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt;script&amp;gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;if (!window.google || !google.gears) {&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;location.href = "http://gears.google.com/?action=install&amp;amp;message=&amp;lt;your welcome message&amp;gt;" +&lt;span style="font-family:monospace;"&gt; &lt;/span&gt;    "&amp;amp;return=&amp;lt;your website url&amp;gt;";&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;}&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;span style="font-family:Georgia,serif;"&gt;然后就可以使用其中的API啦。&lt;br /&gt;&lt;br /&gt;具体可参考&lt;a href="http://code.google.com/apis/gears/tools.html#gears_init"&gt;Gears Resources and Tools&lt;/a&gt;中的gears_init.js、samples及其他API等文档。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、初步探究Gears基本实现原理&lt;/span&gt;&lt;br /&gt;通过初步了解&lt;a href="http://code.google.com/apis/gears/gears_init.js"&gt;Get gears_init.js&lt;/a&gt;可以基本了解Gears提供对IE、Firefox、Chrome、Safari等支持，但其实现方式各有不同。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、对各浏览器的支持&lt;/span&gt;&lt;br /&gt;对Firefox来讲，Gears扩展了一个GearsFactory JS对象，可供JS脚本直接调用，从JS的角度看相对于给window对象新增了一个对象，就像原先的document、navigator对象一样使用，只不过其功能不同而已。&lt;br /&gt;&lt;br /&gt;对IE来讲，Gears扩展了一个Gears.Factory ActiveX对象，可通过JS脚本new ActiveXObject('Gears.Factory');来直接调用，从JS的角度看可以象使用XMLHttpRequest对象一样使用Gears.Factory。&lt;br /&gt;&lt;br /&gt;对Chrome、Safari来讲，就有点特殊啦，也有点诡异的感觉。需要在当前文档动态添加一个MIMEType为application/x-googlegears的Object插件对象，而这个Object对象就是对应的google.gears.factory对象。&lt;br /&gt;&lt;br /&gt;从这里就可以看出WebKit对扩展JS的支持，从架构设计不是那么的直接，需要由NPAPI插件机制来中转实现；而Firefox、IE都从架构上提供了相应扩展机制来扩展，相当的直接明了及与浏览器本身的统一。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、google.gears.factory对Firefox支持的实现&lt;/span&gt;&lt;br /&gt;从&lt;a href="http://ourpgh.blogspot.com/2008/07/geckojavascript.html"&gt;浅谈Gecko关键部分之六认识javascript实现及应用&lt;/a&gt;中我们可以了解到Gecko中XPCOM组件通过xpconnect及对DOMCLASSINFO的定义，就可轻松的将XPCOM组件Binding给JS使用，就像Gecko中对Components、Components.Interfaces、xmlhttprequest等的实现。&lt;br /&gt;&lt;br /&gt;在Gears中就是使用了类似的方式来Binding一个GearsFactory组件给JS环境使用。其中实现了一个实现了GearsFactoryInterface接口的名称为GearsFactory，ContractId 为"@google.com/gears/factory;1"的组件，具体代码详见gears\factory\Factory_ff.cc，然后在gears\base\firefox\Module.cc中注册该组件时使用&lt;br /&gt;catMgr-&gt;AddCategoryEntry(JAVASCRIPT_DOM_CLASS,&lt;br /&gt;                    kGearsFactoryClassName,&lt;br /&gt;                    kDomciExtensionContractId,&lt;br /&gt;                    PR_TRUE, PR_TRUE, NULL);&lt;br /&gt;将该组件声明为需要由xpconnect Binding给JS使用。一旦启用xpconnect，xpconnect就会作相应处理，具体可参考nsDOMClassInfo::RegisterExternalClasses()等方法。这样就完成JS GearsFactory对象的实现。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、google.gears.factory对Safari支持的实现&lt;/span&gt;&lt;br /&gt;从&lt;a href="http://ourpgh.blogspot.com/2008/09/webkitjavascriptcorev8.html"&gt;浅谈WebKit之JavaScriptCore/V8篇&lt;/a&gt;中我们可以知道WebKit中将DOM实现Binding给Javascript实现往往通过generate-bindings.pl生成的代码来静态Binding，这种方式无法满足动态Binding的需求。但是从&lt;a href="http://ourpgh.blogspot.com/2008/07/geckoplugin.html"&gt;浅谈Gecko关键部分之九Plugin&lt;/a&gt;中我们了解到NPAPI插件接口提供了一组接口可以将插件的接口动态Binding给JS环境，同时可以让插件与JS之间相互调用。&lt;br /&gt;&lt;br /&gt;而WebKit中实现了对NPAPI插件接口的支持，这样Gears中实现了一个mimetype为application/x-googlegears的插件，将该插件对象当作google.gears.factory JS对象来提供给页面使用。&lt;br /&gt;&lt;br /&gt;具体可参考gears\base\npapi\Module.cc、Npp_bindings.cc，其中的NPP_New()方法应该是主要入口，同时设置该插件为windowless。至于如何将插件的方法动态Binding给JS使用，可具体参考Webkit中对NPN_CreateObject、NPClass的实现支持等。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、google.gears.factory对IE支持的实现&lt;/span&gt;&lt;br /&gt;按照创建ActiveX及BHO等接口方法来实现Gears.Factory ActiveX，进而将该对象赋值给google.gears.factory。具体关于ActiveX及BHO相关的知识参考Microsoft文档。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5、对其他API接口的实现&lt;/span&gt;&lt;br /&gt;虽然google.gears.factory实现了create、getBuildInfo、version等接口，但对通过create创建出来的提供给开发人员用的localserver、geolocation、httprequest、audio等对象是如何实现的呢？&lt;br /&gt;&lt;br /&gt;体现Gears强大及方便的地方就在这里。Gears提供了一组统一的类及接口实现可以方便将自定义的类及接口Binding给对应浏览器的JS实现。针对Firefox，它通过扩展SpiderMonkey的方式直接扩展JS实现；针对Safari，它还是使用NPAPI、NPObject的方式来扩展。&lt;br /&gt;&lt;br /&gt;具体可以参考一下gears\base\common\Js_runner_np.cc、Js_runner_ff.cc、Js_runner_ie.cc等；&lt;br /&gt;&lt;br /&gt;这一组统一扩展JS实现的类及接口有：ModuleImplBaseClass、ModuleWrapperBaseClass、DispatcherInterface、Dispatcher、MarshaledModule、ModuleEnvironment等，其作用就是按照统一的方式方便的将自定义的类及接口Binding给不同的浏览器实现。&lt;br /&gt;&lt;br /&gt;如果对这方面有兴趣，可以对这些类及接口之间的关系及实现进一步研究，看Gears究竟是如何将C/C++类实现Binding给JS。其实这一点对JS来讲非常有意义，因为一旦可轻松方便的扩展JS，那么JS的应用就会进一步的扩大，就象python一样，python脚本可以方便扩充其模块，C/C++类库也可方便的扩充成python模块，从而让python几乎无所不能。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、如何扩展Gears API?&lt;/span&gt;&lt;br /&gt;在初步了解Gears实现原理之后，正与&lt;a href="http://code.google.com/p/gears/wiki/CreatingNewModules?redir=1"&gt;Gears CreatingNewModules&lt;/a&gt;所描述，我们也可以利用Gears来扩展自己的API，在了解其他API的实现基础上，其实扩展一个自己的Gears API难度似乎并不太大。。。&lt;br /&gt;&lt;br /&gt;期望大家有时间可以加入到Google Gears中来一起拓展Web应用。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、总结&lt;/span&gt;&lt;br /&gt;通过对Gears的初步了解，觉得Gears对浏览器的扩展主要体现在对JS方面的扩展，相当于&lt;span style="font-weight: bold;"&gt;JS功能库&lt;/span&gt;的扩充，并且主要体现在非UI方面，虽然其中有部分UI方面的内容，但相当少；而Adobe推出的flash、Microsoft推出的Silverlight主要是按照插件的方式基于html标准的embed/object进行扩充，往往涉及到UI方面，并都有自身的特色如内嵌脚本语言、播放video/audio、网络处理等等；而Gecko所拥有的extension确可以是全方位的(包括UI、xpcom、插件等等)。&lt;br /&gt;&lt;br /&gt;目前随着Ajax及RIA的推广，各式各样的JS库如prototype、dojo、jquery等也层出不穷，但是针对JS功能库方面的扩展还没有一个相对通用的国际标准，也许Gears正好抓住这样一个发展的趋势才采取这种通过扩展JS接口，为开发人员提供API的方式来扩展Web应用。&lt;br /&gt;&lt;br /&gt;Gears API一方面迎合了RIA等方面的需求，另一方面也推动浏览器的扩展。但是它似乎抛弃了UI方面的扩展如使用Gecko的XUL、Microsoft XAML等的可能，也许flash对UI方面有太多的优势，同时html5中的video/audio逐步提上日程，做一个类似于Silverlight的插件意义不大，还不如在JS方面下足功夫，同时全面拥抱html(如gmail、gmap、gdoc等)，也许这就是Google目前对扩展Web应用的一点看法吧。。。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;参考&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/gears/"&gt;Gears Project&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Google_Gears"&gt;Wiki Gears(software)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-1507126609855828414?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/1507126609855828414/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=1507126609855828414' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1507126609855828414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1507126609855828414'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/10/gears.html' title='认识了解Gears'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-2282431142170284851</id><published>2008-10-08T13:48:00.000+08:00</published><updated>2008-10-08T22:44:38.377+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='移植'/><category scheme='http://www.blogger.com/atom/ns#' term='Port'/><category scheme='http://www.blogger.com/atom/ns#' term='WebCore'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedding'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='嵌入'/><title type='text'>浅谈WebKit之Port篇</title><content type='html'>WebKit作为一个浏览器引擎，其相对于Gecko而言一个较大的特点就是便于移植，嵌入到其他程序中，目前大家已了解使用WebKit引擎的应用包括Safari、iPhone、Chrome、Android、Nokia S60 Browser及KDE QT4.4等，同时还有其他方面的移植如Gtk、wxWidget、3D等，可以说WebKit从架构上讲其Port移植方面的设计及应用，是非常优秀的。这一点相对于Gecko有相当大的优势，有时间可以参考一下&lt;a set="yes" linkindex="19" href="http://ourpgh.blogspot.com/2008/08/geckoembedding.html"&gt;浅谈Gecko关键部分之十二Embedding&lt;/a&gt;。为了更深入的了解WebKit，我们现在就从WebKit有关Ports方面入手，了解其有关Port方面的设计，从而了解究竟如何能移植WebKit到自己的应用中。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、有关Port方面的概述&lt;/span&gt;&lt;br /&gt;在通过了解&lt;a set="yes" linkindex="28" href="http://ourpgh.blogspot.com/2008/09/webkitwebcore.html"&gt;浅谈WebKit之WebCore篇&lt;/a&gt;之后，应该说WebKitPort方面的内容是可以很广的，例如可将不同的图形库、网络库与WebCore集成，提供不同的Port接口供外部程序使用等，例如同样在windows平台上可以运行的Google Chrome和Safari就是针对WebKit的不同移植。&lt;br /&gt;&lt;br /&gt;我们想了解有关Port方面的主要内容在于提供不同的Port接口供外部程序使用以及如何与外部程序交互，因为WebKit中的其它两部分WebCore、Javascript实现，从逻辑上讲是不直接提供接口给外部程序使用的。同时为了完成浏览器的核心功能，WebKit也需要从外部程序中通过Port接口的方式获取一些支持。&lt;br /&gt;&lt;br /&gt;从这个角度讲WebKit作为一个相对独立的整体，它与外部程序之间的交互也就有一组相对固定的接口来定义及维护它们之间的关系，它们之间的关系与插件跟浏览器引擎之间的关系完全类似，接口相当一组协议，有的是由WebKit来实现，而供外部程序调用；有的的正好相反。&lt;br /&gt;&lt;br /&gt;通过前面的了解我们知道WebKit的主要功能集中在分析Html、渲染布局Web内容以及Javascript实现方面等，而这些Web内容显示在哪个窗口及消息处理的启动循环等都需要由外部程序来提供。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、初步分析已有WebKit Port移植实现&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、与WebCore交互接口的实现&lt;/span&gt;&lt;br /&gt;在WebKit源代码目录结构中WebKit目录下分别包含gtk、mac、qt、win、wx目录，其分别对应不同的Port移植方式，在每一个目录下面都包括WebCoreSupport目录，而在不同的WebCoreSupport目录下分别包含有对类接口WebCore::ChromeClient、WebCore::ContextMenuClient、WebCore::DragClient、WebCore::EditorClient、WebCore::FrameLoaderClient、WebCore::InspectorClient等的实现，它们代表外部程序提供给WebKit内部使用的接口实现，其中&lt;span style="font-weight: bold;"&gt;WebCore::ChromeClient、WebCore::FrameLoaderClient&lt;/span&gt;非常重要。&lt;br /&gt;&lt;br /&gt;初步了解其接口定义能基本了解其对应的含义，这些接口往往需要由Port移植部分来提供实现，往往由WebKit内部根据一定的条件来调用。下面初步来了解几个主要接口：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;WebCore::ChromeClient接口：&lt;/span&gt;&lt;br /&gt;//往往在运行window.open脚本时调用，以便由外部程序决定如何打开一个新页面如新建一个窗口、新建一个Tab页签等；&lt;br /&gt;virtual WebCore::Page* createWindow(WebCore::Frame*, const WebCore::FrameLoadRequest&amp;amp;, const WebCore::WindowFeatures&amp;amp;);&lt;br /&gt;&lt;br /&gt;//通知外部程序显示页面；&lt;br /&gt;virtual void show();&lt;br /&gt;&lt;br /&gt;virtual bool canRunModal();&lt;br /&gt;&lt;br /&gt;//通知外部程序以Modal的方式显示页面；&lt;br /&gt;virtual void runModal();&lt;br /&gt;&lt;br /&gt;//通知外部程序显示JS警告提示窗口；&lt;br /&gt;virtual void runJavaScriptAlert(WebCore::Frame*, const WebCore::String&amp;amp;);&lt;br /&gt;&lt;br /&gt;//通知外部程序显示JS警告确认窗口；&lt;br /&gt;virtual bool runJavaScriptConfirm(WebCore::Frame*, const WebCore::String&amp;amp;);&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;WebCore::FrameLoaderClient接口：&lt;/span&gt;&lt;br /&gt;//检查是否拥有主页面窗口；&lt;br /&gt;virtual bool hasWebView() const;&lt;br /&gt;//检查是否拥有页面窗口；&lt;br /&gt;virtual bool hasFrameView() const;&lt;br /&gt;&lt;br /&gt;//通知外部程序有关http请求开始、结束、获取数据等，如通常浏览器状态栏显示的信息；&lt;br /&gt;virtual void dispatchDidReceiveResponse(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceResponse&amp;amp;);&lt;br /&gt;virtual void dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int lengthReceived);&lt;br /&gt;virtual void dispatchDidFinishLoading(WebCore::DocumentLoader*, unsigned long identifier);&lt;br /&gt;virtual void dispatchDidFailLoading(WebCore::DocumentLoader*, unsigned long identifier, const WebCore::ResourceError&amp;amp;);&lt;br /&gt;&lt;br /&gt;//通知外部程序WebKit内部主要事件处理，以便外部程序及时响应或创建维护数据等&lt;br /&gt;virtual void dispatchDidHandleOnloadEvents();&lt;br /&gt;virtual void dispatchDidReceiveServerRedirectForProvisionalLoad();&lt;br /&gt;virtual void dispatchDidCancelClientRedirect();&lt;br /&gt;virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&amp;amp;, double interval, double fireDate);&lt;br /&gt;virtual void dispatchDidChangeLocationWithinPage();&lt;br /&gt;virtual void dispatchWillClose();&lt;br /&gt;virtual void dispatchDidReceiveIcon();&lt;br /&gt;virtual void dispatchDidStartProvisionalLoad();&lt;br /&gt;virtual void dispatchDidReceiveTitle(const WebCore::String&amp;amp;);&lt;br /&gt;virtual void dispatchDidCommitLoad();&lt;br /&gt;virtual void dispatchDidFinishDocumentLoad();&lt;br /&gt;virtual void dispatchDidFinishLoad();&lt;br /&gt;virtual void dispatchDidFirstLayout();&lt;br /&gt;&lt;br /&gt;//告诉外部程序需要提供切换到一个新页面状态。此时外部程序往往会新建FrameView，并将FrameView与Frame关联，设置原生窗口句柄及其消息处理机制等等；&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;virtual void transitionToCommittedForNewPage();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;//告诉外部程序创建一个新的Frame，如遇到html中iframe标签时，需要外部程序创建一个新的Frame及原生窗口句柄等；&lt;br /&gt;virtual PassRefPtr&lt;webcore::frame&gt; &lt;span style="font-weight: bold;"&gt;createFrame&lt;/span&gt;(const WebCore::KURL&amp;amp; url, const WebCore::String&amp;amp; name, WebCore::HTMLFrameOwnerElement* ownerElement,&lt;br /&gt;                           const WebCore::String&amp;amp; referrer, bool allowsScrolling, int marginWidth, int marginHeight);&lt;br /&gt;&lt;br /&gt;//告诉外部程序需要创建一个Plugin实例，从而创建其原生窗口等等；&lt;br /&gt;virtual WebCore::Widget* &lt;span style="font-weight: bold;"&gt;createPlugin&lt;/span&gt;(const WebCore::IntSize&amp;amp;, WebCore::Element*, const WebCore::KURL&amp;amp;, const Vector&lt;webcore::string&gt;&amp;amp;, const Vector&lt;webcore::string&gt;&amp;amp;, const WebCore::String&amp;amp;, bool loadManually);&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、对WebCore中的page/loader等方面的类提供对应Port的实现支持&lt;/span&gt;&lt;br /&gt;如EventHandlerWin.cpp、FrameLoaderWin.cpp、DocumentLoaderWin.cpp、DocumentLoaderWin.cpp、WidgetWin.cpp、KeyEventWin.cpp等&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、实现WebView及WebFrame等以便外部程序嵌入WebKit&lt;/span&gt;&lt;br /&gt;不同的Port移植对WebView及WebFrame的定义及实现有所不同，但其与WebCore中的Page、Frame之间的关系大致与&lt;a set="yes" linkindex="3" href="http://2.bp.blogspot.com/_gp8441q4aEg/SNStXFHX_MI/AAAAAAAAAAw/o6J-lXSnSqs/s1600-h/webcore_page_frame.jpg"&gt;浅谈WebKit之WebCore篇图一&lt;/a&gt;描述相一致。&lt;br /&gt;&lt;br /&gt;具体关于WebView、WebFrame的定义与实现，特别是初始化时的动作可根据不同的Port移植而有所不同，同时初始化时会将上面提到的WebCore Port接口实现告诉WebKit内部。主要示例代码如下：&lt;br /&gt;static void webkit_web_view_init(WebKitWebView* webView)&lt;br /&gt;{&lt;br /&gt;  WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);&lt;br /&gt;  webView-&gt;priv = priv;&lt;br /&gt;  priv-&gt;corePage = &lt;span style="font-weight: bold;"&gt;new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient(webView), new WebKit::EditorClient(webView), new WebKit::DragClient, new WebKit::InspectorClient);&lt;/span&gt;&lt;br /&gt;  priv-&gt;mainFrame = &lt;span style="font-weight: bold;"&gt;WEBKIT_WEB_FRAME(webkit_web_frame_new(webView));&lt;/span&gt;&lt;br /&gt;  priv-&gt;lastPopupXPosition = priv-&gt;lastPopupYPosition = -1;&lt;br /&gt;  priv-&gt;editable = false;&lt;br /&gt;  ................................&lt;br /&gt;&lt;br /&gt;  priv-&gt;webSettings = webkit_web_settings_new();&lt;br /&gt;  webkit_web_view_update_settings(webView);&lt;br /&gt;  ..................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;WebKitWebFrame* webkit_web_frame_new(WebKitWebView* webView)&lt;br /&gt;{&lt;br /&gt;  g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);&lt;br /&gt;&lt;br /&gt;  WebKitWebFrame* frame = WEBKIT_WEB_FRAME(g_object_new(WEBKIT_TYPE_WEB_FRAME, NULL));&lt;br /&gt;  WebKitWebFramePrivate* priv = frame-&gt;priv;&lt;br /&gt;  WebKitWebViewPrivate* viewPriv = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);&lt;br /&gt;&lt;br /&gt;  priv-&gt;webView = webView;&lt;br /&gt;  priv-&gt;client = &lt;span style="font-weight: bold;"&gt;new WebKit::FrameLoaderClient(frame);&lt;/span&gt;&lt;br /&gt;  priv-&gt;coreFrame = &lt;span style="font-weight: bold;"&gt;Frame::create(viewPriv-&gt;corePage, 0, priv-&gt;client).get();&lt;/span&gt;&lt;br /&gt;  priv-&gt;coreFrame-&gt;init();&lt;br /&gt;&lt;br /&gt;  return frame;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、Chrome中对Port移植方面的实现&lt;/span&gt;&lt;br /&gt;其基本上与其他Port移植类似，其主要代码在webkit\glue目录中，可重点关注带client_impl.cc后缀的文件、webview_impl.cc、webwidget_impl.cc等；但是其究竟如何创建原生windows窗口、如何创建Render进程、Render进程与创建的原生windows窗口的关系如何等需要更进一步深入研究Chrome，如果能从上面提到的Port部分入手也许很快就可得到答案，这一点以后有机会单独研究。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5、Android中对Port移植方面的实现&lt;/span&gt;&lt;br /&gt;其实现有点特殊，&lt;/webcore::string&gt;&lt;/webcore::string&gt;&lt;/webcore::frame&gt;由于Andriod将WebKit以一个Java类接口的方式提供给Java环境使用(不像上面提到的Chrome、Safari等都是将WebKit以 一个C++动态或静态库的方式供C/C++外部程序调用)，这样WebKit内部与外部即JavaVM的交互(如上面提到的ChromeClient、 FrameLoaderClient接口实现)需要一个Bridge类来协调处理，&lt;webcore::frame&gt;&lt;webcore::string&gt;&lt;webcore::string&gt;同时&lt;/webcore::string&gt;&lt;/webcore::string&gt;&lt;/webcore::frame&gt;WebView、WebFrame接口绑定给JavaVM的jni接口实现&lt;webcore::frame&gt;&lt;webcore::string&gt;&lt;webcore::string&gt;也需要通过这个Bridge来支持协调处理。具体可详细参考android源码代码中WebCore\platform\android目录下的源文件。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;6、通过进一步了解WebCore Port接口及其实现，可以加深这样一个认识：&lt;/span&gt;&lt;br /&gt;如果&lt;/webcore::string&gt;&lt;/webcore::string&gt;&lt;/webcore::frame&gt;从MVC的角度来看整个基于WebKit的浏览器(当然不尽合理)，&lt;webcore::frame&gt;&lt;webcore::string&gt;&lt;webcore::string&gt;WebKit的Port部分相当于V部分，它提供显示页面内容及其辅助信息(如提示状态)的场所(即原生窗口)以及控制该显示场所的状态变化及消息响应(如改变大小、鼠标移动等)；而M部分往往由WebCore来实现，至于WebCore如何组织DOM则往往由htmlparser部分根据DOM定义来组织，如何在提供的显示场所显示Web内容则往往由WebCore中的layout部分来实现，其中充分利用了Css定义来布局显示该显示的内容；一旦涉及控制或动态处理往往由Port部分发起而由Javascript脚本来实现处理，其任务由JavascriptCore或V8来完成。&lt;br /&gt;&lt;br /&gt;一般说来新打开一个页面，Port部分需要提供一个主显示场所(即原生窗口)，如果页面中含有iframe标签，则需要在主显示场所内创建一个子显示场所，以显示iframe标签对应src的内容；如果页面中含有embed/object等插件标签同样往往也需要&lt;/webcore::string&gt;&lt;/webcore::string&gt;&lt;/webcore::frame&gt;在主显示场所内创建一个子显示场所(除非windowless)，以交由插件实现在提供的显示场所中显示内容。&lt;br /&gt;&lt;br /&gt;特别需要说明的是我们通常看到的页面表单元素input text field、textArea、button、radiobutton等往往不像window图形库中的按钮、菜单、输入框等会对应一个原生窗口，页面中的表单元素在一个显示场所(即原生窗口)中完全是利用Css等通过layout方式来达到我们所看到的类似原生按钮、输入框、列表框、滚动条等效果，其中特别是能准确定位元素大小、设置focus、光标显示、响应事件等，这充分的说明了浏览器引擎内部布局部分的威力所在。&lt;br /&gt;&lt;br /&gt;从另外一个角度来看一个页面一般说来(除非遇到iframe或插件需要另外提供一块子画布)相当于一块画布，浏览器引擎能在其精确的位置绘制不同颜色的文字、图片、图标等，同时根据当前的鼠标及一个模拟的输入提示光标位置，接收键盘输入操作。页面中的绝大多数元素与原生的窗口元素几乎没有关联，完全通过组合、布局、准确定位来处理一切。。。&lt;webcore::frame&gt;&lt;webcore::string&gt;&lt;webcore::string&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、如何利用WebKit?&lt;/span&gt;&lt;br /&gt;了解WebKit Port部分，对我们如何利用WebKit有非常现实的意义，目前已经将WebKit移植到多种平台如windows、qt、gtk、mac、wx、java、framebuffer等，甚至移植到python、ruby及3D等环境中去。通过借鉴或利用这些已有的WebKit Port实现，完全可以将WebKit发扬广大。&lt;br /&gt;&lt;br /&gt;前一阶段正好得到一个网友抓取网页的需求，试想目前移植利用WebKit基本都用来显示页面，往往涉及图形显示方面，但随着ajax及动态页面的广泛使用，未来动态生成的页面越来越多，传统的搜索引擎仅仅抓取静态的页面内容显然是不够的，现代化的搜索引擎应该能抓取动态的页面内容，这样它从某种意义讲相当于一个能获取对应的动态页面但不真正显示出其内容的浏览器，这样一个搜索引擎不仅能分析DOM树，同时能运行Javascript脚本(如运行ajax)，以真正完整获取页面内容，其实这样一个搜索引擎如果利用WebKit来实现的话，应该是个不错的选择，在我们了解WebKit Port部分之后，我们是否可以来模拟一个不真正具备图形显示方面的Port，进而充分利用WebKit中的WebCore及Javascript实现方面的功能呢？一点想法，今后有机会可以试试，或许Google、Yahoo的搜索引擎已经有了相关的实现，不知是否使用的就是WebKit?应该不会，有谁清楚的话，烦请通知一声。&lt;br /&gt;&lt;br /&gt;但愿我们也能利用利用WebKit整出一个象模象样的东东如机顶盒浏览器、手机浏览器等等。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、参考资源&lt;br /&gt;&lt;/span&gt;&lt;/webcore::string&gt;&lt;/webcore::string&gt;&lt;/webcore::frame&gt;&lt;a href="http://webkit.org/"&gt;The WebKit Open Source Project&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/chromium/"&gt;Google Chrome Home&lt;/a&gt;&lt;a href="http://code.google.com/android/index.html"&gt;&lt;br /&gt;&lt;/a&gt;&lt;webcore::frame&gt;&lt;webcore::string&gt;&lt;webcore::string&gt;&lt;a href="http://code.google.com/android/index.html"&gt;Android - An Open Handset Alliance Project&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/webcore::string&gt;&lt;/webcore::string&gt;&lt;/webcore::frame&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-2282431142170284851?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/2282431142170284851/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=2282431142170284851' title='5 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/2282431142170284851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/2282431142170284851'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/10/webkitport.html' title='浅谈WebKit之Port篇'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-7160171113225032465</id><published>2008-09-28T20:20:00.000+08:00</published><updated>2008-09-28T21:21:27.841+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活随想'/><title type='text'>南昌游记</title><content type='html'>2008.09.13-2008.09.17有幸能到有名的洪城南昌悠闲了几天，现将零星的记忆记录如下：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;出发&lt;/span&gt;&lt;br /&gt;9.12晚坐上K287车次的火车，车上人不是很多，不算拥挤，眯眯糊糊睡了一觉，第二天6点多就到目的地，觉得也挺方便，又一次感受到国家推广的火车夕发朝至政策的好处，回想多年前坐船从武汉到南京，可得三、五天呢？很方便出了火车站，听说南昌火车站是新近翻修过的，但仍旧未能留下特别的映象。&lt;br /&gt;&lt;br /&gt;与南京、上海火车站相比，似乎差距不少，就拿出站打的吧，一般日子在南京、上海火车站打的确实够方便，可南昌火车站则需要排仅有的一队，等待按次序安排进来的TAXI，还有不少人在组织安排，可惜车子和人群一样得排老长的队，也许效率有点不高吧，还好大约等了10几分钟，终于坐上了TAXI。比较有趣的是，坐上车前，组织人员还特意发个卡片，提醒自己提防TAXI绕路、坑人等，也许此类事件在当地不少见，也算很实用吧。不过自己这次旅行未曾遇到。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第一天&lt;/span&gt;&lt;br /&gt;上午稍加休息整理，下午来到南昌最大的内湖，最美丽的风景湖区象湖，湖区内风景宜人，空气清新，感觉湖区较大，可惜开发似乎不够，靠近湖区西边倒有不少新近开发的楼盘及大型超市如好又多等，应该还是挺适合居住生活的地方。楼盘价格大约在3000到6000之间。漫步在湖间小道，虽然游人不多，亲身感受到清新的湖风及阵阵风浪声，顿时兴致盎然，不犹回想起诗人般生活及古老的诗词等，当时一首简短打油诗油然而生以记录当时的心情。。。附录如下：《游象湖》太阳西边照，看到友人笑；漫漫人生路，快乐最重要。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第二天&lt;/span&gt;&lt;br /&gt;一早坐上游2线公交车，车费够便宜无论多远仅1元，大约50分钟就来到著名的秋水广场，看到新建的南昌新区，深切的感受到南昌人想建设好南昌，大力发展好南昌的大思路，以及官方大力宣扬的口号&lt;span style="font-weight: bold;"&gt;大气、开放、诚信、图强&lt;/span&gt;所浓缩的精髓。站立在秋水广场，远眺浩瀚的赣江，享受着独特的音乐喷泉，遥望对面的腾王阁，别有一番韵味。&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/SN939ZUAN9I/AAAAAAAAABg/NccE7j6zBlU/s1600-h/quishui2.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_gp8441q4aEg/SN939ZUAN9I/AAAAAAAAABg/NccE7j6zBlU/s400/quishui2.JPG" alt="" id="BLOGGER_PHOTO_ID_5251047587187800018" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;秋水广场&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;来到南昌，就不得不想到著名的八一起义，由此南昌才有红色之城之称。下午，继续坐游2公交车，来到闹市区的八一纪念馆，大约排10分钟的队，就能领取到免费的门票。进入纪念馆，人们纷纷扰扰，可有序而不喧哗，首先映入眼帘的是两幅起义军及领袖们的雕像，其气魄及豪气一样的令人征服。试想当时能有决心起来起义的人们，是需要很大的勇气及信心的，也许还有一股置生死于度外的无奈及冒险，从而大气凛然。。。。&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gp8441q4aEg/SN94UUPmz3I/AAAAAAAAABo/rTgCcfgvXNg/s1600-h/menpiao.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_gp8441q4aEg/SN94UUPmz3I/AAAAAAAAABo/rTgCcfgvXNg/s400/menpiao.jpg" alt="" id="BLOGGER_PHOTO_ID_5251047980964171634" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;门票&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;然后逐步参观了一些珍贵的历史照片及起义的策划、实施，以及起义后革命的走向等历史记录图片等等，详细阅读了历史教课书都提到的起义、会师重要历史事件的主要经过。。。好好重新学习了一段历史，深深感受到革命的成功来之不易，其中印象最深的是陈毅的誓师词，其中深刻的表达了信心、决心、勇气以及一股信念，现在看来他们当时似乎在拿生命作赌注，整整等了20年后，参加八一革命的人们才真正的看到胜利的曙光，看到那些名录表，无名的孤魂野鬼似乎可真不少。。。。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gp8441q4aEg/SN94l3Tc27I/AAAAAAAAABw/Ox43HqqDBXc/s1600-h/diaoxiang1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_gp8441q4aEg/SN94l3Tc27I/AAAAAAAAABw/Ox43HqqDBXc/s400/diaoxiang1.jpg" alt="" id="BLOGGER_PHOTO_ID_5251048282433313714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;雕像一&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gp8441q4aEg/SN94yBN6F2I/AAAAAAAAAB4/R9wKeRWbDd4/s1600-h/diaoxiang2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_gp8441q4aEg/SN94yBN6F2I/AAAAAAAAAB4/R9wKeRWbDd4/s400/diaoxiang2.jpg" alt="" id="BLOGGER_PHOTO_ID_5251048491252848482" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;雕像二&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第三天&lt;/span&gt;&lt;br /&gt;游玩了两天后，该领略南昌的美食及繁华的生活啦！一早就继续坐公交来到八一广场及繁华的市中心，八一广场，人流如织，但除了有个纪念塔外，没什么深刻映象，拿天安门、上海人民广场相比，差距不少，毕竟商业氛围、人们生活水平就如此。&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gp8441q4aEg/SN95WoIHaVI/AAAAAAAAACA/eSHilW7kMB4/s1600-h/bayi.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_gp8441q4aEg/SN95WoIHaVI/AAAAAAAAACA/eSHilW7kMB4/s400/bayi.jpg" alt="" id="BLOGGER_PHOTO_ID_5251049120172829010" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;八一纪念塔&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;然后有幸能去南昌最繁华的万达广场电影院体验了一场《水啸雾都》的影片，其实票价并不便宜，达65元，与上海、南京等市中心影院价格几乎一致，但看的人也还不少，心中不免有点疑惑，也许正好感上中秋节日或者影院本来就不多？影院效果挺不错，空间也挺大，电影情节也够吸引人。。。。&lt;br /&gt;&lt;br /&gt;徘徊在广场附近的街道，感觉一般，街道不是很整洁、宽敞，氛围也一般，不时能看到一些穿着一般的老人、妇人、小孩在街道中驻足或穿梭，不过虽然没有地铁，交通还算方便。。。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第四天&lt;/span&gt;&lt;br /&gt;为了进一步了解，南昌繁华的一面，一早就坐上公交，来到胜利路步行街，也许胜利路在南昌人看来挺繁华，但亲身体验一把后，感觉也一般，比南京的湖南路、无锡的中山路等都有段距离，顺便看了一下其有名的洪客隆超市，其中日常商品种类、价格与上海、南京等大超市相差无几，但人流似乎一般。。。&lt;br /&gt;&lt;br /&gt;中午与友人一起来到蛤蟆街，腐败了一把，吃了一顿美食，价廉味道也不错，可惜听友人讲本地特色菜很少，大部分是外来的。不过自己早上吃到的炒米粉及瓦灌汤还算印象深刻。。。&lt;br /&gt;&lt;br /&gt;餐中聊到南昌人的特点，其中谈到南昌人喜欢说泡、爱面子、说大话，自己未能深刻感觉到，也许需继续了解吧。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;第五天&lt;/span&gt;&lt;br /&gt;由于住在青云浦区，就顺便去了趟八大山人纪念馆，交通挺方便，去过的领导也不少如江、周等，其实那地方挺小，就是一个院子，不过门票得20元。几百年前明朝皇帝朱元璋的一位后裔(不知什么孙辈)，在满人进关后，辞官不做，来到南昌，潜心作画，画中以写物为主，以画寄托其对王朝灭忘的哀思，对民族的热爱，其画影响了中国近现代很多画家如张大千等等，所以留下一笔遗产，其名八大山人及书写都很独特。由于对书画不是很了解，参观大约1个半小时就结束啦，其中参观的人也不是很多。&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gp8441q4aEg/SN955Qi-8TI/AAAAAAAAACQ/inoFRcXV3Q8/s1600-h/8dashanren2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_gp8441q4aEg/SN955Qi-8TI/AAAAAAAAACQ/inoFRcXV3Q8/s400/8dashanren2.jpg" alt="" id="BLOGGER_PHOTO_ID_5251049715138490674" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;八大山人像&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;返回上海&lt;/span&gt;&lt;br /&gt;最后一天，早上8:30左右坐92次动车组返回上海，火车舒适方便，于12点左右到达南站，顺利结束本次旅行。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;总结&lt;/span&gt;&lt;br /&gt;总体感觉南昌之行顺利、愉快，在此感谢为我这次旅行提供支持、帮助的友人及其家人朋友等等，收获颇多，感慨甚多，让我有机会深深的回顾那段难忘的历史，以激励自己的信心、勇气与决心等，同时感受到现代南昌这个城市，虽然与沿海城市相比，城市建设、人文气息、工业化水平等有待发展，市民生活水平、素质等属于非常典型的中部偏低水平，但正与其口号宣称的那样&lt;span style="font-weight: bold;"&gt;大气、开放、诚信、图强&lt;/span&gt;发展着，潜力较大，祝福南昌，祝福每一位用心生活的人们。&lt;br /&gt;&lt;br /&gt;一点个人感觉，不知是否偏颇？有待进一步了解。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-7160171113225032465?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/7160171113225032465/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=7160171113225032465' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/7160171113225032465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/7160171113225032465'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/09/blog-post.html' title='南昌游记'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_gp8441q4aEg/SN939ZUAN9I/AAAAAAAAABg/NccE7j6zBlU/s72-c/quishui2.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-4292861156892137054</id><published>2008-09-25T19:30:00.000+08:00</published><updated>2008-09-25T23:19:50.008+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SquirrelFish'/><category scheme='http://www.blogger.com/atom/ns#' term='JavascriptCore'/><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='WebCore'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='SpiderMonkey'/><category scheme='http://www.blogger.com/atom/ns#' term='V8'/><title type='text'>浅谈WebKit之JavaScriptCore/V8篇</title><content type='html'>WebKit作为一个浏览器引擎，其中Javascript实现包括JavaScriptCore和V8，为了能更全面的了解WebKit，我们需要深入的了解Javascript实现的基本原理、其在WebKit中的作用以及与其他部分之间的交互，同时与Gecko中的Javacript实现作初步的对比。让我们开始了解WebKit之Javascript实现JavaScriptCore、V8之旅吧。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、Javascript实现的作用&lt;/span&gt;&lt;br /&gt;正与&lt;a href="http://ourpgh.blogspot.com/2008/07/geckojavascript.html"&gt;浅谈Gecko关键部分之六认识javascript实现及应用&lt;/a&gt;部分对什么是javascript的描述那样，在WebKit中其Javascript实现，同样相当于一个符合ECMAScript标准的动态库，其往往依附于浏览器引擎，由浏览器引擎来提供运行环境，并控制或发起javascript实现进行编译、解析执行脚本、垃圾回收等，同样需提供对浏览器引擎扩展的支持如Dom Binding等；&lt;br /&gt;&lt;br /&gt;由于Web2.0的提出，动态网页的交互如运行ajax更加的频繁，Javascript脚本运行的总体效率以及安全往往成为浏览器内核的关键，而其Javascript实现就担负着如此重任。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、JavaScriptCore实现特点&lt;/span&gt;&lt;br /&gt;相对于其他的Javascript实现，JavaScriptCore提出了虚拟机的概念，在编译脚本时生成高效的bytecode，bytecode统一在一个虚拟机的环境中执行。而其高效的虚拟机实现常称为SquirrelFish，通过&lt;a href="http://webkit.org/blog/189/announcing-squirrelfish/"&gt;Announcing SquirrelFish&lt;/a&gt;、&lt;a href="http://webkit.org/blog/214/introducing-squirrelfish-extreme/"&gt;Introducing SquirrelFish Extreme&lt;/a&gt;可更进一步了解关于SquirrelFish的相关内容。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、V8实现特点&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Fast Property Access&lt;/span&gt;&lt;br /&gt;To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates &lt;em&gt;hidden classes&lt;/em&gt;  behind the scenes. This basic idea is not new - the prototype-based programming language Self used maps to do something similar. (See for example, &lt;a href="http://research.sun.com/self/papers/implementation.html"&gt;An Efficient Implementation of Self, a Dynamically-Typed Object-Oriented Language Based on Prototypes&lt;/a&gt;). In V8, an object changes its hidden class when a new property is added.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Dynamic Machine Code Generation&lt;/span&gt;&lt;br /&gt;V8 compiles JavaScript source code directly into machine code when it is first executed.  There are no intermediate byte codes, no interpreter. Property access  is handled by inline cache code that may be patched with other machine instructions as V8 executes. &lt;p&gt;&lt;/p&gt;&lt;p&gt;During initial execution of the code for accessing a property of a given object, V8 determines the object's current hidden class. V8 optimizes property access by predicting that this class will also be used for all future objects accessed in the same section of code and uses the information in the class to patch the inline cache code to use the hidden class. If V8 has predicted correctly the property's value is assigned (or fetched) in a single operation. If the prediction is incorrect, V8 patches the code to remove the optimisation.&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight: bold;"&gt;Efficient Garbage Collection&lt;/span&gt;&lt;br /&gt;V8   reclaims memory used by  objects  that are no longer required in a process known as garbage collection. To ensure fast object allocation, short garbage collection pauses, and no memory fragmentation V8 employs a stop-the-world, generational, accurate, garbage collector. This means that V8:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;stops  program execution when performing a garbage collection cycle. &lt;/li&gt;&lt;li&gt;processes only part of the object heap in most garbage collection cycles. This minimizes the impact of stopping the application. &lt;/li&gt;&lt;li&gt;always knows exactly where all  objects and pointers are in memory. This avoids falsely identifying objects as pointers which  can result in memory leaks.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;In V8, the object heap is segmented into two parts: new space where objects are created, and old space to which objects surviving a garbage collection cycle are promoted. If an object is moved in a garbage collection cycle, V8 updates all pointers to the object. &lt;/p&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、JavaScriptCore、V8如何与WebCore交互&lt;/span&gt;&lt;br /&gt;在WebCore::Frame的数据结构中包含数据成员KJSProxy* m_jscript;而在Chrome的代码中调整为JSBridge* m_jscript;而针对不同实现JavaScriptCore、V8，分别有：&lt;br /&gt;class KJSBridge : public JSBridge {&lt;br /&gt;public:&lt;br /&gt;KJSBridge(Frame* frame) : m_proxy(new KJSProxy(frame)) { }&lt;br /&gt;virtual ~KJSBridge() { delete m_proxy; }&lt;br /&gt;........................&lt;br /&gt;private:&lt;br /&gt;KJSProxy* m_proxy;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class V8Bridge : public JSBridge {&lt;br /&gt;public:&lt;br /&gt;explicit V8Bridge(Frame* frame);&lt;br /&gt;virtual ~V8Bridge();&lt;br /&gt;.......................&lt;br /&gt;private:&lt;br /&gt;V8Proxy* m_proxy;&lt;br /&gt;};&lt;br /&gt;V8Bridge::V8Bridge(Frame* frame) {&lt;br /&gt;m_proxy = new V8Proxy(frame);&lt;br /&gt;}&lt;br /&gt;V8Bridge::~V8Bridge() {&lt;br /&gt;delete m_proxy;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;而不同的KJSProxy与V8Proxy分别对应不同的Javascript实现，它们分别实现了与WebCore之间的共同接口，其主要数据结构分别如下:&lt;br /&gt;class KJSProxy {&lt;br /&gt;Frame* m_frame;&lt;br /&gt;KJS::ProtectedPtr&amp;lt; KJS::JSDOMWindow&amp;gt; m_globalObject;&lt;br /&gt;int m_handlerLineno;&lt;br /&gt;.........................................&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class V8Proxy {&lt;br /&gt;Frame* m_frame;&lt;br /&gt;v8::Persistent&amp;lt;v8::context&amp;gt; m_context;&lt;br /&gt;v8::Persistent&amp;lt;v8::object&amp;gt; m_global;&lt;br /&gt;// Special handling of document wrapper;&lt;br /&gt;v8::Persistent&lt;v8::object&gt; m_document;&lt;br /&gt;int m_handlerLineno;&lt;br /&gt;...........................&lt;br /&gt;};&lt;br /&gt;具体不同Javascript实现如何实现与WebCore的接口，需了解不同Javascript实现逻辑；&lt;br /&gt;&lt;br /&gt;如对Javascript实现逻辑及基本原理感兴趣，可具体参考其提供的api及sample等等；&lt;br /&gt;&lt;br /&gt;至于Dom Binding的实现，JavaScriptCore与V8通过通过同样的方式来实现，可参考&lt;a href="http://ourpgh.blogspot.com/2008/09/webkitwebcore.html"&gt;浅谈WebKit之WebCore篇&lt;/a&gt; 中所描述的Javascript实现如何与WebCore集成等；&lt;br /&gt;&lt;br /&gt;具体Dom Binding的实现可参考generate-bindings.pl生成的代码，其中的内容一定会让你受益非浅，同时为将Javascript实现嵌入到其他应用中去提供非常有益的参考。如对window的实现，特别是open方法的实现，很值得研究研究。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、初步对比JavaScriptCore、V8、SpiderMonkey等&lt;/span&gt;&lt;br /&gt;具体JavaScriptCore、V8、SpiderMonkey、TracMonkey执行效率对比如何，不同的测试方法会有不同的测试结果，在这里不再阐述。&lt;br /&gt;&lt;br /&gt;就个人了解而言，觉得JavaScriptCore关于对象的方法、属性的安全访问控制方面略有欠缺；&lt;br /&gt;&lt;br /&gt;SpiderMonkey作为最早一批实现Javascript的引擎，其代码使用C语言来实现，稍现复杂，没有象后来的实现如JavaScriptCore、V8等借鉴了最新的虚拟机技术如JVM等；&lt;br /&gt;&lt;br /&gt;V8作为新近推出的Javascript实现，正与其特点所描述，拥有很多优势，同时基于C++实现，充分利用了C++ template，代码相对简洁，便于学习使用；&lt;br /&gt;&lt;br /&gt;关于TracMonkey请参考&lt;a href="http://arstechnica.com/news.ars/post/20080822-firefox-to-get-massive-javascript-performance-boost.html"&gt;Firefox to get massive JavaScript performance boost&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/JavaScript_engine"&gt;Wiki Javascript&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/v8/"&gt;V8&lt;/a&gt;&lt;br /&gt;&lt;a href="http://webkit.org/blog/189/announcing-squirrelfish/"&gt;Announcing SquirrelFish&lt;/a&gt;&lt;br /&gt;&lt;a href="http://webkit.org/blog/214/introducing-squirrelfish-extreme/"&gt;Introducing SquirrelFish Extreme&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/SpiderMonkey_Internals"&gt;SpiderMonkey Internals&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Tamarin"&gt;Tamarin&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-4292861156892137054?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/4292861156892137054/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=4292861156892137054' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4292861156892137054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4292861156892137054'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/09/webkitjavascriptcorev8.html' title='浅谈WebKit之JavaScriptCore/V8篇'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-409149334405893049</id><published>2008-09-20T14:09:00.000+08:00</published><updated>2008-09-20T18:33:56.144+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WebCore'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><title type='text'>浅谈WebKit之WebCore篇</title><content type='html'>&lt;div align="left"&gt;最近自从Google推出Chrome浏览器之后，浏览器受到人们更加广泛的关注，网上时而会出现这样那样的评价，作为一个浏览器内核爱好者，希望能乘着大家都关注的东风，能对浏览器内核有更深入的理解，进而能更好的进行Web开发及利用。&lt;br /&gt;&lt;br /&gt;Chrome浏览器的代码量其实是非常庞大的，要想对其有深入的理解，仅仅编译编译调试调试，是很难深入下去的。让我们还是从其主要部分如多进程管理通信、WebKit、V8、Skia、WinHttp、Sanbox等着手分析其主要流程及数据结构，或许能达到事半功倍的效果，而WebKit是其中非常重要的一部分，是Chrome的核心引擎部分，其他部分都是基于它来集成的，深入了解了WebKit，对Chrome的理解就会迎刃而解，再说WebKit作为一个相对独立的浏览器引擎在Safari、iPhone、Adobe AIR等中都有应用，非常值得大家深入的研究研究。&lt;br /&gt;&lt;br /&gt;就像前面的文章所说，WebKit主要包括三个部分WebCore、JavascriptCore及Ports部分，让我们先从WebCore部分出发吧。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;一、WebCore所包含的主要内容&lt;/span&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;1、从源代码目录结构来看&lt;/span&gt;&lt;br /&gt;WebCore目录主要包括如下目录：&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;bindings&lt;/span&gt; 包含将Dom Binding给JavascriptCore方面的代码，同时包含依据idl接口描述文件，自动生成对应于JavascriptCore的Binding实现的脚本等内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;bridge&lt;/span&gt; 主要包含NPPlugin方面的接口访问等内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;css &lt;/span&gt;主要包括与css方面相关的内容如解析、不同css规则的定义与实现、css Binding给JS的接口定义等内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;dom&lt;/span&gt; 主要包括dom方面相关的内容如不同dom元素的定义与实现、dom Binding给JS的接口定义等内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;html&lt;/span&gt; 主要包括html方面相关的内容如不同html元素的定义与实现、HTMLTokenizer及HTMLParser等内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;loader&lt;/span&gt; 主要包括装载资源如html页面、css、js及image等方面内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;page&lt;/span&gt; 主要包括描述一个Web页面所涉及的内容如page、frame、frameview、frametree、setting、history、chrome、chromeclient等内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;rendering&lt;/span&gt; 主要包括如何使用样式，组织布局、显示html元素等方面内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;plugins&lt;/span&gt; 主要包括浏览端如何实现NPPlugin方面的内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;svg&lt;/span&gt; 主要包括与svg方面相关的内容；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;xml&lt;/span&gt; 主要包括与xml方面相关的内容如xml parser、XPath、XSLT等；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;platform&lt;/span&gt; 主要包括与不同平台或外部库相关的内容如graphics(图形输出方面)、network(网络处理方面)、image-decoders(解析不同图片格式方面)等；&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;2、主要数据结构&lt;/span&gt;&lt;br /&gt;为了更加简单有效的描述浏览网页的内容及过程，WebKit为了明显区分不同方面的内容，采取了不同的namespace如webcore、javascriptcore、webkit等，webcore方面的主要数据结构有：&lt;br /&gt;webcore::page、webcore::frame、webcore::FrameLoader、webcore::FrameView、Document、DOMWindow、KJSProxy、DocumentLoader、ResourceHandle、ResourceRequest、ResouceResponse、MainResourceLoader、RenderObject、RenderView等；主要数据结构描述如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div align="center"&gt;&lt;strong&gt;WebView及WebFrame与page、frame之间的关系&lt;br /&gt;&lt;/div&gt;&lt;/strong&gt;&lt;p align="center"&gt;&lt;a href="http://2.bp.blogspot.com/_gp8441q4aEg/SNStXFHX_MI/AAAAAAAAAAw/o6J-lXSnSqs/s1600-h/webcore_page_frame.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5248010077815176386" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_gp8441q4aEg/SNStXFHX_MI/AAAAAAAAAAw/o6J-lXSnSqs/s400/webcore_page_frame.jpg" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align="center"&gt;图一&lt;/p&gt;&lt;p align="center"&gt;&lt;br /&gt;&lt;strong&gt;FrameLoader、DocumentLoader、DocLoader类结构&lt;/strong&gt;&lt;/p&gt;&lt;a href="http://1.bp.blogspot.com/_gp8441q4aEg/SNSxiJhCKJI/AAAAAAAAAA4/zIGQdCbErdk/s1600-h/webkit-loader.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5248014666021611666" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_gp8441q4aEg/SNSxiJhCKJI/AAAAAAAAAA4/zIGQdCbErdk/s400/webkit-loader.jpg" border="0" /&gt; &lt;p align="center"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align="center"&gt;图二 &lt;/p&gt;&lt;p align="center"&gt;&lt;strong&gt;主要Document类结构&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://2.bp.blogspot.com/_gp8441q4aEg/SNSxt4k8jZI/AAAAAAAAABA/YFx9r5vkdvA/s1600-h/webkit-document.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5248014867633048978" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_gp8441q4aEg/SNSxt4k8jZI/AAAAAAAAABA/YFx9r5vkdvA/s400/webkit-document.jpg" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align="center"&gt;图三 &lt;/p&gt;&lt;p align="center"&gt;&lt;strong&gt;FrameView类主要结构&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://2.bp.blogspot.com/_gp8441q4aEg/SNSyCrEJ7ZI/AAAAAAAAABI/qpAiSqHg0SU/s1600-h/webkit-frameview.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5248015224783105426" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://2.bp.blogspot.com/_gp8441q4aEg/SNSyCrEJ7ZI/AAAAAAAAABI/qpAiSqHg0SU/s400/webkit-frameview.jpg" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align="center"&gt;图四 &lt;/p&gt;&lt;p align="left"&gt;总的说来，WebCore包含了浏览器引擎的核心部分如处理html、dom、css、svg、获取资源、渲染页面过程控制、回调/通知外壳程序以及与Javascript实现的Binding等等；&lt;/p&gt;&lt;p align="left"&gt;&lt;br /&gt;&lt;strong&gt;二、一个Http请求在WebCore中的主要流程&lt;/strong&gt;&lt;/p&gt;&lt;p align="left"&gt;1、当调用webkit_web_view_open(url)时会触发core(webView)-&gt;mainFrame()-&gt;loader()-&gt;load(uri)(即调用FrameLoader.load)来发起一个Http页面请求；&lt;/p&gt;&lt;p align="center"&gt;&lt;strong&gt;FrameLoader.load方法的主要处理过程如图：&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://1.bp.blogspot.com/_gp8441q4aEg/SNS2SOQSn9I/AAAAAAAAABQ/rcFvUtP6Ano/s1600-h/webkit-frameloader.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5248019889973796818" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_gp8441q4aEg/SNS2SOQSn9I/AAAAAAAAABQ/rcFvUtP6Ano/s400/webkit-frameloader.jpg" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align="center"&gt;图五&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;2、一旦发起ResourceHandle::start，就会由网络库向web服务器发起一个http请求；&lt;/p&gt;&lt;p&gt;3、而MainResourceLoader作为一个ResouceHandleClient，提供了诸如didReceiveData()、didReceiveResponse()等回调接口以供网络库调用，一旦从web服务器获得相关数据后网络库部分则会调用相关接口如didReceiveData等；&lt;/p&gt;&lt;p&gt;4、MainResouceLoader::didReceiveData的主要回调处理过程如下图： &lt;/p&gt;&lt;p align="center"&gt;&lt;a href="http://4.bp.blogspot.com/_gp8441q4aEg/SNS6ijqX1YI/AAAAAAAAABY/xNj-6nCpB50/s1600-h/webkit-didreceivedata.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5248024568644752770" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://4.bp.blogspot.com/_gp8441q4aEg/SNS6ijqX1YI/AAAAAAAAABY/xNj-6nCpB50/s400/webkit-didreceivedata.jpg" border="0" /&gt;&lt;/a&gt; 图六&lt;/p&gt;&lt;p align="left"&gt;5、通过回调didReceiveData()方法，进而调用Node.attach()方法，这样就会解析生成document，同时会创建frameview、domwindow等；&lt;/p&gt;&lt;p align="left"&gt;6、创建的frameview会触发layoutTimerFired时间Timer，进而调用layout()方法，从而触发RenderObject的创建、布局等，同时或许会invalidateRect，进而触发操作系统图形库的paint消息事件；&lt;/p&gt;&lt;p align="left"&gt;7、由程序主消息处理循环接收paint消息事件，进而获取对应frame，获取或创建GraphicContext，然后调用frame-&gt;view()-&gt;paint(&amp;amp;ctx,...)，从而触发对应RenderObject树进行重画处理，这样一个完整的页面就会逐步的显示出来。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;三、网络库、图形库、Javascript实现与WebCore的集成&lt;/strong&gt;&lt;/p&gt;&lt;p align="left"&gt;为方便扩展及模块化，WebCore在处理浏览页面的过程中，往往使用了类似java或gecko中接口的概念，一般先定义一组公共接口或基类，然后由不同模块来实现。&lt;/p&gt;&lt;p align="left"&gt;如网络处理部分由WebCore提供一个ResourceHandle类，而在不同的目录如cf、curl、qt、soup、win等中在不同网络库的支持下对ResourceHandle类提供不同的实现，待编译时择机选择对应目录下的实现，这种方式从架构的角度看比较简单，但往往不能让程序同时使用多个网络库，进而由程序动态切换使用不同网络库实现，而gecko在xpcom的基础上提供了对于这种扩展形式的支持；其中Chrome对ResouceHanle类的实现基于WinHttp网络库。&lt;/p&gt;&lt;p align="left"&gt;同样WebCore对图形库的集成，也是采取这种方式来实现，如由WebCore提供一个GraphicsContext类，然后在不同的目录如cairo、cg、qt、win、wx中在不同的图形库支持下对GraphicsContext提供不同的实现。其中Chrome对GraphicsContext类的实现基于Skia图形库。&lt;/p&gt;&lt;p align="left"&gt;WebCore中实现的dom、html、svg、css等，往往需要通过一定的方式输出给Javascript的实现如JavascriptCore、V8，以便JS Engineer能认识这些dom元素等，并且能调用其中的方法，这种方式叫做Binding，为了便于将WebCore中相对固定的dom、html、svg、css接口等极其方便的Binding出去，WebKit使用了极其高效及神奇的方式来实现。&lt;/p&gt;&lt;p align="left"&gt;首先定义一组非标准的idl接口，然后通过运行一组perl脚本如generate-bindings.pl、CodeGenerator.pm、CodeGeneratorJS.pm等，就可根据idl接口定义，生成一组符合指定Javascript实现规则的脚本对象类。这样极大的减轻了开发人员的投入及编码错误的发生。&lt;/p&gt;&lt;p align="left"&gt;这一点与gecko中将不同的xpcom接口Binding给Javascript实现有本质上的差别，在gecko中通过xpconnect及一组classinfo来维护原生元素与JS对象之间的关系，不同原生元素对应的JS对象的创建及属性方法的Binding完全依赖于xpconnect的实现及classinfo的定义，要添加删除修改Binding的属性与方法，只需修改classinfo；而WebKit中Binding，相对简单明了，不同原生元素对应的JS对象的属性与方法由idl接口文件来定义，而具体实现则交给威力强大的generate-bindings.pl来对应生成实现的代码，这样编译时就可以轻松实现Binding。。。&lt;/p&gt;&lt;p align="left"&gt;&lt;strong&gt;四、参考资源&lt;/strong&gt;&lt;/p&gt;&lt;p align="left"&gt;&lt;a href="http://webkit.org/"&gt;The WebKit Open Source Project&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-409149334405893049?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/409149334405893049/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=409149334405893049' title='3 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/409149334405893049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/409149334405893049'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/09/webkitwebcore.html' title='浅谈WebKit之WebCore篇'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_gp8441q4aEg/SNStXFHX_MI/AAAAAAAAAAw/o6J-lXSnSqs/s72-c/webcore_page_frame.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-1688119054022574654</id><published>2008-09-05T10:55:00.000+08:00</published><updated>2008-09-08T11:13:28.090+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>体验新鲜出炉的Google Chrome浏览器</title><content type='html'>2008年9月2日新一款浏览器终于诞生了，她的名字叫做Chrome，出自名门之家Google，早在N年前就听说Google想推出自己的浏览器，但经过多年的励精图治，其庐山真面目终于大白于天下，一时间网上各种测评、预言等等满天飞，经过这几天的学习研究，作为一个开源浏览器内核爱好者，从自身的角度来学习观察它，现将自己初步了解的Google Chrome浏览器总结如下：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、学习&lt;/span&gt;&lt;a style="font-weight: bold;" href="http://www.google.com/googlebooks/chrome/index.html"&gt;Google Chrome Comic&lt;/a&gt;&lt;br /&gt;Google为了有效宣传Chrome，通过漫画的形式来表达自己对当前浏览器的一些看法，以及他们的实现方案即Chrome，总结起来其主要内容如下：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1、Stability，Testing and the Multi-process Architecture&lt;/span&gt;&lt;br /&gt;其中着重描述浏览器稳定性的要求及其独特的多进程架构，同时强调Chrome经过Google搜索引擎抓到的大量不同页面测试，其稳定性拥有独特的优势，这一点是其他浏览器的测试无法比拟的；&lt;br /&gt;&lt;br /&gt;从技术的角度来讲，采取多进程架构来实现浏览器，目前来讲确实是独一无二的，是其他浏览器无法比拟的，但多进程架构本身在Yahoo!Widget及Apache等早有成功的应用案例，技术难度没有太多的创新，相对多线程架构来讲，增加了大量IPC方面的内容，其实IPC的实现与应用在OS的实现当中拥有大规模的应用。&lt;br /&gt;&lt;br /&gt;但多进程架构是否真的象Google所宣称的那样稳定，会不会带来诸如CPU使用过高，整个浏览器资源是否太多？特别是window句柄是否过多?因为浏览器毕竟是个图形界面程序，而不仅仅是网络程序。&lt;br /&gt;&lt;br /&gt;通过对其&lt;span id="goog-ws-page-title"&gt;Process Models&lt;/span&gt;初步了解，其体系上也考虑到诸如Process-per-site-instance、Process-per-site、Process-per-tab、Single process等方式的选择，但其整体效用如何还需实践的考验，当然其出发点还是够强大的，正如N年前他们设计浏览器时所宣称的那样，浏览器就是一个互联网平台，作为一个互联网平台所能显示的页面及应用越来越多，其稳定性应该是首要解决的问题，他们采取的方案就是向OS学习，采取多进程，由一个主进程来管理浏览器的一切。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2、Speed，WebKit and V8&lt;/span&gt;&lt;br /&gt;从漫画当中，我们可看到Google对浏览器的方方面面都早有相当程度的研究，但WebKit渲染内核是否速度最快，其实值得商榷，但其代码简洁，方便学习开发，倒觉得真的很对。&lt;br /&gt;&lt;br /&gt;至于V8对javascript的实现是否真的很快也很难讲，虽然它对javascript的实现方式有所调整，但是否真的有那么高效率很难讲，毕竟似乎没听说过它在其他地方使用过并有良好表现。&lt;br /&gt;&lt;br /&gt;其中网上就有很多人对其对其它javascript的实现如SpiderMonkey、JavascriptCore的评价特别是垃圾回收方面有很大的争议。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3、Search，UI&lt;/span&gt;&lt;br /&gt;这方面Chrome本身应该没有太大的创新，虽然其提出标签页放在最上方，但其好多想法早在Firefox、Opera中有所实现。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4、Security，Sanboxing and safe Browsing&lt;/span&gt;&lt;br /&gt;对于安全的考虑，其中sanbox及phishing等方面，Firefox早有相应的处理机制，只不过其sanbox可扩展到进程层，有了一定的提升，但其本质还是基于同源策略等，同时根据V8的介绍其中提供了对对象方法、属性权限的控制管理，这一点比JavascriptCore要强大，不过SpiderMonkey其实早有提供，至于其具体Security实现是否也有诸如Firefox中的SecrurityManager还须继续观察。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5、Gears，Standards and Open source&lt;/span&gt;&lt;br /&gt;其中特别提到对Web应用的扩展是基于Gear来实现，由于前期对Gear的实现扩展方式未曾了解，可能以后须加强对这方面的学习。&lt;br /&gt;&lt;br /&gt;但总的说来，其扩展性应该与Firefox相比，还是有很大差距，Firefox中提供了一整套的xpcom、extension、xul等可以让开发者从浏览器的方方面面来扩展，但Chrome因为其渲染部分使用了WebKit，要让开发者象扩展Firefox那样方便的扩展Chrome浏览器应该几乎不可能。目前来看要扩展Chrome需要使用Gear或相当通用的NP Plugin技术。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、切身体验使用Chrome&lt;/span&gt;&lt;br /&gt;2008年9月3日一早第一时间就下载试用了Chrome浏览器，感觉其体现了Google一贯的界面简单，操作简便的风格，并且省掉了很多操作如全屏、打印预览等，一时间觉得让人无所适从，同时页面加载速度及内存占用等方面并没有太突出的表现，特别是打开20个以上的页面后，再在不同页签之间切换，往往有停顿的感觉及空白页面的现象出现，这一点在Firefox3中那怕是50个页签也没有出现类似的现象。&lt;br /&gt;&lt;br /&gt;通过地址栏在不同页签中打开20个不同的网站，对比Chrome及Firefox3的使用情况发现，Chrome的加载速度至少比Firefox3慢20%，而整体占用CPU及内存资源，Chrome比Firefox至少多20%，对计算机系统的影响也较大，在加载完网页后不进行任何鼠标操作的情况下，Chrome主进程或Plugin进程还继续占用大量CPU，而Firefox3中则几乎不占用CPU，或许Chrome整体架构或架构对Flash Plugin等方面的支持还存在或多或少的问题。&lt;br /&gt;&lt;br /&gt;总之毕竟是第一个测试版本，能有不崩溃及正常使用的效果，比上次第一个Safari版本发布的效果好多啦，特别是对中文、英文等不同语言的支持方面。从初步使用的感受来看，应该还是挺不错的，应该可打80分以上。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、初步研究Chrome源代码及相关网站&lt;/span&gt;&lt;br /&gt;第一时间阅读了其开发网站&lt;a href="http://code.google.com/chromium/"&gt;Chromium developer Documentation&lt;/a&gt;中的相关内容，其中对相关内容的说明可谓专业而详细但不够全面，不愧为Google主推的Open Source，有兴趣的话可以好好阅读阅读。&lt;br /&gt;&lt;br /&gt;其中对于Chrome的编译与调试一篇更是特别实用，按照其中的说明经过30-50分钟就可轻松的编译出一个Chrome，这一点在Firefox、WebKit等开源项目中是很难办到的，同时其中包含许多第三方库的编译，而不象一般的开源项目往往需要将第三方包从其他地方下载再编译，充分的说明了Google在Open Source方面的大力支持，对开源社区来讲应该是个福音，它极大的方便了开源项目的开发，从这点讲我们应该感谢Google。&lt;br /&gt;&lt;br /&gt;通过初步分析其源代码及其架构说明，Chrome浏览器的主要特别之处在于多进程通讯、管理及V8，并将WebKit嵌入到其中。&lt;br /&gt;&lt;br /&gt;而与WebKit相关的网络库使用的是WinHttp、图形库使用Google自己提供的skia，而不是苹果的CoreGraphic或者Cairo等，同时对WebKit的Port方面也是自己提供的一套Interface，这样看来Chrome对WebKit的使用主要是Render Layout及页面处理流程方面。&lt;br /&gt;&lt;br /&gt;至于其他模块诸如libxml、libxslt、libjpeg、libpng、sqlite、pthread等与WebKit中使用的相一致。今后若有时间可对其进行进一步的分析。当然其中包含很多Google自己提供的V8、Gear等等。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;通过对漫画及相关文档的学习研究及实践等，虽然Google强调其开源、稳定、安全、扩展等特性，但其架构本身对Web方面并不象Gecko那样非常开放，Gecko通过对xpcom、xul的支持大大的扩展了Html及其应用支持，这一点Gecko应该还有相当的优势。&lt;br /&gt;&lt;br /&gt;虽然从Google看来这正是其看不上Gecko内核而采取WebKit内核的原因，因为相对简单的WebKit内核还在&lt;span&gt;&lt;span style="font-family:Arial;"&gt;Android&lt;/span&gt;&lt;/span&gt;方面也有优势，而Google对RIA方面的支持，也许没那么大，其支持方式应该更像Adobe AIR一样，而不象Gecko那样支持xul一样。&lt;br /&gt;&lt;br /&gt;从整个Chrome浏览器中体现了Google一贯的作风，简单，代码也要简单，而Gecko它太复杂，复杂得让人难以掌控。&lt;br /&gt;&lt;br /&gt;自从Google推出Chrome之后，各种评论特别多，尤其是Google与Mozilla的关系，以及Firefox的发展，有些人悲观地预计3年后Firefox将被Chrome超越甚至让人遗忘。&lt;br /&gt;&lt;br /&gt;但是通过初步的学习研究，个人感觉Chrome的实现方式与Firefox的实现方式还是有本质上的差别，Firefox以前获得大家认可的优势如安全、快速、易扩展等优势依然存在，同时很早以前Mozilla的开发者就认识到其在开放平台及易扩展方面的巨大前景及无人可敌的优势，也许Mozilla的优势就在这里，只要坚守住啦，目前看来Google、Microsoft都短时间内难以超越Mozilla这一点。&lt;br /&gt;&lt;br /&gt;一点个人看法，希望能激起大家一点共鸣，大家都能更好的利用Web技术。&lt;br /&gt;&lt;br /&gt;好好研究研究Chrome，她毕竟是个新生儿，并出自名门之家。。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://code.google.com/chromium/"&gt;Google Chrome Home&lt;/a&gt;&lt;br /&gt;&lt;div class="blog-icon"&gt; &lt;input value="http://blog.chromium.org/favicon.ico" type="hidden"&gt; &lt;/div&gt;  &lt;div class="blog-title"&gt; &lt;a set="yes" linkindex="184" href="http://blog.chromium.org/" target="_blank"&gt; Chromium Blog&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/v8"&gt;V8&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-1688119054022574654?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/1688119054022574654/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=1688119054022574654' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1688119054022574654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1688119054022574654'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/09/google-chrome.html' title='体验新鲜出炉的Google Chrome浏览器'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-6387294722669142942</id><published>2008-08-27T13:28:00.000+08:00</published><updated>2008-08-27T16:08:29.871+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='编译'/><title type='text'>在windows上编译WebKit</title><content type='html'>通过编译WebKit，可以让我们更进一步的了解、使用WebKit，从中了解WebKit使用哪些外部库，其中包含哪些主要内容等等。初次在windows上编译WebKit，是件比较麻烦的事情，需要注意的问题比较多，再加上相关文档不是很全面。从这个角度看，WebKit的编译系统，相对Gecko的编译系统，要粗糙很多。&lt;br /&gt;&lt;br /&gt;下面简单汇总一下自己编译WebKit的过程及所遇到的问题解决方法等&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;一、按照下面由WebKit.org提供的内容准备编译环境、获取源代码等&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://webkit.org/building/tools.html"&gt;Installing the Developer Tools&lt;/a&gt;&lt;br /&gt;&lt;a href="http://webkit.org/building/checkout.html"&gt;Getting WebKit&lt;/a&gt;&lt;br /&gt;&lt;a href="http://webkit.org/building/build.html"&gt;Building WebKit&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;其中首次获取源代码后需要特别注意的是一定要安装WebKit Support Libraries及运行WebKit/WebKitTools/Scripts/update-webkit成功。&lt;br /&gt;&lt;br /&gt;其中WebKit Support Libraries主要包括缺省编译时需要使用的外部库CoreGraphics.lib、CoreFundation.lib、CFNetwork.lib，它们对应Safari所使用的Mac风格图形库及网络库；&lt;br /&gt;&lt;br /&gt;而通过分析update-webkit脚本，得知它主要是下载一个WebKitAuxiliaryLibrary.zip并安装到指定目录，其中包括Unicode方面的icuin.lib及icuuc.lib、xml2及xslt方面的libxml2.lib和libxslt.lib、线程相关的pthreadVC2.lib、SQLite相关的SQLite3.lib等外部开源库等；&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;二、按照下面由Avishkar Autar提供的一篇Blog，修改直接从VS IDE编译WebKit&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://aautar.digital-radiation.com/blog/2008/05/compiling-webkit-on-win32.html"&gt;Avishkar Autar's Blog-Compiling Webkit On Win32&lt;br /&gt;&lt;/a&gt;其中详细描述了相关注意事项及相应路径的修改。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;三、解决编译过程中可能出现的常见问题&lt;/strong&gt;&lt;br /&gt;1、问题描述：&lt;br /&gt;vc++2005 error PRJ0002 的问题 错误的结果 1 (从“C:\WINDOWS\system32\cmd.exe”返回)&lt;br /&gt;&lt;br /&gt;解决方法：&lt;br /&gt;选中解决方案，选择属性-&gt;配置属性-&gt;清单工具-&gt;输入和输出-&gt;嵌入清单，把是改成否。&lt;br /&gt;&lt;br /&gt;2、问题描述：&lt;br /&gt;对VC 2005 error C2220:警告被视为错误-没有生成“object"&lt;br /&gt;&lt;br /&gt;解决方法：&lt;br /&gt;参考&lt;a href="http://wuqiangbk.bokee.com/viewdiary.25464427.html"&gt;FIX:VC2005编译错误：1 error C2220: 警告被视为错误 - 没有生成“object”文件&lt;/a&gt;&lt;br /&gt;选中解决方案，选择属性-&gt;配置属性-&gt;c/c++-&gt;常规-&gt;将警告视为错误，把是改成否。&lt;br /&gt;&lt;br /&gt;3、问题描述：&lt;br /&gt;正在创建库WebCore.lib : fatal error LNK1106: 文件无效或磁盘已满: 无法查找到 0x51F6CD51&lt;br /&gt;&lt;br /&gt;解决方法：&lt;br /&gt;参考&lt;a href="http://support.microsoft.com/kb/834332/"&gt;FIX:LNK1106:: 无法查找到 0x76364 无效或磁盘已满&lt;/a&gt;解决此问题, 添加 /IGNOREIDL 链接选项。&lt;br /&gt;在VisualStudio.NETIDE, 设置此链接器选项请按照下列步骤操作：&lt;br /&gt;a. 打开 属性页 对话框对于项目。&lt;br /&gt;b. 展开 链接 文件夹。&lt;br /&gt;c. 单击要查看嵌入的 IDL 属性页 嵌入的 IDL 。&lt;br /&gt;d. 将 忽略嵌入的 IDL 属性设置 是 。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;四、总结分析&lt;/strong&gt;&lt;br /&gt;通过分析WebKit\WebKitTools\Scripts\build-webkit脚本，可知其在windows环境的编译过程主要是完成VS解决方案WebKit/win/WebKit.vcproj/WebKit.sln中的内容，其中已完成相关基本配置，这样说来其编译系统还是相对比较简单的，但由于需要使用比较多的外部库，并且没有将外部库的编译整合到WebKit的编译系统中，这样往往需要编译或下载、配置(如设置头文件、库文件的路径等)对应版本的外部库。&lt;br /&gt;&lt;br /&gt;同时WebKit核心本身编译出来就是一个动态库，而象WinLanucher、FindSafari、DumpRenderTree等外围测试程序反而比较多，编译时也会出现一些问题，对一个初次接触的人来讲往往比较困惑。&lt;br /&gt;&lt;br /&gt;编译成功后，可运行脚本WebKit/WebKitTools/Scripts/run-safari通过Safari来使用刚才编译的WebKit动态库，具体可参考&lt;a href="http://webkit.org/building/run.html"&gt;Running WebKit&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;但愿大家都能轻松愉快的编译出WebKit。。。&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-6387294722669142942?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/6387294722669142942/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=6387294722669142942' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6387294722669142942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6387294722669142942'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/windowswebkit.html' title='在windows上编译WebKit'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-119802846810130778</id><published>2008-08-25T15:03:00.000+08:00</published><updated>2008-08-25T16:39:13.558+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavascriptCore'/><category scheme='http://www.blogger.com/atom/ns#' term='WebCore'/><category scheme='http://www.blogger.com/atom/ns#' term='WebKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><title type='text'>认识了解WebKit</title><content type='html'>WebKit作为一个浏览器引擎，其第一Release版本在2003年1月发布，虽然出现的相对比较晚，但以其一些优越的特性，获得了诸如Google、Apple、Adobe、Yahoo等公司的青睐，似乎大有赶超Gecko的势头，带着究竟什么是WebKit？其主要特点有哪些？如何应用它？它与其他浏览器内核有哪些不同等疑问，开始认识了解WebKit。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是WebKit?&lt;/span&gt;&lt;br /&gt;WebKit is an open source web browser engine. WebKit is also the name of the Mac OS X system framework version of the engine that's used by Safari, Dashboard, Mail, and many other OS X applications.&lt;br /&gt;&lt;br /&gt;WebKit is an &lt;a set="yes" linkindex="19" href="http://en.wikipedia.org/wiki/Open_source" title="Open source"&gt;open source&lt;/a&gt; &lt;a set="yes" linkindex="20" href="http://en.wikipedia.org/wiki/Application_framework" title="Application framework"&gt;application framework&lt;/a&gt; that provides a foundation upon which to build a &lt;a set="yes" linkindex="21" href="http://en.wikipedia.org/wiki/Web_browser" title="Web browser"&gt;web browser&lt;/a&gt;. WebKit was originally derived from the Konqueror browser’s KHTML software library by Apple, Inc. for use as the engine of Mac OS X’s &lt;a set="yes" linkindex="27" href="http://en.wikipedia.org/wiki/Safari_%28web_browser%29" title="Safari (web browser)"&gt;Safari&lt;/a&gt; web browser, and has now been further developed by Apple, &lt;a set="yes" linkindex="28" href="http://en.wikipedia.org/wiki/Nokia" title="Nokia"&gt;Nokia&lt;/a&gt;, &lt;a set="yes" linkindex="29" href="http://en.wikipedia.org/wiki/Google" title="Google"&gt;Google&lt;/a&gt; and others. The framework is now used by &lt;a set="yes" linkindex="30" href="http://en.wikipedia.org/wiki/Omniweb" title="Omniweb" class="mw-redirect"&gt;Omniweb&lt;/a&gt;, &lt;a set="yes" linkindex="31" href="http://en.wikipedia.org/wiki/Shiira" title="Shiira"&gt;Shiira&lt;/a&gt;, &lt;a set="yes" linkindex="32" href="http://en.wikipedia.org/wiki/ICab" title="ICab"&gt;iCab&lt;/a&gt;, &lt;a set="yes" linkindex="33" href="http://en.wikipedia.org/wiki/Adobe_AIR" title="Adobe AIR" class="mw-redirect"&gt;Adobe AIR&lt;/a&gt;, &lt;a set="yes" linkindex="34" href="http://www.torchmobile.com/" class="external text" title="http://www.torchmobile.com/" rel="nofollow"&gt;Iris Browser&lt;/a&gt;, mobile phones (including the &lt;a linkindex="35" href="http://en.wikipedia.org/wiki/IPhone" title="IPhone"&gt;iPhone&lt;/a&gt;), Nokia’s &lt;a linkindex="36" href="http://en.wikipedia.org/wiki/Series_60_browser" title="Series 60 browser" class="mw-redirect"&gt;Series 60 browser&lt;/a&gt;, and Google’s &lt;a set="yes" linkindex="37" href="http://en.wikipedia.org/wiki/Android_%28mobile_phone_platform%29" title="Android (mobile phone platform)" class="mw-redirect"&gt;Android&lt;/a&gt; platform.&lt;br /&gt;&lt;br /&gt;WebKit's HTML and JavaScript code began as a branch of the KHTML and KJS libraries from KDE.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、WebKit主要特点及其目标&lt;/span&gt;&lt;br /&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;Web Content Engine&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;The project's primary focus is content deployed on the World Wide Web, using standards-based technologies such as HTML, CSS, JavaScript and the DOM. However, we also want to make it possible to embed WebKit in other applications, and to use it as a general-purpose display and interaction engine.&lt;/dd&gt;&lt;/dl&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;Open Source&lt;/dt&gt;&lt;dd&gt;WebKit should remain freely usable for both open source and proprietary applications. &lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;&lt;/dt&gt;&lt;dt style="font-weight: bold;"&gt;Performance&lt;/dt&gt;&lt;dd&gt; Maintaining and improving speed and memory use is an important goal. We never consider performance "good enough", but strive to constantly improve. As web content becomes richer and more complex, and as web browsers run on more limited devices, performance gains continue to have value even if normal browsing seems fast enough.&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;&lt;/dt&gt;&lt;dt style="font-weight: bold;"&gt;Portability&lt;/dt&gt;&lt;dd&gt;The WebKit project seeks to address a variety of needs. We want to make it reasonable to port WebKit to a variety of desktop, mobile, embedded and other platforms. We will provide the infrastructure to do this with tight platform integration, reusing native platform services where appropriate and providing friendly embedding APIs.&lt;/dd&gt;&lt;/dl&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;Compatibility&lt;/dt&gt;&lt;dd&gt;For users browsing the web, compatibility with their existing sites is essential. We strive to maintain and improve compatibility with existing web content, sometimes even at the expense of standards. We use regression testing to maintain our compatibility gains.&lt;/dd&gt;&lt;dt&gt;&lt;br /&gt;&lt;/dt&gt;&lt;dt style="font-weight: bold;"&gt;Standards Compliance&lt;/dt&gt;&lt;dd&gt;WebKit aims for compliance with relevant web standards, and support for new standards&lt;br /&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;Security&lt;/dt&gt;&lt;dd&gt;Protecting users from security violations is critical. We fix security issues promptly to protect users and maintain their trust.&lt;/dd&gt;&lt;/dl&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;WebKit is an engine, not a browser&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;We do not plan to develop or host a full-featured web browser based on WebKit.&lt;/dd&gt;&lt;/dl&gt;&lt;dl&gt;&lt;dt style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;WebKit is not the solution to every problem&lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;We focus on web content, not complete solutions to every imaginable technology need.&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、WebKit主要组成&lt;/span&gt;&lt;br /&gt;WebKit作为一个浏览器内核引擎，正如上面所描述，其主要内容专注在浏览器的核心部分Javascript的实现(&lt;span style="font-weight: bold;"&gt;JavaScriptCore&lt;/span&gt;)、布局渲染的实现(&lt;span style="font-weight: bold;"&gt;WebCore&lt;/span&gt;)以及对外接口的支持。&lt;br /&gt;&lt;br /&gt;Gecko内核提供了一整套的与浏览器相关的解决方案如包括对NSPR、XPCOM、Network、Extension、XUL等的支持与实现等，但WebKit往往专注于核心部分，其他部分由外壳程序或其他公共库来实现，如其对Http请求的实现可由外部的公共库如libcurl、cf、soup等来提供实现，其本身不提供Http协议实现方面的代码，而Gecko中的Http请求完全由Gecko中的Network部分来实现。&lt;br /&gt;&lt;br /&gt;为了跨越更多平台及图形库，WebKit提供了cairo、gtk、mac、win、qt、wxwidget等对外接口的支持，这方面并不比Gecko逊色多少。&lt;br /&gt;&lt;br /&gt;对外部嵌入程序而言，WebKit提供了具有浏览器功能的、同时与外壳程序相对应的平台或图形库相关的动态库。如在Safari中WebKit内核仅以一个webkit.dll的形式出现。相对Gecko内核而言，虽然其功能比较少，但其使用起来简单方便，实现代码相对简洁，性能也不错。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://webkit.org/"&gt;The WebKit Open Source Project&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/WebKit"&gt;WiKi WebKit&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Comparison_of_layout_engines"&gt;Comparison of layout engines&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-119802846810130778?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/119802846810130778/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=119802846810130778' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/119802846810130778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/119802846810130778'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/webkit.html' title='认识了解WebKit'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-5998715449940113546</id><published>2008-08-20T20:49:00.000+08:00</published><updated>2008-08-20T21:53:44.134+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='编译'/><category scheme='http://www.blogger.com/atom/ns#' term='调试'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之十四Build System</title><content type='html'>Mozilla作为一个开源组织，为我们提供了完整的源代码，以便我们进行编译、调试等，为了能真正的运用Gecko内核，我们需要自己动手从源代码中进行编译，进而进行调试，从而真正了解、运用Gecko内核，以致修改、改进Gecko内核，或者自己编写出符合Gecko内核编写规则的应用等。下面提供一些参考资源，以便大家完成编译、调试等。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;参考资源&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.csdn.net/orbit/archive/2007/01/18/1487160.aspx"&gt;自己动手编译Mozilla Firefox和ThunderBird&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/en/Build_Documentation"&gt;Mozilla developer center -Build Documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/en/Windows_Build_Prerequisites"&gt;Windows Build Prerequisites&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/En/Creating_XULRunner_Apps_with_the_Mozilla_Build_System"&gt;Creating XULRunner Apps with the Mozilla Build System&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/En/Adding_XPCOM_components_to_Mozilla_build_system"&gt;Adding XPCOM components to Mozilla build system&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a rel="internal" href="http://developer.mozilla.org/en/Creating_Custom_Firefox_Extensions_with_the_Mozilla_Build_System"&gt;Creating Custom Firefox Extensions with the Mozilla Build System&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;a rel="internal" href="http://developer.mozilla.org/en/How_Mozilla%27s_build_system_works"&gt;How Mozilla's build system works&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/en/Building_a_component_DLL"&gt;Building a component DLL&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;a rel="internal" href="http://developer.mozilla.org/en/Mozilla_Build_FAQ"&gt;Mozilla Build FAQ&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;a rel="internal" href="http://developer.mozilla.org/en/Debugging_Mozilla_on_Windows_FAQ"&gt;Debugging Mozilla on Windows FAQ&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-5998715449940113546?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/5998715449940113546/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=5998715449940113546' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/5998715449940113546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/5998715449940113546'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/geckobuild-system.html' title='浅谈Gecko关键部分之十四Build System'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-6174419785076582820</id><published>2008-08-17T11:08:00.000+08:00</published><updated>2008-08-19T15:13:18.891+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Xulrunner'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedding'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='XUL'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之十三Xulrunner</title><content type='html'>Gecko内核作为一个浏览器内核，为了能充分利用其已有的功能，Mozilla提供了一个可作为运行环境平台的Xulrunner，来扩展Gecko内核的应用。那么究竟什么是Xulrunner、如何实现一个Xulrunner应用程序、它和Firefox、ThunderBird等有什么区别、目前有哪些应用基于Xulrunner等等，通过下面的学习研究，希望能逐步的解答这些疑问。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是Xulrunner?&lt;/span&gt;&lt;br /&gt;XULRunner is a Mozilla runtime package that can be used to bootstrap XUL+XPCOM applications that are as rich as Firefox and Thunderbird. It will provide mechanisms for installing, upgrading, and uninstalling these applications. XULRunner will also provide libxul, a solution which allows the embedding of Mozilla technologies in other projects and products.&lt;br /&gt;&lt;br /&gt;其实质上是一个运行环境，类似于java虚拟机、Adobe AIR、Yahoo! Widget等，只不过它目前支持xul、xpcom、js、html等，而其他的运行环境大都有其对应的支持格式及实现方式等。有了Xulrunner，为开发Rich Internet application提供另一种实现方式。&lt;br /&gt;&lt;br /&gt;Xulrunner基于Gecko内核，充分利用了其功能及实现方式，而Gecko内核的功能、性能及实现方式等在Firefox中得到了充分的体现与运用。这样Xulrunner应用程序基本上完全可以应用Firefox所拥有的功能。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、如何实现一个Xulrunner应用&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;程序&lt;/span&gt;&lt;br /&gt;1、下载、安装Xulrunner;&lt;br /&gt;&lt;br /&gt;2、创建应用目录结构，设置应用application.ini及chrome manifest；&lt;br /&gt;application.ini内容大致如下：&lt;br /&gt;[App]&lt;br /&gt;Vendor=***&lt;br /&gt;Name=Bamboo&lt;br /&gt;Version=1.0&lt;br /&gt;BuildID=2008052906&lt;br /&gt;Copyright=Copyright (c) 1998 - 2008 mozilla.org&lt;br /&gt;ID={ec6039f7-c60a-784f-9b0e-23b3a9e67323}&lt;br /&gt;[Gecko]&lt;br /&gt;MinVersion=1.9&lt;br /&gt;MaxVersion=1.9&lt;br /&gt;[XRE]&lt;br /&gt;EnableProfileMigrator=1&lt;br /&gt;EnableExtensionManager=1&lt;br /&gt;[Crash Reporter]&lt;br /&gt;Enabled=1&lt;br /&gt;ServerURL=https://crash-reports.mozilla.com/submit&lt;br /&gt;&lt;br /&gt;其中ID表示xulrunner应用的唯一ID，在编写extension时须指定该extension能够应用的目标程序，在其install.rdf的targetApplication项的ID中指定已知的应用ID(也即xulrunner应用在其application.ini中指定的ID)。如Firefox的应用ID为{ec8030f7-c20a-464f-9b0e-13a3a9e97384}。&lt;br /&gt;&lt;br /&gt;3、创建xul、js文件；&lt;br /&gt;&lt;br /&gt;4、设置应用选项；&lt;br /&gt;在pref.js中指定Xulrunner应用程序启动的主窗口，如&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;pref("toolkit.defaultChromeURI", "chrome://myapp/content/main.xul");&lt;br /&gt;&lt;br /&gt;5、运行Xulrunner应用程序；&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;.\xulrunner\xulrunner.exe application.ini&lt;br /&gt;&lt;br /&gt;具体参考&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Getting_started_with_XULRunner" title="Getting started with XULRunner"&gt;Getting Started with XULRunner&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、Xulrunner和Firefox、ThunderBird等有什么区别?&lt;/span&gt;&lt;br /&gt;Xulrunner作为一个运行环境，以供他人开发基于Xulrunner、基于Gecko内核的应用程序，从Gecko1.9以后，从严格的意义来讲，Firefox、ThunderBird等是基于Xulrunner而开发的，也是一个Xulrunner应用，只不过它得到Mozilla官方的支持，它是浏览器。&lt;br /&gt;&lt;br /&gt;Mozilla在开发Firefox、Xulrunner、Gecko内核的过程中，不断的相互扩充，相互优化，相互促进，往往一个Firefox主要版本都对应一个Xulrunner版本，Xulrunner、Firefox对某一特性的支持程度有时有一些略微不一致，往往是由于对应版本未及时更新而造成的。&lt;br /&gt;&lt;br /&gt;自Firefox3.0以来，通过firefox.exe -app application.ini的调用方式同样可以运行一个Xulrunner应用，只不过此时该Xulrunner应用的Gecko内核是当前Firefox对应Gecko内核。&lt;br /&gt;&lt;br /&gt;到目前为止不同组织开发了许多基于Xulrunner的应用，如比较著名的有Songbird、Joost、Miro等等。&lt;br /&gt;&lt;br /&gt;具体可参考&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XULRunner_Hall_of_Fame" title="XULRunner Hall of Fame"&gt;XULRunner Hall of Fame&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、开发Xulrunner应用程序与Embedding Gecko有什么不同？&lt;/span&gt;&lt;br /&gt;以基于Xulrunner的方式开发应用，可以充分利用Gecko内核的所有功能(包括xul、xpcom、js等等)，入手比较简单，对开发者而言，只须专注实现自身所关心的部分，但要想真正开发出好的应用，需要对Gecko内核的方方面面拥有较深入的理解，难度较大，虽然其符合许多W3C标准，但Gecko内核的各个方面都自成一个体系(特别是xpcom)，与其他的库及开发平台的接口相对较少。同时Mozilla目前也推荐开发人员以运行平台的方式来利用Gecko内核。&lt;br /&gt;&lt;br /&gt;通过Embedding Gecko的方式来利用Gecko内核，其实现方式和可利用的外部库等都比较灵活，不一定只限于与Gecko相关的实现方式或外部动态库，其往往将Gecko内核作为一个相对独立的外部库使用，但由于目前Gecko内核在Embedding方面的接口有限，不能让外部程序充分利用Gecko内核的功能，从而限制了外部程序对其利用，同时如只利用Gecko内核中浏览页面的部分功能，而需要嵌入整个Gecko内核，有点得不偿失。&lt;br /&gt;&lt;br /&gt;究竟是使用Xulrunner的方式还是使用Embedding Gecko的方式来利用Gecko内核？&lt;br /&gt;这就存在一个取舍的问题，如只须嵌入浏览页面的功能，嵌入IE内核或Webkit内核，肯定方便很多，嵌入Gecko内核，稍现复杂，但嵌入的功能都相对有限；想更进一步了解嵌入Gecko内核的内容，可参考&lt;a href="http://ourpgh.blogspot.com/2008/08/geckoembedding.html"&gt;浅谈Gecko关键部分之十二Embedding&lt;/a&gt;一节。&lt;br /&gt;&lt;br /&gt;如使用Xulrunner的方式来利用Gecko内核，则须完全拥抱Xulrunner平台，可利用的功能丰富强大，需要学习研究的难度曲线较大，但是Mozilla毕竟是一个开源组织，其是否能提供一个高质量的可商用的运行环境，存在一定风险，有可能没有Microsoft、Adobe等商业公司提供的平台那样得到更广泛的支持。虽然如此，但其开放程度及对Web技术趋势的创新是独一无二的，再说目前其提供的文档越来越规范，应用越来越多。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、总结&lt;/span&gt;&lt;br /&gt;总的说来，如想真正深入的了解Web技术或浏览器，使用Xulrunner是个非常好的选择，但代价可能较高，如一旦真正掌握，则至少Web技术实力会很强；&lt;br /&gt;&lt;br /&gt;如只是利用Web技术或浏览器，完全可抛开Gecko内核，利用IE内核或Webkit内核，来运用Web技术，但对Web技术的真正把握可能不是很深入；&lt;br /&gt;&lt;br /&gt;作为一个开源爱好者，想更深入了解Web技术或浏览器，作手学习研究使用Firefox、Xulrunner等Gecko内核相关应用程序，是个不错的选择，因为它提供了很多非常不错的Web技术及工具如ajax、firebug、xul、venkman等；经过一定时间的运用，一定会收获颇多！&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XULRunner"&gt;Mozilla Developer center -XULRunner&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/XULRunner"&gt;Wiki XULRunner&lt;/a&gt;&lt;br /&gt;&lt;a set="yes" linkindex="38" href="http://developer.mozilla.org/en/docs/XULRunner:What_XULRunner_Provides" title="XULRunner:What XULRunner Provides"&gt;What XULRunner Provides&lt;/a&gt;&lt;br /&gt;&lt;a set="yes" linkindex="39" href="http://developer.mozilla.org/en/docs/XULRunner_FAQ" title="XULRunner FAQ"&gt;XULRunner FAQ&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-6174419785076582820?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/6174419785076582820/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=6174419785076582820' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6174419785076582820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6174419785076582820'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/geckoxulrunner.html' title='浅谈Gecko关键部分之十三Xulrunner'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-4852198687301362592</id><published>2008-08-09T08:35:00.000+08:00</published><updated>2008-08-09T11:32:07.660+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活随想'/><title type='text'>奥运真的来啦！</title><content type='html'>2008年8月8日20时，令人期盼以久激动人心的时刻终于来到，第29届北京奥林匹克运动会在北京鸟巢体育馆开幕啦！&lt;br /&gt;&lt;br /&gt;经过洋洋洒洒4个多小时的激情澎湃之后，开幕式结束了，令人回味无穷。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、鲜明的主题，展示出中华民族&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;灿烂&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;辉煌的历史文化画卷&lt;/span&gt;&lt;br /&gt;充分利用灯光道具的奇特效果，以历史画卷的形式，向全世界人民展现中华民族的重大历史时刻、思想文化现象等如击鼓、太极、丝绸之路、清明上河图、长城、京剧、木偶等，构思奇特，令人赞叹；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、灯火辉煌，渲染北京，照耀中华，展示追逐奥运之梦&lt;/span&gt;&lt;br /&gt;利用中华传统焰火，以历史足迹的形式，展现中华儿女百年追逐奥运之梦。客观而现实，令人感慨，回想起亲身经历的2001年7月13日奥运申办成功后的北京不眠之夜，天安门、西单、王府井等到处都是热烈狂欢的人们，尽情展现追逐奥运之情，犹如今日，感慨、欣喜;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、令人感觉平淡的会歌及点火仪式&lt;/span&gt;&lt;br /&gt;回想起以前汉城、洛杉机、巴塞罗那、悉尼、雅典等近现代奥运会歌及点火仪式，心中重新唤起对奥林匹克运动的激情，对奥林匹克精神的敬仰、向往。而我们的会歌及点火仪式，似乎构思一般，没有充分体现出奥林匹克核心精神如激情、自然、创新、执着、更高、更快、更强等。。。&lt;br /&gt;&lt;br /&gt;也许奥林匹克精神本来就是泊来品，来自古老的西方，熊熊烈火能在古老的中华大地点燃，本身就象罗格、何振梁等所说本届奥运会是独一无二的，结点就在于此吧。&lt;br /&gt;&lt;br /&gt;也许我们有太多令人值得回味的历史画卷，令人痴迷，沉醉其中，几乎忘了外界的一切，或者想将外部的一切也融入其中。&lt;br /&gt;&lt;br /&gt;也许东西方的融合之路才逐步真正开始，近现代我们的激情、我们的创新、我们的自信、我们的文化、我们的思想、我们的体制等等正逐步追赶西方，正象夸父追日，有点真实而惭愧，但愿融合之路能令世人受益，让老百姓切切实实的受益，解放思想，提升生活质量，共同面对世界，实现共同之梦，真正实现One World One Dream，我们改变自己，改变世界。&lt;br /&gt;&lt;br /&gt;我们不卑不亢，不留恋过去，忘掉耻辱，昂首迎接现在，拥抱世界，面对挑战，真实而自然，以更高、更快、更强的心态去创造美好生活，再现辉煌。。。。&lt;br /&gt;&lt;br /&gt;一点感悟，可有偏颇？！但愿能激起一丝思考。。。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-4852198687301362592?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/4852198687301362592/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=4852198687301362592' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4852198687301362592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4852198687301362592'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/blog-post.html' title='奥运真的来啦！'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-8025195818365802797</id><published>2008-08-05T18:46:00.000+08:00</published><updated>2008-08-07T11:50:47.889+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Embedding'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='嵌入'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之十二Embedding</title><content type='html'>随着Gecko内核的广泛使用，人们会期望Gecko内核能作为一个相对独立的拥有能访问Web、解析Html、渲染页面等浏览器基本功能的动态库甚至作为一个ActiveX或GtkWidget以供其他程序将其嵌入，就像大家熟知的MyIE作为一个外壳程序将IE内核以ActiveX的方式嵌入到其中，这样外壳程序相对简单，往往基于应用层，而内核则专注于html、css、dom等浏览器核心部分的处理，一旦能将浏览器内核以相对固定相对简单的接口形式提供给外部程序使用，则会大大拓展其应用包括动态脚本语言如python、perl、ruby都可能将其应用其中，其他的外壳程序也会应运而生。其实IE内核及Safari内核Webkit都提供了相对简单固定的接口供外部调用，这样才有了MyIE及Safari。那么Gecko内核是否也有类似的接口，外部程序又是如何嵌入的，这些与IE内核及Webkit等有什么差别呢？&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、认识Embedding接口&lt;/span&gt;&lt;br /&gt;Gecko内核作为相对独立的部分嵌入到外部程序中，在本质上外部程序与Gecko内核的关系其实很类似Plugin与Gecko内核的关系，外部程序与Gecko内核需要分别实现一些接口，各负其责，以供对方调用，这样两者相互结合实现所要的功能。不过Gecko内核官方目前提供给外部调用的接口封装得不是很简单，使用起来也不是非常的方便，但通过对GTKMozEmbed、winEmbed等的了解，Gecko内核部分往往通过nsWebBrowser来实现public nsIWebBrowser、nsIWebNavigation、&lt;br /&gt;nsIWebBrowserSetup、nsIDocShellTreeItem、nsIBaseWindow、nsIWebBrowserPersist、nsIWebBrowserFocus、 nsIWebProgressListener等接口，以代表一个浏览器页面浏览实例；&lt;br /&gt;&lt;br /&gt;而外壳程序部分需要实现nsIWebBrowserChrome、nsIEmbeddingSiteWindow、nsIWebProgressListener、nsISHistoryListener、nsIContextMenuListener等接口以代表一个浏览器页面浏览外壳，供Gecko内核调用。&lt;br /&gt;&lt;br /&gt;其中nsWebBrowser初始化后通过setcontainerWindow来设置其nsIWebBrowserChrome containerWindow为其对应的外壳实现，然后通过InitWindow、Create等方法可真正创建一个浏览器页面浏览实例，而外壳实现通过设置其nsIWebBrowser webBrowser为前面初始化的nsWebBrowser实例，这样两者可互为引用，同时外壳部分可向nsWebBrowser添加一些如WebProgress、ContextMenu等listener，以供Gecko内核nsWebBrowser需要时调用通知。&lt;br /&gt;&lt;br /&gt;另外外壳部分需要实现接口nsIWindowCreator，并通过调用window watch service的方法&lt;span style="font-family:monospace;"&gt;se&lt;/span&gt;tWindowCreator来告诉window watch service由外壳部分来createChromeWindow，以保证内核在由页面脚本通过window.open来打开新窗口时统一由外壳部分来创建新开的窗口。&lt;br /&gt;&lt;br /&gt;上面提到的是Gecko内核为了实现Embedding，需要由内核部分与外壳部分分别实现的基本接口及相关调用关系，其中Gecko内核还提供有诸如NS_InitEmbedding、NS_TermEmbedding等XPCOM方面的接口以供外壳部分充分利用Gecko内核提供的XPCOM强大组件管理等功能。&lt;br /&gt;&lt;br /&gt;为了更方便外壳程序的调用，Gecko也提供了诸如GtkMozEmbed widget及MozApp、MozView、 MozViewListener等，其实质仍属于上面提到的外壳部分，只不过更加的方便用户使用罢了。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、外部程序如何嵌入Gecko内核&lt;/span&gt;&lt;br /&gt;为了能真正了解如何将目前的Gecko内核嵌入到外部程序中，最好还是先参考&lt;a href="http://developer.mozilla.org/en/docs/Roll_your_own_browser_-_An_embedding_HowTo"&gt;Roll your own browser - An embedding HowTo&lt;/a&gt;按照其提供的编译方式，了解TestGtkEmbed、mfcEmbed等实现。通过对这些实例的了解才能对嵌入Gecko内核有一定的了解。&lt;br /&gt;&lt;br /&gt;外部程序嵌入Gecko内核的主要步骤如下：&lt;br /&gt;1、通过NS_InitEmbedding初始化内核；&lt;br /&gt;2、通过 do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &amp;amp;rv)创建mWebBrowser；&lt;br /&gt;3、创建实现nsIWebBrowserChrome、nsIEmbeddingSiteWindow接口实例mpBrowserImpl；&lt;br /&gt;4、创建绑定窗口&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;mpBrowserImpl-&gt;Init(mpBrowserFrameGlue, mWebBrowser);&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;mWebBrowser-&gt;SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome*, mpBrowserImpl));&lt;br /&gt;&lt;br /&gt;nsCOMPtr&lt;nsiwebbrowsersetup&gt;setup(do_QueryInterface(mWebBrowser));  &lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;if (setup)&lt;br /&gt;  setup-&gt;SetProperty(nsIWebBrowserSetup::SETUP_IS_CHROME_WRAPPER,PR_TRUE);&lt;br /&gt;&lt;br /&gt;rv = mBaseWindow-&gt;InitWindow(nsNativeWidget(m_hWnd),   nsnull,0, 0, rcLocation.right - rcLocation.left, rcLocation.bottom - rcLocation.top);&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;rv = mBaseWindow-&gt;Create();&lt;br /&gt;&lt;br /&gt;5、添加监听&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;void mWebBrowser-&gt;AddWebBrowserListener(weakling, NS_GET_IID(nsIWebProgressListener));&lt;br /&gt;&lt;br /&gt;6、设定WindowCreator、preference及promptservice等；&lt;br /&gt;&lt;br /&gt;7、装载页面mWebNav＝nsCOMPtr&lt;nsiwebnavigation&gt;setup(do_QueryInterface(mWebBrowser));&lt;br /&gt;if(mWebNav)&lt;span style="font-family:monospace;"&gt;&lt;br /&gt; &lt;/span&gt;mWebNav-&gt;loadURI();&lt;br /&gt;&lt;br /&gt;8、通过NS_TermEmbedding卸载内核，退出程序；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、&lt;/span&gt;&lt;/nsiwebnavigation&gt;&lt;/nsiwebbrowsersetup&gt;&lt;span style="font-weight: bold;"&gt;与IE内核、Webkit等嵌入方面的差别&lt;/span&gt;&lt;br /&gt;同样作为浏览器内核，其实有很多文章就Gecko内核、IE内核、Webkit等多方面进行过比较如&lt;a href="http://en.wikipedia.org/wiki/Comparison_of_layout_engines" title="Comparison of layout engines"&gt;Comparison of layout engines&lt;/a&gt;。但就嵌入易用方面来讲，它们之间差别还是蛮大的，个人认为IE内核充分利用windows com技术，作为一个独立的ActiveX，其拥有很好接口封装，对windows用户来讲，大大提高了其易用性复用性；&lt;br /&gt;&lt;br /&gt;Webkit内核本身一开始就专注于浏览器内核部分如KHTML、KJS，其提供给windows、gtk、mac等方面的接口也相对完毕；&lt;br /&gt;&lt;br /&gt;Gecko内核往往不仅仅专注于浏览器内核如HTML、Javascript等方面，同时它还提供了XPCOM、XUL，从大的方面看，嵌入Gecko内核访问通用的html类的Web网站，只利用了其中一部分功能，其XUL、XPCOM等功能几乎可以不用，这样一来也是一种浪费，所以目前Embedding方面的接口，既要考虑到XPCOM方面，又要考虑到用户嵌入内核的易用性，显然没有IE内核及Webkit内核，简单明了，要想嵌入Gecko内核，需要对其进行深入的了解，这样反而降低了嵌入的意义。&lt;br /&gt;&lt;br /&gt;顺便提一下，Avant/Orca Browser创始人宣称花了3年多的时间才将Gecko内核研究透彻，弄出个基于Gecko内核的浏览器Orca Browser，但其利用方式，不是基于Embedding的，而是基于Xulrunner的，这样既迎合了Gecko本身，同时能充分利用其强大功能，可谓一举两得，但是要想用好它，可要花上3、5年功夫不可。&lt;br /&gt;&lt;nsiwebbrowsersetup&gt;&lt;nsiwebnavigation&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;其实目前通过Embedding的方式使用Gecko内核的还不是很多，使用起来也比较困难，需要较深入的了解XPCOM等内核知识，比较好的实例也就只有上面提到的TestGtkEmbed、mfcEmbed等，可喜的是Mozilla最近似乎想重新加强其对Embedding方面的支持。详见&lt;a href="http://wiki.mozilla.org/Embedding/NewApi"&gt;Embedding/NewApi&lt;/a&gt; 及&lt;a href="http://www.0xdeadbeef.com/weblog/?p=359"&gt;Chris Blizzard's blog&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;另外&lt;a href="http://wiki.secondlife.com/"&gt;Second life&lt;/a&gt;提供了一组接口以更加方便嵌入Gecko内核。详见&lt;a href="http://ubrowser.com/"&gt;uBrowser and LLMozLib&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/embedding/"&gt;Mozilla project Embedding Mozilla&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Embedding_Mozilla"&gt;Mozilla developer center-Embedding Mozilla&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Mozilla_Embedding_FAQ"&gt;Mozilla Embedding FAQ&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Gecko_Embedding_Basics"&gt;Gecko Embedding Basics&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Mozilla_embedding_APIs_overview"&gt;Mozilla embedding APIs overview&lt;/a&gt;&lt;/nsiwebnavigation&gt;&lt;/nsiwebbrowsersetup&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-8025195818365802797?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/8025195818365802797/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=8025195818365802797' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/8025195818365802797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/8025195818365802797'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/geckoembedding.html' title='浅谈Gecko关键部分之十二Embedding'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-4615247387284471233</id><published>2008-08-02T07:33:00.000+08:00</published><updated>2008-08-19T15:07:23.039+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Extension'/><category scheme='http://www.blogger.com/atom/ns#' term='Add-on'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='外挂'/><category scheme='http://www.blogger.com/atom/ns#' term='扩展'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之十一Extension</title><content type='html'>Extension扩展或称Add-on外挂这些日子随着Firefox3的发布，逐步走入人们的视野，并且有些Extension确实赋有强大的功能，其中不乏有google、yahoo!等这样的大公司打造，甚至有人由此提出Firefox3掀起新的浏览器开发应用模式。那究竟什么是Extension？如何编写Extension?编写Extension需要哪些知识？它与plugin、xpcom等开发有什么不一样？为了解答心中疑问，下面分别就这些问题予以学习研究探讨。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是Extension?&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Extensions&lt;/b&gt; add new functionality to Mozilla applications such as Firefox and Thunderbird. They can add anything from a toolbar button to a completely new feature. They allow the application to be customized to fit the personal needs of each user if they need additional features, while keeping the applications small to download.&lt;br /&gt;&lt;br /&gt;它从小方面看，其实就是为Firefox等添加一些小的功能，如在菜单栏、地址栏、状态栏等添加一些小的按钮以扩展功能，有些类似于为IE等浏览器的工具栏、菜单栏等添加新的选项。&lt;br /&gt;&lt;br /&gt;但从本质上看由于Gecko内核提供了xul、xpinstall、xpconnect、javascript、xpcom、rdf等相关技术，使得可通过extension的方式几乎可以扩展浏览器方方面面的内容(这一点完全可从&lt;a href="https://addons.mozilla.org/zh-CN/firefox"&gt;Firfox Add-ons&lt;/a&gt;繁多种类的extension中窥见其一班)，更为特别的是整个浏览器Firefox本身几乎就是通过extension方式来实现的，完全超越了传统的扩展IE等浏览器的方式，同时gecko内核提供了包括extension资源标识、卸载安装等一系列支持，以便快速便捷为浏览器开发extension。&lt;br /&gt;&lt;br /&gt;Gecko内核有这种对extension全方位的支持，仅此就完全超越了opera、safari、ie等传统浏览器内核，进而开拓出一种新的&lt;em&gt;RIA&lt;/em&gt;（Rich Internet Application，富互联网应用系统）应用方式，虽然没有象microsoft、adobe等公司对xaml、flex那样的商业支持，但Gecko内核在RIA应用开发方面的技术研究、实现方式探索、还有开放方面等，都是首屈一指的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、如何编写Extension?&lt;/span&gt;&lt;br /&gt;编写一个简单的Extension其实非常的简单，参考&lt;a href="http://developer.mozilla.org/en/docs/Building_an_Extension"&gt;Building an extension&lt;/a&gt;一步一步的来设定extension资源标识rdf文件、chrome及manifest等包固定目录结构、编写js及xul文件、打包发布即可。&lt;br /&gt;&lt;br /&gt;其中较为关键的在于xul文件中对xul标签overlay的使用，简单来的说来就是extension想在firefox浏览器的菜单栏或状态栏等什么位置添加上你的extension内容。具体对xul标签overlay的使用可参考&lt;a href="http://developer.mozilla.org/en/docs/XUL_Overlays"&gt;XUL overlays&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;尽管js文件在xul文件中可以加载，但是extension作为对firefox浏览器的扩展，这些overlay xul文件，一般也是在浏览器主窗口文件browser.xul加载时一块加载的。这样如果你的extension有一些初始化的需求，只须在js文件中添加window.addeventlistener('load', initfunc,false)即可。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、编写Extension需要哪些知识？&lt;/span&gt;&lt;br /&gt;编写一个简单的extension需要的知识似乎不要太多，但是编写出一个切实可用的extension，必须对以下方面下番功夫不可。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;首先&lt;/span&gt; 对Firefox本身的实现需要有一定的认识，如对browser.xul、browser.js的了解等，了解extension的运作机制如什么时候启动extension、如何响应用户事件等。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;其次&lt;/span&gt; 对xul、html、js、xpconnect需要有基本的认识，了解extension的基本构成元素，进而了解Gecko内核为extension提供的可用资源，同时重点关注自身extension所涉及的相关内容如xpcom组件、plugin、css、dom等等。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;最后&lt;/span&gt; 充分利用已有工具如venkman、dom inspect、firebug、xpcomviewer等以提供开发效率。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、extension与plugin、xpcom等的区别&lt;/span&gt;&lt;br /&gt;extension作为一种对浏览器的扩展机制，而不是对Gecko内核的扩展机制，而plugin、xpcom往往扩展Gecko内核的基础内容，可看成是对Gecko内核的扩展。其中plugin的扩展往往与页面上某一块区域内容显示相关，而xpcom往往扩展Gecko内核基本组件等。&lt;br /&gt;&lt;br /&gt;为了扩展浏览器应用(浏览器其实只是Gecko内核应用的一个典型代表)，extension则完全可以使用Gecko内核提供的各种机制及技术，同时其本身也可扩展Gecko内核如提供独立的plugin、xpcom组件来扩展浏览器应用。这样说来extension开发，也可包括plugin、xpcom等等方面的开发，就看你所扩展的应用需求啦。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、总结&lt;/span&gt;&lt;br /&gt;&lt;a href="https://addons.mozilla.org/zh-CN/firefox"&gt;Firfox Add-ons&lt;/a&gt;中提供了种类繁多的extensions给大家使用，其中不免有令人耳目一新的东西，令人感慨万千，进而发出互联网应用竟然可以这样的感慨。有了对extension的认识，我们就可以着手阅读他人所写的extension，更深入的了解Gecko内核，编写自己的extension，挖掘属于自己的互联网应用。&lt;br /&gt;&lt;br /&gt;总之对Gecko内核了解得越深，编写起extension来就越得心应手，其实写这一系列浅谈Gecko的文章也就是为了了解Gecko内核，能编写extension，进而开拓属于自己的Gecko内核应用、互联网应用。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、目前所关注的Firefox extensions&lt;/span&gt;&lt;br /&gt;Dom Inspector&lt;br /&gt;Firebug&lt;br /&gt;Venkman&lt;br /&gt;Xpcomviewer&lt;br /&gt;IE Tab&lt;br /&gt;Split Browser&lt;br /&gt;&lt;br /&gt;Weave     //有空可用用Mozilla主推的在线共享书签等&lt;br /&gt;PicLens  //一个超酷的3D在线图片、视频管理&lt;br /&gt;HttpFox//一个很好的http分析&lt;br /&gt;Gladder//一个蛮好用的代理&lt;br /&gt;Extension Developer&lt;br /&gt;&lt;strong&gt;&lt;a name="Delicious"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/strong&gt;Delicious&lt;br /&gt;&lt;br /&gt;DownloadHelper//可从多个站点下载视频和图片&lt;br /&gt;Feed Sidebar      //显示实时书签&lt;br /&gt;。。。。。。。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;七、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Extensions"&gt;Mozilla developer center -Extensions&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Building_an_Extension"&gt;Building An extension&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Extension_Frequently_Asked_Questions"&gt;Extension Frequently Asked Questions&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Setting_up_extension_development_environment"&gt;Setting up extension development environment&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Code_snippets"&gt;Code snippets&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XUL_Overlays"&gt;Mozilla developer center-XUL Overlays&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XUL_Tutorial:Overlays"&gt;XUL Tutorial:Overlays&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Add-on_%28Mozilla%29"&gt;WIKI Firefox extensions(Add-on)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/List_of_Firefox_extensions"&gt;WIKI List of Firefox extensions&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-4615247387284471233?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/4615247387284471233/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=4615247387284471233' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4615247387284471233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/4615247387284471233'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/08/geckoextension.html' title='浅谈Gecko关键部分之十一Extension'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-125993092333352762</id><published>2008-07-29T20:50:00.000+08:00</published><updated>2008-08-02T16:56:56.803+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='XUL'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之十XUL</title><content type='html'>Gecko内核作为一个功能强大的浏览器内核，其提出XUL(XML User Interface Language)，并且由该语言来实现整个浏览器Firefox界面部分，XUL的实现从另个角度扩充了浏览器内核渲染引擎的内涵，因为它不仅仅可渲染HTML，同时可以象渲染HTML一样渲染xul，这样将XUL与HTML同等看待的浏览器内核实在独无仅有，从这个角度讲Gecko内核的渲染机制比IE、Webkit、Opera等浏览器内核要强大好多倍，因为它们目前本身仅仅支持HTML的渲染。虽然windows推出的XAML、adobe推出的Flex/Laszlo、yahoo widgets等都具有类似功能，但毕竟还没有与浏览器完全整合在一起。这样看来XUL作为Gecko内核的一部分具有根本而独特的作用，那就让我们抽时间来好好了解了解这个XUL。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是XUL?&lt;/span&gt;&lt;br /&gt;&lt;b&gt;XUL&lt;/b&gt; (XML User Interface Language) is Mozilla's &lt;a href="http://developer.mozilla.org/en/docs/XML" title="XML"&gt;XML&lt;/a&gt;-based language that lets you build feature-rich cross platform applications that can run connected or disconnected from the Internet. These applications are easily customized with alternative text, graphics and layout so they can be readily branded or localized for various markets.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、XUL的实现机制&lt;/span&gt;&lt;br /&gt;为了充分的达到利用XML+JS来实现图形界面程序，XUL作为一门类似HTML的语言，其中定义了一组标签、事件处理机制、渲染方式等，这些定义没有得到W3C等国际标准组织确认，仅由Mozilla组织定义并实现，解析处理一个xul文件的过程与处理html文件的主要过程是类似的，只不过在content、layout等方面有较大的不同，同时xul文件中可以嵌入html标签，将xul标签与html标签完全融为一体来处理，其主要处理过程完全类似&lt;a href="http://ourpgh.blogspot.com/2008/07/geckothe-life-of-html-http-request.html"&gt;浅谈Gecko关键部分之四The life of an html http Request&lt;/a&gt;中所描述的。&lt;br /&gt;&lt;br /&gt;关于XUL具体定义的标签、CSS、事件处理等等，内容非常庞大，可具体参考下面提供的参考资源。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/XUL"&gt;WIKI XUL&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XUL"&gt;Mozilla developer center-xul&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XUL_Reference"&gt;XUL Reference&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/The_Joy_of_XUL"&gt;The Joy Of Xul&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XUL_Overlays"&gt;Xul Overlay&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/XUL_Tutorial"&gt;XUL Tutorial&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.xulplanet.com/"&gt;XUL PLANET&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Extensible_Application_Markup_Language"&gt;WIKI XAML&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Adobe_Flex"&gt;WIKI Adobe Flex&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Yahoo%21_Widgets"&gt;WIKI Yahoo! Widget&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-125993092333352762?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/125993092333352762/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=125993092333352762' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/125993092333352762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/125993092333352762'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/geckoxul.html' title='浅谈Gecko关键部分之十XUL'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-2350076003550690881</id><published>2008-07-28T18:25:00.000+08:00</published><updated>2008-08-02T16:56:19.262+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><category scheme='http://www.blogger.com/atom/ns#' term='插件'/><title type='text'>浅谈Gecko关键部分之九Plugin</title><content type='html'>Plugin作为一种对浏览器内核扩充的方式，为丰富浏览器应用提供了更加广阔的空间，如大家熟知的flash、java applet、window media player、vlc、adobe pdf等插件已经在人们的不知不觉中走到人们的生活当中，那么究竟什么是plugin？为firefox写的plugin能在其他浏览器中使用吗？如何为浏览器写plugin？浏览器实现plugin的机制及其基本原理如何？等等这些问题一直困扰在心头，现就这几方面来了解了解Gecko内核中的plugin实现等。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是plugin?&lt;/span&gt;&lt;br /&gt;大家以前应该接触过一些关于plugin插件的概念，如eclipse就提供了很好的插件机制，以扩展ide的功能，apache也提供了丰富的插件机制，以丰富http server的处理请求。他们都有一个共同的特点就是&lt;span style="font-weight: bold;"&gt;以独立动态库的形式存在，动态库提供的输出接口应该满足主程序所规定的一些要求，以向主程序描述自身的特性及主要功能；而主程序也提供一组公共函数接口以供动态库调用，这样协同作业以完成任务。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在Gecko内核中plugin通过扩展html标签embed、object的MIMEtype类型的方式来拓展显示在一个页面中指定区域的内容。如大家熟知的application/x-shockwave-flash、application/x-java-applet、application/x-vlc-plugin等等，每一个plugin须说明自身所能支持的mime类型。一旦页面中遇到指定标签embed或object的mime类型，gecko内核就会搜索它目前所能支持的mime类型及对应的plugin，然后调用plugin中输出的接口由plugin来完成指定区域内的内容显示。&lt;br /&gt;&lt;br /&gt;在Gecko内核中，就扩展的方向及方式的不同，plugin与xpcom拥有本质上的差别，plugin以扩展页面embed/object标签 mime类型的方式存在，往往与页面布局渲染相关，而xpcom是以扩展不同的组件种类，以实现不同内部功能的方式存在，它往往有更大的扩展空间包如字符串管理、线程管理、p2p传输管理等。他们的应用场景有本质上的差别，一般说来plugin相对内核而言更加独立如可以有独立的线程管理、内存管理、渲染方式等，而xpcom往往是内核中的一个组成部分。&lt;br /&gt;&lt;br /&gt;Gecko内核plugin机制的实现接口&lt;b&gt;Netscape Plugin Application Programming Interface&lt;/b&gt;&lt;br /&gt;简称为NPAPI，它提供了相当完备的跨平台的接口框架，其中包括对Stream、Security、Scripting等方面的支持，目前包括Firefox、Opera、Safari、部分IE等浏览器都支持符合NPAPI接口标准的插件来扩展浏览器的功能。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、如何编写plugin？&lt;/span&gt;&lt;br /&gt;为了能编写plugin，首先需要了解其主要API，下面四个函数接口往往需要由plugin实现并export出去，可由外部即浏览器内核调用。&lt;br /&gt;NPError WINAPI NP_Initialize(NPNetscapeFuncs* pFuncs);&lt;br /&gt;当该plugin动态库第一次加载后浏览器内核会调用该方法，其中参数为当前内核提供给plugin调用的函数接口，plugin往往会将这些接口保存下来，以待以后使用；&lt;br /&gt;&lt;br /&gt;NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pFuncs);&lt;br /&gt;浏览器内核初始plugin动态库后，会调用该方法以获取该plugin实现的接口函数，内核会根据具体情况的不同来调用该plugin提供的不同接口函数；&lt;br /&gt;&lt;br /&gt;NPError WINAPI NP_Shutdown();&lt;br /&gt;当浏览器内核需要释放该plugin动态库时会调用该方法以告诉plugin其将会被释放；&lt;br /&gt;&lt;br /&gt;char* NP_GetMIMEDescription(void);&lt;br /&gt;浏览器内核通过该方法可获得该plugin支持的MIME类型，以便在解析页面embed/object标签时匹配其Type是否由哪个plugins来支持；&lt;br /&gt;&lt;br /&gt;typedef struct _NPPluginFuncs {&lt;br /&gt;  uint16 size;&lt;br /&gt;  uint16 version;&lt;br /&gt;  NPP_NewUPP newp;&lt;br /&gt;  NPP_DestroyUPP destroy;&lt;br /&gt;  NPP_SetWindowUPP setwindow;&lt;br /&gt;  NPP_NewStreamUPP newstream;&lt;br /&gt;  NPP_DestroyStreamUPP destroystream;&lt;br /&gt;  NPP_StreamAsFileUPP asfile;&lt;br /&gt;  NPP_WriteReadyUPP writeready;&lt;br /&gt;  NPP_WriteUPP write;&lt;br /&gt;  NPP_PrintUPP print;&lt;br /&gt;  NPP_HandleEventUPP event;&lt;br /&gt;  NPP_URLNotifyUPP urlnotify;&lt;br /&gt;  JRIGlobalRef javaClass;&lt;br /&gt;  NPP_GetValueUPP getvalue;&lt;br /&gt;  NPP_SetValueUPP setvalue;&lt;br /&gt;} NPPluginFuncs;&lt;br /&gt;&lt;br /&gt;typedef struct _NPNetscapeFuncs {&lt;br /&gt;  uint16 size;&lt;br /&gt;  uint16 version;&lt;br /&gt;  NPN_GetURLUPP geturl;&lt;br /&gt;  NPN_PostURLUPP posturl;&lt;br /&gt;  NPN_RequestReadUPP requestread;&lt;br /&gt;  NPN_NewStreamUPP newstream;&lt;br /&gt;  NPN_WriteUPP write;&lt;br /&gt;  NPN_DestroyStreamUPP destroystream;&lt;br /&gt;  NPN_StatusUPP status;&lt;br /&gt;  NPN_UserAgentUPP uagent;&lt;br /&gt;  NPN_MemAllocUPP memalloc;&lt;br /&gt;  NPN_MemFreeUPP memfree;&lt;br /&gt;  NPN_MemFlushUPP memflush;&lt;br /&gt;  NPN_ReloadPluginsUPP reloadplugins;&lt;br /&gt;  NPN_GetJavaEnvUPP getJavaEnv;&lt;br /&gt;  NPN_GetJavaPeerUPP getJavaPeer;&lt;br /&gt;  NPN_GetURLNotifyUPP geturlnotify;&lt;br /&gt;  NPN_PostURLNotifyUPP posturlnotify;&lt;br /&gt;  NPN_GetValueUPP getvalue;&lt;br /&gt;  NPN_SetValueUPP setvalue;&lt;br /&gt;  NPN_InvalidateRectUPP invalidaterect;&lt;br /&gt;  NPN_InvalidateRegionUPP invalidateregion;&lt;br /&gt;  NPN_ForceRedrawUPP forceredraw;&lt;br /&gt;} NPNetscapeFuncs;&lt;br /&gt;NPPluginFuncs、 NPNetscapeFuncs结构中的函数接口分别由plugin和浏览器内核提供实现，而让对方调用。每个接口的具体含义及什么时候调用可参考下面提到的相关资源。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、Gecko内核的plugin实现机制及基本原理&lt;/span&gt;&lt;br /&gt;Gecko内核作为外部调用plugin的主程序，它不仅提供一组NPNetscapeFuncs函数接口给plugin调用，同时需要管理所有的plugin动态库、针对不同embed/object创建不同的plugininstance以及相关安全、创建窗口句柄、释放资源等。&lt;br /&gt;&lt;br /&gt;在Gecko内核中提供了如下几个主要头文件、接口及类来完成相关任务。&lt;br /&gt;\mozilla\modules\plugin\base\public\Npapi.h&lt;br /&gt;\mozilla\modules\plugin\base\public\Npupp.h&lt;br /&gt;\mozilla\modules\plugin\base\public\Npruntime.h&lt;br /&gt;这几个头文件包含实现plugin所需要的函数接口、常量定义、数据结构定义等；&lt;br /&gt;&lt;br /&gt;nsIPluginTag.idl&lt;br /&gt;主要代表一个plugin动态库基本信息包括文件名、描述等；&lt;br /&gt;nsIPluginTagInfo.idl/nsIPluginTagInfo2.idl&lt;br /&gt;主要代表一个embed/object标签所描述的内容如MIME类型、参数、宽高等；&lt;br /&gt;nsIPlugin.idl&lt;br /&gt;主要描述一个plugin动态库所对应的initialize、shutdown、getMIMEDescription、getValue及创建plugin实例方法createPluginInstance，相当于plugin动态库加载后该plugin所提供的函数入口等；&lt;br /&gt;nsIPluginInstance.idl&lt;br /&gt;主要描述一个plugin动态库所实现的一个plugin实例所对应的函数接口，如initialize、start、stop、destroy、setWindow、newStream、getValue、handleEvent等；&lt;br /&gt;nsIPluginHost.idl&lt;br /&gt;主要描述如何装载plugin动态库、实例化EmbededPlugin、FullPagePlugin、检查指定MIME类型是否有对应plugin来实现等；&lt;br /&gt;&lt;br /&gt;由类nsPluginHostImpl来代表"@mozilla.org/plugin/manager;1"、"@mozilla.org/plugin/host;1"来管理plugin等；它主要实现了接口nsIPluginHost、nsIPluginManager2等，提供了&lt;br /&gt;void loadPlugins();&lt;br /&gt;nsIPlugin getPluginFactory(in string aMimeType);&lt;br /&gt;void instantiateEmbeddedPlugin(in string aMimeType, in nsIURI aURL, in nsIPluginInstanceOwner aOwner);&lt;br /&gt;void setUpPluginInstance(in string aMimeType, in nsIURI aURL, in nsIPluginInstanceOwner aOwner);&lt;br /&gt;void stopPluginInstance(in nsIPluginInstance aInstance);&lt;br /&gt;等主要方法；&lt;br /&gt;&lt;br /&gt;由类ns4xPlugini来实现nsIPlugin接口，其中维护了上面提到的函数接口&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NPPluginFuncs fCallbacks;&lt;/span&gt;&lt;br /&gt;PRLibrary*    fLibrary;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NP_PLUGINSHUTDOWN fShutdownEntry;&lt;/span&gt;&lt;br /&gt;/**&lt;br /&gt; * The browser-side callbacks that a 4.x-style plugin calls.&lt;br /&gt;*/&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;static NPNetscapeFuncs CALLBACKS;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在nsPluginHostImpl.cpp中通过static nsActivePluginList *gActivePluginList;来维护一组当前活动的plugin&lt;br /&gt;class nsActivePluginList&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;nsActivePlugin * mFirst;&lt;br /&gt;nsActivePlugin * mLast;&lt;br /&gt;PRInt32 mCount;&lt;br /&gt;................................&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct nsActivePlugin&lt;br /&gt;{&lt;br /&gt;nsActivePlugin*        mNext;&lt;br /&gt;char*                  mURL;&lt;br /&gt;nsIPluginInstancePeer* mPeer;&lt;br /&gt;nsRefPtr&lt;nsplugintag&gt;  mPluginTag;&lt;br /&gt;nsIPluginInstance*     mInstance;&lt;br /&gt;PRTime                 mllStopTime;&lt;br /&gt;PRPackedBool           mStopped;&lt;br /&gt;PRPackedBool           mDefaultPlugin;&lt;br /&gt;PRPackedBool           mXPConnected;&lt;br /&gt;//Array holding all opened stream listeners for this entry&lt;br /&gt;nsCOMPtr &lt;nsisupportsarray&gt;  mStreams;&lt;br /&gt;.........................................&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;由nsPluginHostImpl、ns4xPlugin及nsActivePluginList等类能够维护好plugin动态库的加载、创建一个新plugin实例等，哪究竟是由谁来加载动态库、创建新的plugin实例呢？&lt;br /&gt;&lt;br /&gt;作为一个html embed/object标签，其对应的元素为nsHTMLObjectElement，其继承自nsGenericHTMLFormElement、nsObjectLoadingContent、nsIDOMHTMLObjectElement，其中nsObjectLoadingContent提供了下面主要的方法&lt;br /&gt;nsObjectLoadingContent::LoadObject(const nsAString&amp;amp; aURI,&lt;br /&gt;                                 PRBool aNotify, const nsCString&amp;amp; aTypeHint, PRBool aForceLoad)&lt;br /&gt;&lt;br /&gt;nsresult nsObjectLoadingContent::TryInstantiate(const nsACString&amp;amp; aMIMEType,&lt;br /&gt;                                     nsIURI* aURI)&lt;br /&gt;&lt;br /&gt;而nsHTMLObjectElement往往对应有nsObjectFrame；其中包含有 nsRefPtr&lt;nsplugininstanceowner&gt; mInstanceOwner;&lt;br /&gt;&lt;br /&gt;而nsPluginInstanceOwner中含有如下元素：&lt;br /&gt;nsPluginNativeWindow       *mPluginWindow;&lt;br /&gt;nsCOMPtr&lt;nsiplugininstance&gt; mInstance;&lt;br /&gt;nsObjectFrame              *mOwner;&lt;br /&gt;nsCOMPtr&lt;nsicontent&gt;        mContent;&lt;br /&gt;nsCString                   mDocumentBase;&lt;br /&gt;char                       *mTagText;&lt;br /&gt;nsCOMPtr&lt;nsiwidget&gt;         mWidget;&lt;br /&gt;nsCOMPtr&lt;nsitimer&gt;          mPluginTimer;&lt;br /&gt;nsCOMPtr&lt;nsipluginhost&gt;     mPluginHost;&lt;br /&gt;&lt;br /&gt;有了对基本的数据结构理解之后这样在parser html内容时，会根据embed/object标签创建nsHTMLObjectElement、nsObjectFrame、nsPluginInstanceOwner等实例，进而在nsHTMLObjectElement的LoadObject方法驱动下逐步的调用TryInstantiate、Instantiate、InstantiateEmbeddedPlugin、TrySetUpPluginInstance、Create4xPlugin等等，从而完成一个plugin实例的生成等。&lt;br /&gt;&lt;br /&gt;至于其Scripting、Stream、security方面的支持须进一步参考nsIDOMClassInfo、nsGenericHtmlObjectSH及nsIPluginStreamListener等；&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;通过初步了解plugin的实现机制后，然后自己动手参照Mozilla提供的plugin examples及相关API，完成一个基本的Plugin难度其实并不大，但是如想利用plugin技术实现如3D、Stream Media、叠加等方面的效果，须更进一步的了解3D、Stream Media等方面的内容。其实支持Gecko内核的Plugin相当多，如主流的播放器、flash、java applet、silverlight等等都有浏览器插件，再加上支持Gecko内核的plugin一般也支持Opera、Safari，这样如果我们掌握了NPAPI Plugin技术，那么我们就可以充分运用已有的plugin或自己动手创建一个好用的plugin，这样会大大的扩展浏览器的应用，让我们拭目以待吧。。。。。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/NPAPI"&gt;WIKI NPAPI&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/plugins/"&gt;Mozilla projects -plugins&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Plugins"&gt;Mozilla developer center -plugins&lt;/a&gt;&lt;br /&gt;&lt;a href="http://web.archive.org/web/20040203041440/http://devedge.netscape.com/library/manuals/2002/plugin/1.0/"&gt;Netscape Gecko Plugin API Reference&lt;/a&gt;&lt;br /&gt;&lt;a href="http://plugindoc.mozdev.org/windows-all.html"&gt;Mozilla Plugin Support on Microsoft Windows&lt;/a&gt;&lt;/nsipluginhost&gt;&lt;/nsitimer&gt;&lt;/nsiwidget&gt;&lt;/nsicontent&gt;&lt;/nsiplugininstance&gt;&lt;/nsplugininstanceowner&gt;&lt;/nsisupportsarray&gt;&lt;/nsplugintag&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-2350076003550690881?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/2350076003550690881/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=2350076003550690881' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/2350076003550690881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/2350076003550690881'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/geckoplugin.html' title='浅谈Gecko关键部分之九Plugin'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-6697166835440555434</id><published>2008-07-24T21:22:00.000+08:00</published><updated>2008-08-02T16:55:41.902+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='APR'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><category scheme='http://www.blogger.com/atom/ns#' term='NSPR'/><title type='text'>浅谈Gecko关键部分之八NSPR</title><content type='html'>Gecko内核作为一个跨平台的内核，具有很强的跨平台系统处理能力，其中就缺不了Netscape Portable Runtime (NSPR)的功劳，要想深入的了解Gecko内核，就不得不了解了解NSPR，它提供了基础性系统性功能的封装，在此基础上才有了线程管理、内存管理、I/O管理等等，下面提供一些资料以供参考学习。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是NSPR?&lt;/span&gt;&lt;br /&gt;The &lt;b&gt;Netscape Portable Runtime&lt;/b&gt;, or &lt;b&gt;NSPR&lt;/b&gt;, is a &lt;a href="http://en.wikipedia.org/w/index.php?title=Platform_abstraction_library&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Platform abstraction library (page does not exist)"&gt;platform abstraction library&lt;/a&gt; that makes all &lt;a href="http://en.wikipedia.org/wiki/Operating_system" title="Operating system"&gt;operating systems&lt;/a&gt; it supports appear the same to &lt;a href="http://en.wikipedia.org/wiki/Mozilla" title="Mozilla"&gt;Mozilla&lt;/a&gt;. NSPR provides &lt;a href="http://en.wikipedia.org/wiki/Platform_independence" class="mw-redirect" title="Platform independence"&gt;platform independence&lt;/a&gt; for &lt;a href="http://en.wikipedia.org/w/index.php?title=Non-GUI&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Non-GUI (page does not exist)"&gt;non-GUI&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Operating_system" title="Operating system"&gt;operating system&lt;/a&gt; facilities. These facilities include &lt;a href="http://en.wikipedia.org/wiki/Thread" title="Thread"&gt;threads&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Thread_synchronization" class="mw-redirect" title="Thread synchronization"&gt;thread synchronization&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/w/index.php?title=Normal_file&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Normal file (page does not exist)"&gt;normal file&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/w/index.php?title=Network_I/O&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Network I/O (page does not exist)"&gt;network I/O&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/w/index.php?title=Interval_timing&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Interval timing (page does not exist)"&gt;interval timing&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/w/index.php?title=Calendar_time&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Calendar time (page does not exist)"&gt;calendar time&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/w/index.php?title=Basic_memory_management&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Basic memory management (page does not exist)"&gt;basic memory management&lt;/a&gt; (&lt;a href="http://en.wikipedia.org/wiki/Malloc" title="Malloc"&gt;malloc&lt;/a&gt; and free) and &lt;a href="http://en.wikipedia.org/w/index.php?title=Shared_library_linking&amp;amp;action=edit&amp;amp;redlink=1" class="new" title="Shared library linking (page does not exist)"&gt;shared library linking&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;相关参考资源&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Netscape_Portable_Runtime"&gt;NSPR WiKi&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/nspr/index.html"&gt;Mozilla NSPR HomePage&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/nspr/reference/html/index.html"&gt;NSPR Reference&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、为什么了解NSPR?&lt;/span&gt;&lt;br /&gt;除了Gecko内核是基于NSPR的，其他一些应用也是基于NSPR；它具有很强的稳定性、可复用性等，了解NSPR，对了解Gecko内核是不可或缺的，就像想了解Apache Http Sever，就必须对APR有所了解。&lt;br /&gt;&lt;br /&gt;了解了NSPR，除了让我们能更好更快更清晰的了解Gecko内核，其实还可以让我们从另一个侧面更好的了解不同操作系统的主要差异如线程的实现、线程同步的实现、I/O管理的不同等等，从而提升我们对操作系统的认识，进一步的把握计算机技术。&lt;br /&gt;&lt;br /&gt;相关参考资源&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Apache_Portable_Runtime"&gt;Apache Portable Runtime(APR) WiKi&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer"&gt;Simple DirectMedia Layer(SDL) WiKi &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-6697166835440555434?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/6697166835440555434/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=6697166835440555434' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6697166835440555434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6697166835440555434'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/geckonspr.html' title='浅谈Gecko关键部分之八NSPR'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-8826809254201345334</id><published>2008-07-20T15:47:00.000+08:00</published><updated>2008-07-20T18:58:59.698+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='安全'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之七安全及其实现</title><content type='html'>很长一段时间以来Firefox以安全、小巧、快捷著称，从而逐步从饱受不安全批评的IE中抢夺到部分用户的支持，在用户心中确立了Firefox比IE更安全的想法，其实浏览器的安全一直受到人们的广泛关注，但往往不能做到百分百的完美，似乎总有一些遗憾的地方，正所谓道高一尺魔高一丈。为了更深入的了解浏览器技术，安全正可谓不得不面对的问题，也许它比较的复杂，涉及面比较广，还是让我们从安全问题的出现、Gecko内核的安全策略及其主要实现路径等方面来学习研究，以便达到以一窥十的效果。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、安全问题的出现&lt;/span&gt;&lt;br /&gt;浏览器作为一个通往互联网的入口，其可以连接访问的网站成千上万，并且类型也缤纷多彩，正是这一点突出了浏览器功能强大、实用的特点，进而确立其在互联网应用中不可缺失的地位，但同时也带来了人们的疑虑，我们刚才访问的网站是否下载了病毒、是否破坏了操作系统、提交的数据如用户名密码是否泄漏、访问的历史记录是否遭到外部网站的截取等等。这些问题从浏览器出现的一刻起就受到浏览器开发者的关注，到目前为止，有些浏览器还是受到人们广泛的质疑。&lt;br /&gt;&lt;br /&gt;其实困扰人们心中的浏览器安全问题往往可分为两类：&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;对用户本地私有数据的保护&lt;/span&gt;&lt;br /&gt;私有数据往往包含两方面，一方面在于操作系统的文件是否遭到访问、读写等，其实一旦存在这类漏洞，其危害是特别大的，往往会导致整个操作系统的不安全，我们以前通过IE访问不良网站时，经常会遭遇到木马等病毒的骚扰，其实问题的出现正是由于病毒利用了activex组件等方面的漏洞，从而重新配置操作系统，并下载病毒文件等。另一方面在于保护用户保存的Cookie、历史访问记录，提交的表单数据是否遭到非法访问，在同一浏览中同时打开的不同页面是否能相互访问，共享数据等。&lt;br /&gt;&lt;br /&gt;其实在浏览器设计之初就充分考虑到这些方面的问题，特别在javascript设计之初，因为浏览器能够执行外部网站的操作往往来源于javascript脚本，一旦能控制住浏览器为脚本提供的接口的安全性，浏览器的安全问题就得到架构上保证，再加上javascript本身是脚本语言，这样为任何一句脚本语言&lt;span style="font-weight: bold;"&gt;提供执行前的检查&lt;/span&gt;提供了可能。正是基于这样的出发点，&lt;span style="font-weight: bold;"&gt;javascript的实现是基于sanbox技术的&lt;/span&gt;，脚本语言的执行是在一个安全的上下文中进行的，它所造成的危害是可控的如从理论上讲，javascript是不可以访问操作系统文件的，是不可以上传不由用户指定的任意文件的。当然其中很多相关的安全细则可参考相关js手册，其实现是由内核来提供保证的。&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;对用户提交给网站数据的保护&lt;br /&gt;&lt;/span&gt;浏览器往往通过http协议来与网站进行数据交互，由于http协议属于应用层协议，交互的数据对网络层来讲是透明的，也是不安全的，作为一个能广泛使用的应用程序，为了满洲需对提供的银行帐户与密码进行加密等需求，浏览器必须提供一些数据加密措施来保证数据交互的安全。基于这一点及广泛标准的支持，Gecko内核采用了PKI开源应用模块(相对来说蛮独立)来保证数据加密的要求如对&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;PKCS #5, PKCS #7, PKCS #11, PKCS #12,  S/MIME, TLS, SSL v2 and v3, X.509 v3 certificates等方面的支持，而没有使用目前很多项目都采用的OpenSSL来对SSL的支持，不过SSL作为一个标准，无论采取OpenSSL还是PKI，只不过是实现上的不同而已。&lt;br /&gt;&lt;br /&gt;其中人们经常听说的反钓鱼技术，往往与此有点关联。&lt;br /&gt;网络钓鱼 (phishing)是国际通用的新字，取phreak(偷接电话线的人)的前两个字母ph取代fishing(钓鱼)的f，是以社会工程学（也就是骗术）结合电脑科技的新犯罪手法。&lt;br /&gt;&lt;br /&gt;网络钓鱼的目的是骗取受害人的网站上的帐号密码（网络银行或线上游戏）、信用卡资料以及个人资料，进行例如线上转帐、偷取游戏虚拟宝物、窥伺别人的email以及盗刷银行卡等违法行为。&lt;br /&gt;&lt;br /&gt;钓鱼正以一种新的犯罪形式侵犯，在不断侵犯普通网民的合法利益，具体表现在伪装“网络银行”窃取用户的银行卡卡号和密码，转走用户在银行的存款；伪装成网 络游戏的官方网站窃取用户的网游帐号，转走用户在游戏里面的虚拟货币或者虚拟装备； 伪装成送QQ币的网站让用户输入QQ号和密码进而窃取QQ号……&lt;br /&gt;&lt;br /&gt;其中Firefox应该是目前提供反钓鱼技术最好的浏览器，它不仅提供反盗取密码等网站，还提供反不安全、非法及含有黄色内容的网站。&lt;br /&gt;其实现机制往往结合nsIContentPolicy接口及维护后台不安全网站列表来共同实现。&lt;br /&gt;&lt;br /&gt;如须具体了解数据加密的内容，可更加深入的了解PKI OpenSource等方面的知识，这次主要学习研究对本地私有数据安全方面的内容。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、Gecko内核的安全策略&lt;/span&gt;&lt;br /&gt;为了保证数据的提交与行为的安全执行，Gecko内核中提供两种安全策略，Same-Origin Policy和Security Zones and Signed Scripts。&lt;br /&gt;&lt;br /&gt;其中Same-Origin Policy的主要含义在于一段脚本只能访问具有同一来源的window及document的内容，同一来源包括同一主机、同一端口、同一协议，同时为了对扩展域名的支持，同一来源也指具有同一&lt;tt&gt;domain的不同window及document&lt;/tt&gt;。&lt;br /&gt;&lt;br /&gt;而Security Zones and Signed Scripts指的是为了给一段脚本更高的访问权限，需要由用户确认后来授权该脚本可以拥有更高的权限。其实现的方式有通过SignTool及安全Jar的方式来授权、提示用户由用户来确认的方式来授权。其中前一种相当复杂，普通用户使用较少，而后一种方式应用较多，并且可以由用户自己来配置一些对象的属性、方法的访问权限或自定义一些域名浏览器访问权限，下面示例一些权限设置。&lt;br /&gt;user_pref("capability.policy.default.Window.open", "noAccess");&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;user_pref("capability.policy.policynames", "strict");&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt; user_pref("capability.policy.strict.sites", "http://www.evil.org http://www.annoying.com");   user_pref("capability.policy.strict.Window.alert", "noAccess");&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;user_pref("capability.policy.strict.Window.confirm", "noAccess");&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/span&gt;user_pref("capability.policy.strict.Window.prompt", "noAccess");&lt;br /&gt;&lt;br /&gt;user_pref("capability.principal.codebase.p2.granted", "UniversalXPConnect");&lt;br /&gt;user_pref("capability.principal.codebase.p2.id", "http://192.168.1.200");&lt;br /&gt;user_pref("capability.principal.codebase.p2.subjectName", "");&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;一段脚本可拥有的浏览器访问权限包括UniversalBrowserRead、UniversalBrowserWrite UniversalXPConnect、UniversalPreferencesRead、UniversalPreferencesWrite CapabilityPreferencesAccess、UniversalFileRead等，它们可以通过netscape.security.PrivilegeManager.enablePrivilege("UniversalPreferencesRead");等方式来设置权限，如果用户的signed.applets.codebase_principal_support配置选项设为true，在设置权限时会提示用户是否设置该codebase权限。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、安全主要实现路径&lt;/span&gt;&lt;br /&gt;首先由javascript SpiderMonkey提供了一组安全方面的接口，以供脚本安全的检查，至于具体的安全规则则由xpconnect及securitymanager来实现，主要接口有JSPrincials、JS_CheckAccess、&lt;br /&gt;JSObjectOps.checkAccess、JSClass.checkAccess、JS_SetPrincipalsTranscoder等；&lt;br /&gt;&lt;br /&gt;然后由nsScriptSecurityManager来管理维护其提供的nsPricipal实例及相关的安全检查，其中在其初始化时完成如下主要操作：&lt;br /&gt;&lt;br /&gt;nsresult nsScriptSecurityManager::Init()&lt;br /&gt;{&lt;br /&gt;    nsresult rv = InitPrefs();//将用户自定义的pricipal组织起来&lt;br /&gt;    NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;    。。。。。。。。。。。。。。。。&lt;br /&gt;    // Create our system principal singleton&lt;br /&gt;    nsRefPtr&lt;nssystemprincipal&gt; system = new nsSystemPrincipal();&lt;br /&gt;    NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);&lt;br /&gt;    rv = system-&gt;Init();&lt;br /&gt;    NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;    mSystemPrincipal = system;&lt;br /&gt;   。。。。。。。。。。。。。。。&lt;br /&gt;    //-- Register security check callback in the JS engine&lt;br /&gt;    //   Currently this is used to control access to function.caller&lt;br /&gt;    nsCOMPtr&lt;nsijsruntimeservice&gt; runtimeService =&lt;br /&gt;        do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &amp;amp;rv);&lt;br /&gt;    NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;    rv = runtimeService-&gt;GetRuntime(&amp;amp;sRuntime);&lt;br /&gt;    NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;    //CheckObjectAccess成为安全检查的主要入口点&lt;br /&gt;    &lt;span style="font-weight: bold;"&gt;JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    sXPConnect-&gt;GetXPCWrappedNativeJSClassInfo(&amp;amp;sXPCWrappedNativeJSClass,&lt;br /&gt;                                               &amp;amp;sXPCWrappedNativeGetObjOps1,&lt;br /&gt;                                               &amp;amp;sXPCWrappedNativeGetObjOps2);&lt;br /&gt;&lt;br /&gt;    return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;在实现的过程中会提供一些nsPrincipal实例如nsNullPrincipal、nsSystemPrincipal来表示不同的安全规则，同时每一个nsPricipal实例都包含一个JSPricipals接口实例，其内容可由JS_SetPrincipalsTranscoder来根据不同情况来设定，这样可以为不同的JSContext、JSClass、JSObject、JSFunction设置对应的JSPricipals，由它可以获得nsPrincipal实例，以了解真正的安全规则。&lt;br /&gt;&lt;br /&gt;其中&lt;span style="font-family: monospace;"&gt;由SpiderMonkey JS Engineer内部或Xpconnect、nsScriptSecurityManager等外部&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;在需要实施安全规则检查的地方如检查xpcom组件接口参数发起&lt;/span&gt;JS_CheckAccess的执行，其中会调用上面提到的回调函数CheckObjectAccess，&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;以触发nsSecurityManager来统一对安全的检查，起到sanbox的作用。具体的nsPricipal及nsSecurityManager的管理可参考\mozilla\caps\src\nsPricipal.cpp及nsScriptSecurityManger.cpp等，至于如何为JS对象设置一些JSPricipals则需要更深入对函数JS_SetPrincipalsTranscoder的调用与实现作一些了解。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、参考资源&lt;br /&gt;&lt;/span&gt;&lt;a href="http://www.mozilla.org/projects/security/components/reviewguide.html"&gt;Mozilla Security Review and Best Practices Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/security/components/same-origin.html"&gt;The Same Origin Policy&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/security/components/signed-scripts.html"&gt;Signed Scripts in Mozilla&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/security/components/ConfigPolicy.html"&gt;Configurable Security Policies&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/JSAPI_User_Guide"&gt;JSAPI User Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/projects/security/pki/"&gt;Open Source PKI Projects &lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-8826809254201345334?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/8826809254201345334/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=8826809254201345334' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/8826809254201345334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/8826809254201345334'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/gecko.html' title='浅谈Gecko关键部分之七安全及其实现'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-6863822990502776924</id><published>2008-07-13T01:22:00.000+08:00</published><updated>2008-07-13T02:33:33.073+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='DOM'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='SpiderMonkey'/><category scheme='http://www.blogger.com/atom/ns#' term='Xpconnect'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之六认识javascript实现及应用</title><content type='html'>作为一个目前应用范围非常广的脚本语言javascript，或许每一个程序员都听说过并使用过，但据部分统计，许多程序员对javascript的认识存在一定误解，认为它非常简单，会写javascript简直算不了什么，并且认为它在Web开发中的地位根本没有如php、ruby等开发语言及所谓的框架那么实用好用，以致没有重视javascript在Web开发中所应有的作用。为寻求Gecko内核究竟是如何实现javascript以及它在内核中的地位究竟如何，乃至进一步探讨一下javascript的发展方向，下面分别就什么是Javascript、它在Gecko中的实现及其扩展、应用等方面作一些学习研究总结，以致从整体上对javascript有更清晰的认识。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、什么是javascript?&lt;/span&gt;&lt;br /&gt;javascript是一门动态、弱类型、基于原型的脚本语言，其核心部分包含对脚本的编译、解析、执行、反编译、垃圾回收及标准类/类型如 bool、string、number的实现等；然后在此基础通过将已经符合DOM标准的文档DOM接口按照javascript接口定义及声明的方式绑定/导出到 javascript运行环境中，以丰富javascript的内涵，其本质相当于有了java虚拟机后，通过import不同类型的类库来扩展 java语言的应用。&lt;br /&gt;&lt;br /&gt;目前javascript比较独特的地方在于它自身没有一个完整独立的运行环境，其往往依附于浏览器，由浏览器来提供运行环境，并控制或发起javascript进行编译、解析执行脚本、垃圾回收等，其核心部分相当于一个符合ECMAScript标准的动态库，以供浏览器来调用，这样看来其本质是为了对浏览器主要部分的扩展及更灵活运用的支持，从MVC的角度来看，javascript相当于浏览器中的控制部分，其应用场景往往具有一定的局限性、独特性的；而通用的脚本语言如perl、python、 ruby等都提供了完整独立的语言运行环境及线程管理等，并且提供了良好的扩展机制以丰富语言的内涵。&lt;br /&gt;&lt;br /&gt;在Gecko内核中xpconnect扮演为javascript提供运行环境及扩展的角色，其不仅将符合DOM标准的接口扩展到javascript运行环境中去，同时将大部分xpcom接口也扩展到整个javascript运行环境中，这一点在其他浏览器如Safari、IE是没有的，这样就奠定了 javascript在整个Gecko内核中不仅可访问文档的DOM接口，同时可以访问极大部分xpcom接口，进而可以使用javascript编写 xpcom组件，以供其他xpcom组件访问。从架构的角度看Gecko内核对javascript的扩展提供了极大的支持，但由于Gecko内核中有一部分重要组件是由javascript来实现的，从而绑定javascript成为Gecko内核的核心部分，虽然这样给程序的开发带来了极大的方便性，但也带来了调试等方面的不便。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、javascript在Gecko中的实现及其扩展&lt;/span&gt;&lt;br /&gt;为了更好的扩展及模块化，Mozilla对 javascript的实现是以SpiderMonkey+xpconnect的方式来实现的，其中SpiderMonkey主要是按照 ECMAscript的方式来实现javascript语言的核心部分，其提供了一组公共JSAPI以供外部调用，SpiderMonkey是相当独立的一部分，它可以单独编译，可以嵌入到其他程序中去，下一个版本可能会整合Tamarin相关的内容；&lt;br /&gt;&lt;br /&gt;而xpconnect作为一个xpcom服务类组件，具有sington特性，从javascript 语言的角度来看，它为javascript提供了运行环境，同时按照SpiderMonkey提供的JSAPI对其进行了扩展；从xpcom角度来看，xpconnect将很大一部分xpcom接口以javascript的接口方式绑定出去，以便其能在javascript的运行环境中以 javascript的方式来引用xpcom组件及接口。其复杂程度是相当大的，因为它既要按照ECMAScript标准的要求考虑到脚本语言方面的控制如动态性、安全方面等，同时它要尽可能将xpcom组件方面的接口绑定出去给javascript脚本使用，并且两者的内存管理、对象生命周期的管理机制是完全不同的，再加上javascript及xpcom本身具有一定的动态特性。因此，xpconnect部分也就成为内存泄漏及效率提升方面的重点关注对象。&lt;br /&gt;&lt;br /&gt;SpiderMonkey按照ECMAScript标准提供的主要外部接口有：&lt;br /&gt;Starting up相关JS_NewRuntime、JS_NewContext、JS_NewObject、JS_InitStandardClasses&lt;br /&gt;Defining objects and properties相关JS_DefineObject、JS_DefineProperties&lt;br /&gt;Defining functions and classes相关JS_DefineFunctions、JS_InitClass&lt;br /&gt;Execute/Call function相关JS_EvaluateScript、JS_ExecuteScript、JS_CallFunctionName&lt;br /&gt;Shutting down相关JS_DestroyContext、JS_DestroyRuntime、JS_ShutDown&lt;br /&gt;其具体实现及应用可以参考后面提供的网址。&lt;br /&gt;&lt;br /&gt;xpconnect is a technology which enables simple interoperation between XPCOM and JavaScript.&lt;br /&gt;其主要内容有&lt;br /&gt;将用c/c++实现的xpcom组件接口(包含标准的DOM、CSS接口等)绑定出去给javascript运行环境使用。&lt;br /&gt;为了统一方便使用，Gecko内核提出供一组nsDOMClassInfo子类，如nsWindowSH、nsLocationSH、 nsElementSH、nsDocumentSH等，作为Script Helper类，他们实现了接口nsIXPCScriptable及nsIClassInfo。&lt;br /&gt;&lt;br /&gt;每当xpconnect需要将原生c/c++xpcom组件对象绑定给javascript使用时，它可通过 InitClassesWithNewWrappedGlobal或WrapNative方法来处理，但都会调用到 XPCConvert::NativeInterface2JSObject方法，这个方法主要处理过程是：&lt;br /&gt;首先获取该组件对象对应的nsDOMClassInfo子类实例，整个Gecko内核拥有很多Script Helper nsDOMClassInfo子类实例(其往往在初始化时存储在一个Hash表中，并建好相关查询索引)；&lt;br /&gt;&lt;br /&gt;然后利用获取的Script Helper nsDOMClassInfo子类实例的PreCreate方法来创建该组件对应的jsObject，同时会创建XPCWrappedNative类实例，在其中保存好mScriptableInfo信息，其如nsCOMPtr&lt;nsixpcscriptable&gt; mCallback往往为nsDOMClassInfo子类实例，&lt;br /&gt;&lt;br /&gt;如需要会为其创建prototype原型对象以便后面共享，这时需要向javascript运行环境提供一组回调API，其主要函数在 mozilla\js\src\xpconnect\Xpcwrappednativejsops.cpp中如 XPC_WN_Helper_AddProperty、XPC_WN_Helper_DelProperty、 XPC_WN_Helper_NewResolve等，通过观测这些回调函数发现他们往往首先会通过传递过来的jsObject获取 XPCWrappedNative对象，然后获取其ScriptableInfo,根据相关flag来决定是否调用Script Helper 实例中对应的方法，而Script Helper实例往往在初始时就已经知道原生绑定出去的xpcom组件能支持的一些xpcom接口，进而可以对原先不认识的接口、属性、方法、参数，进行 QueryInferface，进行WrapNative处理，将结果返回给js使用。&lt;br /&gt;&lt;br /&gt;其中需要注意的是有些组件或类对象没有直接实现nsIClassInfo，哪么nsCOMPtr&lt;nsiclassinfo&gt; info ＝do_QueryInterface(aComObj);是如何获得Script Helper nsIClassInfo 实例呢？&lt;br /&gt;&lt;br /&gt;费了九牛二虎之力，终于发现Gecko内核中使用了一些诡异的办法来到达目的的。示例如下：&lt;br /&gt;&lt;br /&gt;定义一个Macro&lt;br /&gt;#define NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class)                          \&lt;br /&gt;if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {                                \&lt;br /&gt;  foundInterface = NS_GetDOMClassInfoInstance(eDOMClassInfo_##_class##_id); \&lt;br /&gt;  if (!foundInterface) {                                                    \&lt;br /&gt;    *aInstancePtr = nsnull;                                                 \&lt;br /&gt;    return NS_ERROR_OUT_OF_MEMORY;                                          \&lt;br /&gt;  }                                                                         \&lt;br /&gt;} else&lt;br /&gt;&lt;br /&gt;而extern nsIClassInfo* NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID);就是根据ID到sClassInfoData数组中去匹配即可，这个数组在初始化时就填充完毕，其不同ID值对应不同的 nsIClassInfo 实例如nsWindowSH、nsDocumentSH实例等。&lt;br /&gt;&lt;br /&gt;而在\mozilla\dom\src\base\nsGlobalWindow.cpp中通过&lt;br /&gt;// QueryInterface implementation for nsGlobalChromeWindow&lt;br /&gt;NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)&lt;br /&gt;NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)&lt;br /&gt;NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ChromeWindow)&lt;br /&gt;NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)&lt;br /&gt;来设定do_QueryInterface时对nsIClassInfo的支持。&lt;br /&gt;另外还有一些类也是通过该方式来对nsIClassInfo的支持。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、javascript在Gecko中的应用&lt;/span&gt;&lt;br /&gt;在Gecko内核及Firefox本身的实现中使用了很多javascript代码，其中不仅仅是对基本javascript语言及DOM 接口的使用，同时充分利用了上面提到到xpcom绑定出去的组件接口，假如对xpcom及其绑定原理不是很清楚，也就对Firefox当中许多js看不懂，往往让人纳闷Gecko内核中的js为什么会多出这么多非ECMAScript所定义的关键字如Components&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;、interfaces、classes等，其具体含义是什么？虽然XULPlant.org对其中有一定的说明，但还是显得抽象，不具体。在有了上面最基本的认识后，如需全面掌握Gecko内核究竟向javascript绑定导出了多少接口、属性及方法等，可具体参考文档\mozilla\dom\src\base\nsDOMClassInfo.cpp的nsDOMClassInfo::Init()方法中一大段关于nsIDOMClassInfo方面的初始化。如&lt;br /&gt;DOM_CLASSINFO_MAP_BEGIN(Window, nsIDOMWindow)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowInternal)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMViewCSS)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMAbstractView)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageWindow)&lt;br /&gt;DOM_CLASSINFO_MAP_END&lt;br /&gt;&lt;br /&gt;DOM_CLASSINFO_MAP_BEGIN(Location, nsIDOMLocation)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMLocation)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSLocation)&lt;br /&gt;DOM_CLASSINFO_MAP_END&lt;br /&gt;&lt;br /&gt;DOM_CLASSINFO_MAP_BEGIN(XMLHttpRequest, nsIXMLHttpRequest)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequest)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIJSXMLHttpRequest)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)&lt;br /&gt;  DOM_CLASSINFO_MAP_ENTRY(nsIInterfaceRequestor)&lt;br /&gt;DOM_CLASSINFO_MAP_END&lt;br /&gt;&lt;br /&gt;这样就对Firefox browser.js中的类似下面的代码就不觉得迷糊啦。&lt;br /&gt;const nsCI               = Components.interfaces;&lt;br /&gt;const nsIWebNavigation   = nsCI.nsIWebNavigation;&lt;br /&gt;window.XULBrowserWindow = new nsBrowserStatusHandler();&lt;br /&gt;window.QueryInterface(nsCI.nsIInterfaceRequestor)&lt;br /&gt;      .getInterface(nsIWebNavigation)&lt;br /&gt;      .QueryInterface(nsCI.nsIDocShellTreeItem).treeOwner&lt;br /&gt;      .QueryInterface(nsCI.nsIInterfaceRequestor)&lt;br /&gt;      .getInterface(nsCI.nsIXULWindow)&lt;br /&gt;      .XULBrowserWindow = window.XULBrowserWindow;&lt;br /&gt;window.QueryInterface(nsCI.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、总结&lt;/span&gt;&lt;br /&gt;经过上面的学习研究，觉得不管是javascript基本语法及应用方面，还是其具体实现方面，还有xpconnect实现方面等，都可单独写一本书来描述，其内容实在太多，并且比较复杂，以后可多花点心力来继续了解他们。但是为了更好的了解其实现过程，能充分发挥javascript优势，不妨多用用DOM Inspecter及javascript debuger venkman等工具。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、参考资源&lt;/span&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Scripting_language"&gt;Wiki Script language&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/JavaScript"&gt;WiKi Javascript&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide"&gt;Core Javascript1.5 Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/scriptable/"&gt;XPConnect(Scriptable Components)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/docs/dom/mozilla/hacking.html"&gt;The Mozilla DOM Hacking Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/JavaScript-DOM_Prototypes_in_Mozilla"&gt;JavaScript-DOM Prototypes in Mozilla&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/JSAPI_User_Guide"&gt;JSAPI User Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/SpiderMonkey_Internals"&gt;SpiderMonkey Internals&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/SpiderMonkey_Internals:_Thread_Safety"&gt;SpiderMonkey Thread Safety&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/SpiderMonkey_Garbage_Collection_Tips"&gt;SpiderMonkey Garbage Collection Tips&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/How_to_embed_the_JavaScript_engine"&gt;How to embed the javascript engine&lt;/a&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/Tamarin"&gt;Tamarin&lt;/a&gt;&lt;/nsiclassinfo&gt;&lt;/nsixpcscriptable&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-6863822990502776924?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/6863822990502776924/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=6863822990502776924' title='2 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6863822990502776924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/6863822990502776924'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/geckojavascript.html' title='浅谈Gecko关键部分之六认识javascript实现及应用'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-581448335213339614</id><published>2008-07-07T20:02:00.000+08:00</published><updated>2008-08-02T16:50:46.374+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='W3C标准'/><category scheme='http://www.blogger.com/atom/ns#' term='SVG'/><category scheme='http://www.blogger.com/atom/ns#' term='XHTML'/><category scheme='http://www.blogger.com/atom/ns#' term='DOM'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='CSS'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之五认识HTML、DOM、CSS、XML、XHTML、SVG等标准</title><content type='html'>在了解Gecko内核是如何响应用户输入的Web地址，如何渲染、显示包含文字、图片、动画甚至视频的画面给用户的整个过程之后，假如我们深思一下，Gecko内核为什么要这样解析、渲染这个Web地址对应的内容？为什么不那样解析？它在解析、渲染的时候会受到约束吗？它可以自由发挥吗？答案是肯定，它所受的约束也就是我们熟知的W3C标准，它是尽可能按照标准来办事的，当然标准当中也肯定有未尽之事，所以它也有一定的自由发挥空间。正是有了如此众多的W3C标准，让我们的互联网应用是如此的丰富多彩，IE、Safari、Opera等浏览器都基本按照标准办事，所以我们编写的符合标准的Web页面可以在如此多的浏览器上被解析、渲染显示出来，并且效果基本一致。标准也就是协议，所以我们要想深入的了解Gecko内核，必须深入的了解它所支持的标准。下面初略的介绍一下HTML、DOM、CSS、XML、XHTML、SVG等标准。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、HTML&lt;/span&gt;&lt;br /&gt;&lt;b&gt;HTML&lt;/b&gt;, an &lt;a linkindex="15" href="http://en.wikipedia.org/wiki/Acronym_and_initialism" title="Acronym and initialism"&gt;initialism&lt;/a&gt; of &lt;b&gt;HyperText Markup Language&lt;/b&gt;, is the predominant &lt;a linkindex="16" href="http://en.wikipedia.org/wiki/Markup_language" title="Markup language"&gt;markup language&lt;/a&gt; for &lt;a set="yes" linkindex="17" href="http://en.wikipedia.org/wiki/Web_page" title="Web page"&gt;web pages&lt;/a&gt;. It provides a means to describe the structure of text-based information in a document — by denoting certain text as links, headings, paragraphs, lists, and so on — and to supplement that text with &lt;i&gt;interactive forms&lt;/i&gt;, embedded &lt;i&gt;images&lt;/i&gt;, and other objects. HTML is written in the form of tags, surrounded by &lt;a linkindex="18" href="http://en.wikipedia.org/wiki/Brackets#Angle_brackets_or_chevrons_.3C_.3E" class="mw-redirect" title="Brackets"&gt;angle brackets&lt;/a&gt;. HTML can also describe, to some degree, the appearance and &lt;a linkindex="19" href="http://en.wikipedia.org/wiki/Semantics" title="Semantics"&gt;semantics&lt;/a&gt; of a document, and can include embedded &lt;a set="yes" linkindex="20" href="http://en.wikipedia.org/wiki/Scripting_language" title="Scripting language"&gt;scripting language&lt;/a&gt; code (such as JavaScript) which can affect the behavior of &lt;a set="yes" linkindex="21" href="http://en.wikipedia.org/wiki/Web_browser" title="Web browser"&gt;Web browsers&lt;/a&gt; and other HTML processors.&lt;br /&gt;&lt;br /&gt;具体可参考&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/HTML#Version_history_of_the_standard"&gt;HTML Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/html401/"&gt;HTML 4.01 Specification&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/html5/"&gt;HTML 5 Specification&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、&lt;/span&gt;&lt;/span&gt;DOM&lt;/span&gt;&lt;br /&gt;The &lt;b&gt;Document Object Model&lt;/b&gt; (&lt;b&gt;DOM&lt;/b&gt;) is a platform- and &lt;a linkindex="5" href="http://en.wikipedia.org/wiki/Programming_language" title="Programming language"&gt;language&lt;/a&gt;-independent standard &lt;a linkindex="6" href="http://en.wikipedia.org/wiki/Object_model" title="Object model"&gt;object model&lt;/a&gt; for representing &lt;a linkindex="7" href="http://en.wikipedia.org/wiki/HTML" title="HTML"&gt;HTML&lt;/a&gt; or &lt;a linkindex="8" href="http://en.wikipedia.org/wiki/XML" title="XML"&gt;XML&lt;/a&gt; and related formats. &lt;p&gt;A &lt;a set="yes" linkindex="9" href="http://en.wikipedia.org/wiki/Web_browser" title="Web browser"&gt;web browser&lt;/a&gt; is not obliged to use DOM in order to render an HTML document. However, the DOM is required by &lt;a linkindex="10" href="http://en.wikipedia.org/wiki/JavaScript" title="JavaScript"&gt;JavaScript&lt;/a&gt; scripts that wish to inspect or modify a web page dynamically. In other words, the Document Object Model is the way JavaScript sees its containing HTML page and browser state.&lt;/p&gt;&lt;p&gt;具体可参考&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Document_Object_Model"&gt;DOM Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/DOM-Level-2-HTML/"&gt;DOM2 Html Specification&lt;/a&gt;&lt;a href="http://www.w3.org/TR/DOM-Level-2-HTML/"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;span style="font-weight: bold;"&gt;三、CSS&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Cascading Style Sheets&lt;/b&gt; (&lt;b&gt;CSS&lt;/b&gt;) is a &lt;a set="yes" linkindex="45" href="http://en.wikipedia.org/wiki/Stylesheet_language" class="mw-redirect" title="Stylesheet language"&gt;stylesheet language&lt;/a&gt; used to describe the presentation of a document written in a &lt;a set="yes" linkindex="46" href="http://en.wikipedia.org/wiki/Markup_language" title="Markup language"&gt;markup language&lt;/a&gt;. Its most common application is to style &lt;a linkindex="47" href="http://en.wikipedia.org/wiki/Web_page" title="Web page"&gt;web pages&lt;/a&gt; written in &lt;a style="color: orange;" set="yes" linkindex="48" href="http://en.wikipedia.org/wiki/HTML" title="HTML"&gt;HTML&lt;/a&gt; and &lt;a set="yes" linkindex="49" href="http://en.wikipedia.org/wiki/XHTML" title="XHTML"&gt;XHTML&lt;/a&gt;, but the language can be applied to any kind of &lt;a linkindex="50" href="http://en.wikipedia.org/wiki/XML" title="XML"&gt;XML&lt;/a&gt; document, including &lt;a linkindex="51" href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics" title="Scalable Vector Graphics"&gt;SVG&lt;/a&gt; and &lt;a set="yes" linkindex="52" href="http://en.wikipedia.org/wiki/XUL" title="XUL"&gt;XUL&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;具体可参考&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets"&gt;CSS Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/CSS21/"&gt;CSS Specification&lt;/a&gt;&lt;a href="http://www.w3.org/TR/CSS21/"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;a href="http://www.w3.org/TR/CSS21/"&gt;&lt;/a&gt;&lt;a href="http://www.w3.org/TR/CSS21/"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、XML&lt;/span&gt;&lt;br /&gt;The &lt;b&gt;Extensible Markup Language&lt;/b&gt; (&lt;b&gt;XML&lt;/b&gt;) is a general-purpose &lt;i&gt;specification&lt;/i&gt; for creating custom &lt;a linkindex="16" href="http://en.wikipedia.org/wiki/Markup_language" title="Markup language"&gt;markup languages&lt;/a&gt;.&lt;sup id="cite_ref-0" class="reference"&gt;&lt;a linkindex="17" href="http://en.wikipedia.org/wiki/XML#cite_note-0" title=""&gt;[1]&lt;/a&gt;&lt;/sup&gt; It is classified as an &lt;a set="yes" linkindex="18" href="http://en.wikipedia.org/wiki/Extensible_language" title="Extensible language"&gt;extensible language&lt;/a&gt; because it allows its users to define their own elements. Its primary purpose is to facilitate the sharing of structured data across different information systems, particularly via the &lt;a set="yes" linkindex="19" href="http://en.wikipedia.org/wiki/Internet" title="Internet"&gt;Internet&lt;/a&gt;,&lt;sup id="cite_ref-XmlOriginsGoals_1-0" class="reference"&gt;&lt;a set="yes" linkindex="20" href="http://en.wikipedia.org/wiki/XML#cite_note-XmlOriginsGoals-1" title=""&gt;[2]&lt;/a&gt;&lt;/sup&gt; and it is used both to encode documents and to &lt;a linkindex="21" href="http://en.wikipedia.org/wiki/Serialization" title="Serialization"&gt;serialize&lt;/a&gt; data. In the latter context, it is comparable with other text-based serialization languages such as &lt;a linkindex="22" href="http://en.wikipedia.org/wiki/JSON" title="JSON"&gt;JSON&lt;/a&gt; and &lt;a linkindex="23" href="http://en.wikipedia.org/wiki/YAML" title="YAML"&gt;YAML&lt;/a&gt;.&lt;sup id="cite_ref-2" class="reference"&gt;&lt;a linkindex="24" href="http://en.wikipedia.org/wiki/XML#cite_note-2" title=""&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;&lt;br /&gt;具体可参考&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/XML"&gt;XML Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/xml11/"&gt;XML Specification&lt;/a&gt;&lt;a href="http://www.w3.org/TR/xml11/"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、XHTML&lt;/span&gt;&lt;br /&gt;The &lt;i&gt;&lt;b&gt;Extensible &lt;a set="yes" linkindex="38" href="http://en.wikipedia.org/wiki/Hypertext" title="Hypertext"&gt;Hypertext&lt;/a&gt; Markup Language&lt;/b&gt;&lt;/i&gt;, or &lt;b&gt;XHTML&lt;/b&gt;, is a &lt;a linkindex="39" href="http://en.wikipedia.org/wiki/Markup_language" title="Markup language"&gt;markup language&lt;/a&gt; that has the same depth of expression as &lt;a linkindex="40" href="http://en.wikipedia.org/wiki/HTML" title="HTML"&gt;HTML&lt;/a&gt;, but also conforms to &lt;a set="yes" linkindex="41" href="http://en.wikipedia.org/wiki/XML" title="XML"&gt;XML&lt;/a&gt; syntax.&lt;br /&gt;&lt;br /&gt;具体可参考&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/XHTML"&gt;XHTML Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/xhtml1/"&gt;XHTML Specification&lt;/a&gt;&lt;a href="http://www.w3.org/TR/xhtml1/"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、SVG&lt;/span&gt;&lt;br /&gt;&lt;b&gt;Scalable Vector Graphics&lt;/b&gt; (&lt;b&gt;SVG&lt;/b&gt;) is an &lt;a linkindex="27" href="http://en.wikipedia.org/wiki/XML" title="XML"&gt;XML&lt;/a&gt; specification and &lt;a linkindex="28" href="http://en.wikipedia.org/wiki/File_format" title="File format"&gt;file format&lt;/a&gt; for describing two-dimensional &lt;a set="yes" linkindex="29" href="http://en.wikipedia.org/wiki/Vector_graphics" title="Vector graphics"&gt;vector graphics&lt;/a&gt;, both static and &lt;a set="yes" linkindex="30" href="http://en.wikipedia.org/wiki/Animated" class="mw-redirect" title="Animated"&gt;animated&lt;/a&gt;. SVG can be purely &lt;a linkindex="31" href="http://en.wikipedia.org/wiki/Declarative_programming" title="Declarative programming"&gt;declarative&lt;/a&gt; or may include &lt;a linkindex="32" href="http://en.wikipedia.org/wiki/Scripting" class="mw-redirect" title="Scripting"&gt;scripting&lt;/a&gt;. Images can contain &lt;a linkindex="33" href="http://en.wikipedia.org/wiki/Hyperlink" title="Hyperlink"&gt;hyperlinks&lt;/a&gt; using outbound simple &lt;a set="yes" linkindex="34" href="http://en.wikipedia.org/wiki/XLink" title="XLink"&gt;XLinks&lt;/a&gt;.&lt;sup id="cite_ref-1" class="reference"&gt;&lt;a linkindex="35" href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics#cite_note-1" title=""&gt;[2]&lt;/a&gt;&lt;/sup&gt; It is an &lt;a linkindex="36" href="http://en.wikipedia.org/wiki/Open_standard" title="Open standard"&gt;open standard&lt;/a&gt; created by the &lt;a linkindex="37" href="http://en.wikipedia.org/wiki/World_Wide_Web_Consortium" title="World Wide Web Consortium"&gt;W3C&lt;/a&gt;'s &lt;a set="yes" linkindex="38" href="http://en.wikipedia.org/wiki/SVG_Working_Group" title="SVG Working Group"&gt;SVG Working Group&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;具体可参考&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics"&gt;SVG Wiki&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/2006/CR-SVGMobile12-20060810/"&gt;SVG Tiny1.2 Specification&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;七、总结&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;面对如此众多的W3C标准，特别是W3C上发布的标准文档，我们往往会看得云里雾里，毕竟这些标准文档是所谓的专家学者所写，够严谨全面的。为了便于日常运用，我们只要把握两条即可1、懂得其基本用途及主要要素； 2、必要时刻需仔细研读之，定会收获众多，她们就像我们的良师益友，平时没事的时候可常习之。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.w3.org/TR/html5/"&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-581448335213339614?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/581448335213339614/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=581448335213339614' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/581448335213339614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/581448335213339614'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/geckohtmldomcssxmlxhtmlsvg.html' title='浅谈Gecko关键部分之五认识HTML、DOM、CSS、XML、XHTML、SVG等标准'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-7237680845033387534</id><published>2008-07-05T10:32:00.000+08:00</published><updated>2008-08-02T16:53:58.627+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Render'/><category scheme='http://www.blogger.com/atom/ns#' term='Parser'/><category scheme='http://www.blogger.com/atom/ns#' term='Http'/><category scheme='http://www.blogger.com/atom/ns#' term='Frame'/><category scheme='http://www.blogger.com/atom/ns#' term='View'/><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之四The life of an html http Request</title><content type='html'>从用户的角度来看，一个浏览器其实是相当简单的，用户输入一个Web地址，然后按回车，等不了多久，一个具有丰富内容的画面就会出现在用户面前，其中包含五彩缤纷的排列整齐的文字、图片、动画甚至视频，用户通过点击自己感兴趣的地方，新的内容画面就会呈现在用户面前，这样用户就可以只需简单的点击一下鼠标就可以在互联网上自由遨游啦。现在回想起来，也许正是浏览器当初在设计的时候充分考虑到用户的易用性才导致互联网的蓬勃发展，正像谷歌提供搜索一样简单易用并且非常实用，这样说来，互联网的发展离不开浏览器，是她带领人们走向了互联网，回顾历史让我们感慨万千，那么浏览器主要做了些啥？她为什么能支持如此丰富的内容？她的发展方向在哪里？为了解答心中的疑问，首先让我们初步了解Gecko内核是如何完成从用户输入Web地址，直到内容丰富的画面显示出来的整个过程，这个过程涉及的面比较广，目前我们主要关心关键过程、关键点及相关的关键类的实现，争取能有个整体的而又完整的印象。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;一、&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;创建nsWebShellWindow实例，准备处理输入的WebURI地址；&lt;/span&gt;&lt;br /&gt;因为接收用户打开一个新URI的情况比较多，如通过脚本中的window.open或直接在地址栏中输入或者在新开的一个窗口打开或者在新建的一个页签打开等等，通过对这一系列的打开一个页面的外围场景进行处理后，内核都会新建一个或利用原有的nsWebShellWindow实例来处理整个打开URI的过程。其包含的主要成员有nsComPtr&lt;nsiwidget&gt; mWindow，代表一个原生窗口，将要打开的页面可在其中显示内容如文字、图片等；nsComPtr&lt;nsidocshell&gt; mDocShell，代表一个协调者，它管理整个打开URI的过程，其实现类nsDocShell也就成为整个Gecko内核的核心部分，它不仅接收处理打开URI请求，同时提供接口以反馈相关信息给外部如提示正在打开某某地址等。在nsWebShellWindow的Initialize()方法中通过mWindow = do_CreateInstance(kWindowCID, &amp;amp;rv);来创建mWindow，通过mDocShell = do_CreateInstance("@mozilla.org/webshell;1");来创建设置mDocShell为打开URI做好前期准备。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;二、&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;准备装载指定URI的内容；&lt;/span&gt;&lt;br /&gt;首先由协调者nsDocShell的LoadURI方法来发起装载的请求，经过一番安全或请求Policy等方面的设定后创建nsCOMPtr&lt;nsiuriloader&gt; uriLoader=do_GetService(NS_URI_LOADER_CONTRACTID, &amp;amp;rv);&lt;br /&gt;nsCOMPtr&lt;nsichannel&gt; channel;&lt;br /&gt;rv = NS_NewChannel(getter_AddRefs(channel),&lt;br /&gt;                   aURI,  nsnull,  nsnull, static_cast&lt;nsiinterfacerequestor&gt;(this), loadFlags);&lt;br /&gt;由uriLoader-&gt;OpenURI(aChannel, (mLoadType == LOAD_LINK), this);来统一继续处理所有的URI请求，其中会创建一个临时的nsCOMPtr&lt;nsdocumentopeninfo&gt; loader =new nsDocumentOpenInfo(aWindowContext, aFlags, this);同时将loader作为一个nsIStreamListener来接收请求而来的数据，以分析请求而来的文档类型如text/html、xml等以决定后续不同的处理，然后由rv = channel-&gt;AsyncOpen(loader, nsnull);来真正向Web服务发出请求，并通过异步的方式来处理接收数据，这里往往会涉及到以前提到的线程处理等，总之至此基本的准备动作应该都已准备好，就等待Web服务端返回数据啦。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;三、&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;根据接收的数据类型创建Document及相关ContentViewer;&lt;/span&gt;&lt;br /&gt;根据异步数据的获取，获取数据的线程向MainThread发出nsInputStreamReadyEvent事件，由主线程来处理相关事件，其往往会调用到nsInputStreamPump中去，其关键调用如下：&lt;br /&gt;nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)&lt;br /&gt;{&lt;br /&gt;LOG(("nsInputStreamPump::OnInputStreamReady [this=%x]\n", this));&lt;br /&gt;&lt;br /&gt;// this function has been called from a PLEvent, so we can safely call&lt;br /&gt;// any listener or progress sink methods directly from here.&lt;br /&gt;&lt;br /&gt;for (;;) {&lt;br /&gt;    if (mSuspendCount || mState == STATE_IDLE) {&lt;br /&gt;        mWaiting = PR_FALSE;&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    PRUint32 nextState;&lt;br /&gt;    switch (mState) {&lt;br /&gt;    case STATE_START:&lt;br /&gt;        nextState = OnStateStart();&lt;br /&gt;        break;&lt;br /&gt;    case STATE_TRANSFER:&lt;br /&gt;        nextState = OnStateTransfer();&lt;br /&gt;        break;&lt;br /&gt;    case STATE_STOP:&lt;br /&gt;        nextState = OnStateStop();&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;    ...........&lt;br /&gt;&lt;br /&gt;    mState = nextState;&lt;br /&gt;}&lt;br /&gt;return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;当STATE_START时，表示已获取部分&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;初始&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;数据，其中OnStateStart()会调用作为Channel的streamListener的OnStartRequest方法，此时streamListener为uriLoader临时创建的nsDocumentOpenInfo实例loader，由它来处理，其方法OnStartRequest进而由nsDocumentOpenInfo的DispatchContent方法来尝试决定能否处理该文档类型，一旦决定可以处理该类型，进而由nsDSURIContentListener的DoContent来调用nsDocShell的方法CreateContentViewer来创建Document及Viewer，其中主要进行代码包括：&lt;br /&gt;{&lt;br /&gt;..........................................&lt;br /&gt;// Instantiate the content viewer object&lt;br /&gt;nsCOMPtr&lt;nsicontentviewer&gt; viewer;&lt;br /&gt;nsresult rv = NewContentViewerObj(aContentType, request, mLoadGroup,&lt;br /&gt;                                  aContentHandler, getter_AddRefs(viewer));&lt;br /&gt;&lt;br /&gt;NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull),&lt;br /&gt;                  NS_ERROR_FAILURE);&lt;br /&gt;............................................&lt;br /&gt;}&lt;br /&gt;nsresult&lt;br /&gt;nsDocShell::NewContentViewerObj(const char *aContentType,&lt;br /&gt;                            nsIRequest * request, nsILoadGroup * aLoadGroup,&lt;br /&gt;                            nsIStreamListener ** aContentHandler,&lt;br /&gt;                            nsIContentViewer ** aViewer)&lt;br /&gt;{&lt;br /&gt;nsCOMPtr&lt;nsichannel&gt; aOpenedChannel = do_QueryInterface(request);&lt;br /&gt;&lt;br /&gt;nsresult rv;&lt;br /&gt;nsCOMPtr&lt;nsicategorymanager&gt; catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &amp;amp;rv));&lt;br /&gt;if (NS_FAILED(rv))&lt;br /&gt;  return rv;&lt;br /&gt;&lt;br /&gt;nsXPIDLCString contractId;&lt;br /&gt;rv = catMan-&gt;GetCategoryEntry("Gecko-Content-Viewers", aContentType, getter_Copies(contractId));&lt;br /&gt;&lt;br /&gt;// Create an instance of the document-loader-factory&lt;br /&gt;nsCOMPtr&lt;nsidocumentloaderfactory&gt; docLoaderFactory;&lt;br /&gt;if (NS_SUCCEEDED(rv))&lt;br /&gt;    docLoaderFactory = do_GetService(contractId.get());&lt;br /&gt;&lt;br /&gt;if (!docLoaderFactory) {&lt;br /&gt;    return NS_ERROR_FAILURE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Now create an instance of the content viewer&lt;br /&gt;// nsLayoutDLF makes the determination if it should be a "view-source" instead of "view"&lt;br /&gt;NS_ENSURE_SUCCESS(docLoaderFactory-&gt;CreateInstance("view",&lt;br /&gt;                                                   aOpenedChannel,&lt;br /&gt;                                                   aLoadGroup, aContentType,&lt;br /&gt;                                                   static_cast&lt;nsicontentviewercontainer*&gt;(this),&lt;br /&gt;                                                   nsnull,&lt;br /&gt;                                                   aContentHandler,&lt;br /&gt;                                                   aViewer),&lt;br /&gt;                  NS_ERROR_FAILURE);&lt;br /&gt;&lt;br /&gt;(*aViewer)-&gt;SetContainer(static_cast&lt;nsicontentviewercontainer&gt;(this));&lt;br /&gt;return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;这里主要会根据contentType的不同创建不同的Document对象，它由nsContentDLF::CreateInstance来实现。其主要代码如下&lt;br /&gt;&lt;br /&gt;nsCOMPtr&lt;nsidocument&gt; doc;&lt;br /&gt;nsCOMPtr&lt;nsidocumentviewer&gt; docv;&lt;br /&gt;do {&lt;br /&gt;// Create the document&lt;br /&gt;doc = do_CreateInstance(aDocumentCID, &amp;amp;rv);//针对htmldocumnt、xuldocument、imagedocument的不同会对应不同的DocumnetCID&lt;br /&gt;if (NS_FAILED(rv))&lt;br /&gt;  break;&lt;br /&gt;&lt;br /&gt;// Create the document viewer  XXX: could reuse document viewer here!&lt;br /&gt;rv = NS_NewDocumentViewer(getter_AddRefs(docv));&lt;br /&gt;if (NS_FAILED(rv))&lt;br /&gt;  break;&lt;br /&gt;docv-&gt;SetUAStyleSheet(gUAStyleSheet);&lt;br /&gt;&lt;br /&gt;doc-&gt;SetContainer(aContainer);&lt;br /&gt;&lt;br /&gt;// Initialize the document to begin loading the data.  An&lt;br /&gt;// nsIStreamListener connected to the parser is returned in&lt;br /&gt;// aDocListener.&lt;br /&gt;rv = doc-&gt;StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, PR_TRUE);&lt;br /&gt;if (NS_FAILED(rv))&lt;br /&gt;  break;&lt;br /&gt;&lt;br /&gt;// Bind the document to the Content Viewer&lt;br /&gt;rv = docv-&gt;LoadStart(doc);&lt;br /&gt;*aDocViewer = docv;&lt;br /&gt;NS_IF_ADDREF(*aDocViewer);&lt;br /&gt;} while (PR_FALSE);&lt;br /&gt;&lt;br /&gt;其中需要注意的是在StartDocumentLoad的时候会创建一个mParser = do_CreateInstance(kCParserCID, &amp;amp;rv);作为DocListener，以供后面解析文档内容用；同时会创建nsCOMPtr&lt;nsicontentsink&gt; sink，以供后面组织文档内容用；创建ContentSink的主要代码逻辑如下：&lt;br /&gt;// create the content sink&lt;br /&gt;nsCOMPtr&lt;nsicontentsink&gt; sink;&lt;br /&gt;&lt;br /&gt;if (aSink)&lt;br /&gt;  sink = aSink;&lt;br /&gt;else {&lt;br /&gt;  if (IsXHTML()) {&lt;br /&gt;    nsCOMPtr&lt;nsixmlcontentsink&gt; xmlsink;&lt;br /&gt;    rv = NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri,&lt;br /&gt;                              docShell, aChannel);&lt;br /&gt;&lt;br /&gt;    sink = xmlsink;&lt;br /&gt;  } else {&lt;br /&gt;    nsCOMPtr&lt;nsihtmlcontentsink&gt; htmlsink;&lt;br /&gt;&lt;br /&gt;    rv = NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri,&lt;br /&gt;                               docShell, aChannel);&lt;br /&gt;&lt;br /&gt;    sink = htmlsink;&lt;br /&gt;  }&lt;br /&gt;  NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;  NS_ASSERTION(sink,&lt;br /&gt;               "null sink with successful result from factory method");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mParser-&gt;SetContentSink(sink);&lt;br /&gt;// parser the content of the URI&lt;br /&gt;mParser-&gt;Parse(uri, nsnull, (void *)this);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;一旦初步组织好nsDocShell、Document、Viewer、Parser、ContentSink之间的关系后，在nsDocumentOpenInfo调用DispatchContent时将返回的DocListener也即nsParser实例赋值给nsDocumentOpenInfo的m_targetStreamListener，以供后续使用，同时告诉Parser、ContentSink作好解析、组织文档准备；&lt;br /&gt;&lt;br /&gt;另外通过nsDocShell的Embed方法，初始化DocumentViewer，其主要实现如下：&lt;br /&gt;nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)&lt;br /&gt;{&lt;br /&gt;..........................&lt;br /&gt;mContentViewer = aNewViewer;&lt;br /&gt;nsCOMPtr&lt;nsiwidget&gt; widget;&lt;br /&gt;NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);&lt;br /&gt;&lt;br /&gt;nsCOMPtr&lt;nsidevicecontext&gt; deviceContext;&lt;br /&gt;if (widget) {&lt;br /&gt;    deviceContext = do_CreateInstance(kDeviceContextCID);&lt;br /&gt;    NS_ENSURE_TRUE(deviceContext, NS_ERROR_FAILURE);&lt;br /&gt;    deviceContext-&gt;Init(widget-&gt;GetNativeData(NS_NATIVE_WIDGET));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;nsRect bounds(x, y, cx, cy);&lt;br /&gt;&lt;br /&gt;mContentViewer-&gt;Init(widget, deviceContext, bounds);&lt;br /&gt;..........................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,&lt;br /&gt;                             nsISupports *aState,&lt;br /&gt;                             nsIDeviceContext* aDeviceContext,&lt;br /&gt;                             const nsRect&amp;amp; aBounds,&lt;br /&gt;                             PRBool aDoCreation,&lt;br /&gt;                             PRBool aInPrintPreview,&lt;br /&gt;                             PRBool aNeedMakeCX /*= PR_TRUE*/)&lt;br /&gt;{&lt;br /&gt;.......................................&lt;br /&gt;if (aParentWidget &amp;amp;&amp;amp; !mPresContext) {&lt;br /&gt;  // Create presentation context&lt;br /&gt;  if (mIsPageMode) {&lt;br /&gt;    //Presentation context already created in SetPageMode which is calling this method&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;    mPresContext =&lt;br /&gt;        new nsPresContext(mDocument, nsPresContext::eContext_Galley);&lt;br /&gt;  NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY);&lt;br /&gt;&lt;br /&gt;  nsresult rv = mPresContext-&gt;Init(aDeviceContext);&lt;br /&gt;  if (NS_FAILED(rv)) {&lt;br /&gt;    mPresContext = nsnull;&lt;br /&gt;    return rv;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;if (aDoCreation &amp;amp;&amp;amp; mPresContext) {&lt;br /&gt;// The ViewManager and Root View was created above (in&lt;br /&gt;// MakeWindow())...&lt;br /&gt;&lt;br /&gt;rv = InitPresentationStuff(!makeCX, !makeCX);&lt;br /&gt;}&lt;br /&gt;................................................&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReenableRefresh)&lt;br /&gt;{&lt;br /&gt;..............................................&lt;br /&gt;&lt;br /&gt;// Create the style set...&lt;br /&gt;nsStyleSet *styleSet;&lt;br /&gt;nsresult rv = CreateStyleSet(mDocument, &amp;amp;styleSet);&lt;br /&gt;NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;// Now make the shell for the document&lt;br /&gt;rv = mDocument-&gt;CreateShell(mPresContext, mViewManager, styleSet,&lt;br /&gt;                          getter_AddRefs(mPresShell));&lt;br /&gt;&lt;br /&gt;mPresShell-&gt;BeginObservingDocument();//mDocument-&gt;AddObserver(mPresShell);&lt;br /&gt;..............................................&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;nsDocument::doCreateShell(nsPresContext* aContext,&lt;br /&gt;                      nsIViewManager* aViewManager, nsStyleSet* aStyleSet,&lt;br /&gt;                      nsCompatibility aCompatMode,&lt;br /&gt;                      nsIPresShell** aInstancePtrResult)&lt;br /&gt;{&lt;br /&gt;*aInstancePtrResult = nsnull;&lt;br /&gt;&lt;br /&gt;NS_ENSURE_FALSE(mShellsAreHidden, NS_ERROR_FAILURE);&lt;br /&gt;&lt;br /&gt;FillStyleSet(aStyleSet);&lt;br /&gt;&lt;br /&gt;nsCOMPtr&lt;nsipresshell&gt; shell;&lt;br /&gt;nsresult rv = NS_NewPresShell(getter_AddRefs(shell));&lt;br /&gt;if (NS_FAILED(rv)) {&lt;br /&gt;return rv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;rv = shell-&gt;Init(this, aContext, aViewManager, aStyleSet, aCompatMode);&lt;br /&gt;NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;// Note: we don't hold a ref to the shell (it holds a ref to us)&lt;br /&gt;NS_ENSURE_TRUE(mPresShells.AppendElementUnlessExists(shell),&lt;br /&gt;             NS_ERROR_OUT_OF_MEMORY);&lt;br /&gt;shell.swap(*aInstancePtrResult);&lt;br /&gt;&lt;br /&gt;return NS_OK;&lt;br /&gt;}&lt;br /&gt;这样同时准备好与显示相关的nsDeviceContext、nsPresContext、nsPresShell，其中需要留意的是nsPresShell对象是作为nsDocument&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;实例&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;对象的一个Observer，同时也是nsView&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;Manager&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;实例对象的一个Observer；至此初始化完nsPresShell，并加入到nsViewManager的管理机制中去，&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;为后面创建新的nsView对象及进行布局安排、显示内容作好准备。&lt;br /&gt;&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;四、解析、组织文档内容，同时作好布局&lt;/span&gt;&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;&lt;span style="font-weight: bold;"&gt;准备&lt;/span&gt;&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;&lt;br /&gt;继续查看nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)方法中的STATE_TRANSFER时，表示已获取相关文档数据，此时会继续利用uriLoader临时创建的nsDocumentOpenInfo，由它的方法OnDataAvailable来继续处理获得的数据，其实现如下：&lt;br /&gt;&lt;br /&gt;NS_IMETHODIMP nsDocumentOpenInfo::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt, nsIInputStream * inStr, PRUint32 sourceOffset, PRUint32 count)&lt;br /&gt;{&lt;br /&gt;// if we have retarged to the end stream listener, then forward the call....&lt;br /&gt;// otherwise, don't do anything&lt;br /&gt;nsresult rv = NS_OK;&lt;br /&gt;if (m_targetStreamListener)&lt;br /&gt;rv = m_targetStreamListener-&gt;OnDataAvailable(request, aCtxt, inStr, sourceOffset, count);&lt;br /&gt;return rv;&lt;br /&gt;}&lt;br /&gt;此时其&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;m_targetStreamListener值也即上面创建出来的nsParser实例，&lt;br /&gt;&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;这样正好一环套一环，任务转交给了上面准备好的nsParser；&lt;br /&gt;Gecko内核中的Parser有HtmlParser以解析html文档；xmlParser以解析符合xml格式的文档如xul、svg；CssParser以解析Css文档等。解析器通过Tokenizer来认识文档中的标识，然后结合不同文档类型预定义的Atom及ContentSink来组织想要的文档结构。整个HtmlParser的解析过程还是蛮复杂的，不过无论解析的过程怎样，其结果就是会适时的调用ContentSink中的主要方法，如OpenHead、OpenBody、CloseBody、OpenForm、CloseForm、OpenContainer、CloseContainer、StartLayout、ProcessLINKTag、ProcessSCRIPTEndTag、ProcessSTYLEEndTag等；&lt;br /&gt;&lt;br /&gt;其中需要留意的是在构建文档结构的同时往往需要对不同的Content Node 创建对应Frame对象，同时针对不同的Frame，还时可能还需要构建nsView，如nsBoxFrame，在一些条件下需要调用方法CreateViewForFrame来创建一个nsView实例，其主要代码如下：&lt;br /&gt;{&lt;br /&gt;   // Create a view&lt;br /&gt;   nsIView *view = viewManager-&gt;CreateView(aFrame-&gt;GetRect(), parentView, visibility);&lt;br /&gt;   if (view) {&lt;br /&gt;     // Insert the view into the view hierarchy. If the parent view is a&lt;br /&gt;     // scrolling view we need to do this differently&lt;br /&gt;     nsIScrollableView*  scrollingView = parentView-&gt;ToScrollableView();&lt;br /&gt;     if (scrollingView) {&lt;br /&gt;       scrollingView-&gt;SetScrolledView(view);&lt;br /&gt;     } else {&lt;br /&gt;       viewManager-&gt;SetViewZIndex(view, autoZIndex, zIndex);&lt;br /&gt;       // XXX put view last in document order until we can do better&lt;br /&gt;       viewManager-&gt;InsertChild(parentView, view, nsnull, PR_TRUE);&lt;br /&gt;     }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // Remember our view&lt;br /&gt;   aFrame-&gt;SetView(view);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;NS_IMETHODIMP_(nsIView *)&lt;br /&gt;nsViewManager::CreateView(const nsRect&amp;amp; aBounds,&lt;br /&gt;                       const nsIView* aParent,&lt;br /&gt;                       nsViewVisibility aVisibilityFlag)&lt;br /&gt;{&lt;br /&gt;nsView *v = new nsView(this, aVisibilityFlag);&lt;br /&gt;if (v) {&lt;br /&gt; v-&gt;SetPosition(aBounds.x, aBounds.y);&lt;br /&gt; nsRect dim(0, 0, aBounds.width, aBounds.height);&lt;br /&gt; v-&gt;SetDimensions(dim, PR_FALSE);&lt;br /&gt; v-&gt;SetParent(static_cast&lt;nsview*&gt;(const_cast&lt;nsiview*&gt;(aParent)));&lt;br /&gt;}&lt;br /&gt;return v;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;同时对于一些nsView还需要通过其nsIView::CreateWidget方法来创建原生的窗口，主要代码如下&lt;br /&gt;&lt;br /&gt;nsresult nsIView::CreateWidget(const nsIID &amp;amp;aWindowIID,&lt;br /&gt;                            nsWidgetInitData *aWidgetInitData,&lt;br /&gt;                            nsNativeWidget aNative,&lt;br /&gt;                            PRBool aEnableDragDrop,&lt;br /&gt;                            PRBool aResetVisibility,&lt;br /&gt;                            nsContentType aContentType,&lt;br /&gt;                            nsIWidget* aParentWidget)&lt;br /&gt;{&lt;br /&gt;nsView* v = static_cast&lt;nsview*&gt;(this);&lt;br /&gt;&lt;br /&gt;v-&gt;LoadWidget(aWindowIID))&lt;br /&gt;..................................&lt;br /&gt;mWindow-&gt;Create(aNative, trect, ::HandleEvent, dx, nsnull, nsnull, aWidgetInitData);&lt;br /&gt; ..............................&lt;br /&gt;}&lt;br /&gt;在mWindow-&gt;Create中会接着调用如nsWindow::StandardWindowCreate、BaseCreate等；&lt;br /&gt;其中&lt;/nsview*&gt;&lt;/nsiview*&gt;&lt;/nsview*&gt;&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;参数::HandleEvent会在创建原生窗口时保存在nsWindow的属性成员&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;mEventCallback中;这个函数句柄在原生窗口的处理函数中经过一定处理后往往根据一定上下文而去调用它，它会处理如WM_SIZE、WM_PAINT等主要消息，后面的处理会引用到。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;五、显示文档内容&lt;/span&gt;&lt;br /&gt;在上面解析、组织文档结构时，当调用OpenBody时会适时调用StartLayout，其主要代码如下&lt;br /&gt;{&lt;br /&gt;nsPresShellIterator iter(mDocument);&lt;br /&gt;nsCOMPtr&lt;nsipresshell&gt; shell;&lt;br /&gt;while ((shell = iter.GetNextShell())) {&lt;br /&gt;// Make sure we don't call InitialReflow() for a shell that has&lt;br /&gt;// already called it. This can happen when the layout frame for&lt;br /&gt;// an iframe is constructed *between* the Embed() call for the&lt;br /&gt;// docshell in the iframe, and the content sink's call to OpenBody().&lt;br /&gt;// (Bug 153815)&lt;br /&gt;&lt;br /&gt;PRBool didInitialReflow = PR_FALSE;&lt;br /&gt;shell-&gt;GetDidInitialReflow(&amp;amp;didInitialReflow);&lt;br /&gt;if (didInitialReflow) {&lt;br /&gt;  // XXX: The assumption here is that if something already&lt;br /&gt;  // called InitialReflow() on this shell, it also did some of&lt;br /&gt;  // the setup below, so we do nothing and just move on to the&lt;br /&gt;  // next shell in the list.&lt;br /&gt;  continue;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;nsRect r = shell-&gt;GetPresContext()-&gt;GetVisibleArea();&lt;br /&gt;nsCOMPtr&lt;nsipresshell&gt; shellGrip = shell;&lt;br /&gt;nsresult rv = shell-&gt;InitialReflow(r.width, r.height);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;由nsPresShell的InitialReflow方法来启动布局，主要作用是根据文档元素的类型、属性的不同，而决定是否需要重新布局该文档元素及其子元素，一旦觉得有必要重新布局则调用nsPresShell的PostReflowEvent方法，它通过向主线程MainThread发送一个ReflowEvent，一旦MainThread接收到该ReflowEvent，其会由对应nsPresShell的DoFlushPendingNotifications方法来处理，其最终根据当前的nsView及原生窗口的不同，在windows平台上它会对原生的窗口句柄进行InvalidateRect或UpdateWindow处理，按照windows图形管理的逻辑，系统会根据相关条件，及时向该原生窗口句柄发送原生的WM_PAINT消息，而对处理原生的窗口消息，一般会由窗口创建时提供的窗口回调函数来处理，经过一番处理判断后会触发调用nsWindow::DispatchWindowEvent，进而会调用上面提到的&lt;/nsipresshell&gt;&lt;/nsipresshell&gt;&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;mEventCallback所对应的&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;&lt;nsipresshell&gt;&lt;nsipresshell&gt;公共的函数，其实现如下：&lt;br /&gt;//&lt;br /&gt;// Main events handler&lt;br /&gt;//&lt;br /&gt;nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent)&lt;br /&gt;{&lt;br /&gt;//printf(" %d %d %d (%d,%d) \n", aEvent-&gt;widget, aEvent-&gt;widgetSupports,&lt;br /&gt;//       aEvent-&gt;message, aEvent-&gt;point.x, aEvent-&gt;point.y);&lt;br /&gt;nsEventStatus result = nsEventStatus_eIgnore;&lt;br /&gt;nsView       *view = nsView::GetViewFor(aEvent-&gt;widget);&lt;br /&gt;&lt;br /&gt;if (view)&lt;br /&gt;{&lt;br /&gt; view-&gt;GetViewManager()-&gt;DispatchEvent(aEvent, &amp;amp;result);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return result;&lt;br /&gt;}&lt;br /&gt;进而由nsViewManager::DispatchEvent统一来处理事件，这时经过一些处理，往往需要重新渲染相关View，而渲染View的主要代码如下：&lt;br /&gt;&lt;br /&gt;void nsViewManager::RenderViews(nsView *aView, nsIRenderingContext&amp;amp; aRC,&lt;br /&gt;                             const nsRegion&amp;amp; aRegion)&lt;br /&gt;{&lt;br /&gt;if (mObserver) {&lt;br /&gt; nsView* displayRoot = GetDisplayRootFor(aView);&lt;br /&gt; nsPoint offsetToRoot = aView-&gt;GetOffsetTo(displayRoot);&lt;br /&gt; nsRegion damageRegion(aRegion);&lt;br /&gt; damageRegion.MoveBy(offsetToRoot);&lt;br /&gt;&lt;br /&gt; aRC.PushState();&lt;br /&gt; aRC.Translate(-offsetToRoot.x, -offsetToRoot.y);&lt;br /&gt; mObserver-&gt;Paint(displayRoot, &amp;amp;aRC, damageRegion);&lt;br /&gt; aRC.PopState();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;而上面提到的nsPresShell实例往往作为nsViewManager的一个Observer，这样工作就这样转交给nsPresShell来处理。而nsPresShell的Paint方法的主要内容如下：&lt;br /&gt;&lt;br /&gt;PresShell::Paint(nsIView*             aView,&lt;br /&gt;              nsIRenderingContext* aRenderingContext,&lt;br /&gt;              const nsRegion&amp;amp;      aDirtyRegion)&lt;br /&gt;{&lt;br /&gt;AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Paint);&lt;br /&gt;nsIFrame* frame;&lt;br /&gt;nsresult  rv = NS_OK;&lt;br /&gt;&lt;br /&gt;if (mIsDestroying) {&lt;br /&gt; NS_ASSERTION(PR_FALSE, "A paint message was dispatched to a destroyed PresShell");&lt;br /&gt; return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;NS_ASSERTION(!(nsnull == aView), "null view");&lt;br /&gt;&lt;br /&gt;frame = static_cast&lt;nsiframe*&gt;(aView-&gt;GetClientData());&lt;br /&gt;nscolor backgroundColor;&lt;br /&gt;mViewManager-&gt;GetDefaultBackgroundColor(&amp;amp;backgroundColor);&lt;br /&gt;for (nsIView *view = aView; view; view = view-&gt;GetParent()) {&lt;br /&gt; if (view-&gt;HasWidget()) {&lt;br /&gt;   PRBool widgetIsTransparent;&lt;br /&gt;   view-&gt;GetWidget()-&gt;GetHasTransparentBackground(widgetIsTransparent);&lt;br /&gt;   if (widgetIsTransparent) {&lt;br /&gt;     backgroundColor = NS_RGBA(0,0,0,0);&lt;br /&gt;     break;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if (!frame) {&lt;br /&gt; if (NS_GET_A(backgroundColor) &gt; 0) {&lt;br /&gt;   aRenderingContext-&gt;SetColor(backgroundColor);&lt;br /&gt;   aRenderingContext-&gt;FillRect(aDirtyRegion.GetBounds());&lt;br /&gt; }&lt;br /&gt; return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion,&lt;br /&gt;                         backgroundColor);&lt;br /&gt;&lt;br /&gt;return rv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;相关主要工作又转交给nsLayoutUtils::PaintFrame；其主要工作就是通过  nsDisplayListBuilder builder来建立一个nsDisplayList list，并调用nsDisplayList::Paint方法，其实现如下：&lt;br /&gt;&lt;br /&gt;void nsDisplayList::Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,&lt;br /&gt;                       const nsRect&amp;amp; aDirtyRect) const {&lt;br /&gt;for (nsDisplayItem* i = GetBottom(); i != nsnull; i = i-&gt;GetAbove()) {&lt;br /&gt; i-&gt;Paint(aBuilder, aCtx, aDirtyRect);&lt;br /&gt;}&lt;br /&gt;nsCSSRendering::DidPaint();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;在其中的for循环中会根据DisplayList Item构成的不同，会调用不同frame的Paint方法等，如&lt;br /&gt;nsDisplayText::Paint(nsDisplayListBuilder* aBuilder,&lt;br /&gt;  nsIRenderingContext* aCtx, const nsRect&amp;amp; aDirtyRect) {&lt;br /&gt;static_cast&lt;nstextframe*&gt;(mFrame)-&gt;&lt;br /&gt; PaintText(aCtx, aBuilder-&gt;ToReferenceFrame(mFrame), aDirtyRect);&lt;br /&gt;}&lt;br /&gt;通过这样一个流程，就会显示出相关内容给用户。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;六、总结分析&lt;/span&gt;&lt;br /&gt;通过上面初步的整理，对整个过程有了初步的了解，其中关键在于了解到LoadURI的发起、nsIStreamListener数据的接收、nsParser及nsContentSink对文档的组织构成、nsPresShell结合nsFrame、nsView、nsViewManager、nsWindow对内容的显示。总的说来整个过程是相当的复杂，毕竟自从Web服务端获取数据后在内核中需要不断的动态创建很多&lt;/nstextframe*&gt;&lt;/nsiframe*&gt;&lt;/nsipresshell&gt;&lt;/nsipresshell&gt;&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;对应的&lt;nsiwidget&gt;&lt;nsidocshell&gt;&lt;nsiuriloader&gt;&lt;nsichannel&gt;&lt;nsiinterfacerequestor&gt;&lt;nsdocumentopeninfo&gt;&lt;nsicontentviewer&gt;&lt;nsichannel&gt;&lt;nsicategorymanager&gt;&lt;nsidocumentloaderfactory&gt;&lt;nsicontentviewercontainer*&gt;&lt;nsicontentviewercontainer&gt;&lt;nsidocument&gt;&lt;nsidocumentviewer&gt;&lt;nsicontentsink&gt;&lt;nsicontentsink&gt;&lt;nsixmlcontentsink&gt;&lt;nsihtmlcontentsink&gt;&lt;nsiwidget&gt;&lt;nsidevicecontext&gt;&lt;nsipresshell&gt;&lt;nsipresshell&gt;&lt;nsipresshell&gt;类对象，但&lt;span style="font-weight: bold;"&gt;关键流程的流转在于&lt;/span&gt;&lt;/nsipresshell&gt;&lt;/nsipresshell&gt;&lt;/nsipresshell&gt;&lt;/nsidevicecontext&gt;&lt;/nsiwidget&gt;&lt;/nsihtmlcontentsink&gt;&lt;/nsixmlcontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsicontentsink&gt;&lt;/nsidocumentviewer&gt;&lt;/nsidocument&gt;&lt;/nsicontentviewercontainer&gt;&lt;/nsicontentviewercontainer*&gt;&lt;/nsidocumentloaderfactory&gt;&lt;/nsicategorymanager&gt;&lt;/nsichannel&gt;&lt;/nsicontentviewer&gt;&lt;/nsdocumentopeninfo&gt;&lt;/nsiinterfacerequestor&gt;&lt;/nsichannel&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;&lt;span style="font-weight: bold;"&gt;对nsInputStreamReadyEvent事件和ReflowEvent两个事件的处理&lt;/span&gt;，有了这样基本的认识之后，对于css文档、image文档、js文档、plugin的处理，应该有了扎实的基础准备，至于具体每一html标签、xul标签具体对应哪些Node、Frame、Widget还须具体结合自身的不同加以分析。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;七、参考网址&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.org/docs/url_load.html"&gt;The Life Of An HTML HTTP Request&lt;/a&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;&lt;/nsiuriloader&gt;&lt;/nsidocshell&gt;&lt;/nsiwidget&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-7237680845033387534?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/7237680845033387534/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=7237680845033387534' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/7237680845033387534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/7237680845033387534'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/07/geckothe-life-of-html-http-request.html' title='浅谈Gecko关键部分之四The life of an html http Request'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-9122567404894815557</id><published>2008-06-27T22:04:00.000+08:00</published><updated>2008-06-28T02:07:23.080+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Gecko'/><category scheme='http://www.blogger.com/atom/ns#' term='线程'/><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之三线程管理及主要线程</title><content type='html'>&lt;p&gt;作为一个浏览器内核，Gecko所要完成的任务是非常繁杂的，其主要任务就是根据用户提供的资源地址，通过http协议从Web服务器中取得页面文档，然后解析其内容，最后根据一定的约定在浏览器指定区域中显示出页面，其中往往涉及网络编程及图形界面编程，而大家通常都知道的是网络编程中的连接、读取数据等往往需要考虑到服务器端的情况，一般采用异步方式来确保有效处理服务端返回的数据包括连接不成功、错误处理等；而图形界面的处理往往需要采用一个主消息循环及回调函数的方式来处理用户的动作，为了给用户提供平滑的操作及兼顾后台服务器的不确定性，一个可行的浏览器内核必须充分利用多线程来协调处理复杂的应用场景，只有这样才能高效的完成其所要完成的任务，如果能够初步了解Gecko内核的线程模型及相关线程管理的知识，对了解Gecko是非常有帮助的，下面初步了解Gecko是如何进行线程管理及其主要线程实现。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;一、Gecko线程模型&lt;/strong&gt;&lt;br /&gt;为了统一接口编程，Gecko将其线程模型按照组件的方式来处理，定义的接口主要有nsIRunnable、nsIEventTarget、nsIThread、nsIThreadManager、nsIThreadPool，其中nsIThreadManager由nsThreadManager来实现，它主要用于来管理所有的nsThread，包括创建nsThread实例，并通过维护一些系统原生线程的属性可以判断同一段代码是在什么线程的上下文中调用，从而可作出不同的处理，如GetIsMainThread可以判定当前执行线程是否为主线程，这一点在Gecko中应该得到了充分的应用，同时nsThreadManager的实例属于sington模式，在第一次启用XPCOM组件时由NS_InitXPCOM3实例化出来，以供以后管理nsThread使用；&lt;br /&gt;&lt;br /&gt;nsThread代表一个一般意义上的原生线程，在其构造函数中会初始化它并启动原生线程，它同时增加了EventQueue及ThreadObserver的概念，其函数入口为nsThread::ThreadFunc，在线程的整个周期中也即nsThread::ThreadFunc中不断的处理外部线程或本身向其EventQueue中Dispatch来的Event，同时每处理一个Event之前都会检查其是否存在Observer，如存在则先让Observer调用其OnProcessNextEvent来处理该Event，然后调用Event本身提供的run方法，这样增加了nsThread处理Event的灵活性；同时nsThread统一由nsThreadManager来创建，通过调用其Shutdown方法来结束该线程；并提供了一组外部接口来进行线程管理操作，如&lt;br /&gt;NS_NewThread、NS_GetMainThread、NS_DispatchToMainThread、NS_ProcessNextEvent等以供不同线程调用，同时保证线程安全；&lt;br /&gt;&lt;br /&gt;nsThreadPool代表一组线程，当外部向其Dispatch一个Event时它先会向其中的EventQueue添加该Event，然后它会根据设置的参数来决定是否分配一个nsThread来处理该Event，一旦创建了一些nsThread则将其维护在mThreads队列中，同时向该nsThread Dispatch这个nsThreadPool实例以让该nsThread去执行该nsThreadPool的run方法，这样可保证线程池中的每个nsThread的执行体都是nsThreadPool中的run方法，在其run方法中会根据是否空闲等条件自动ShutDown一些暂时不用的nsThread，以达到线程池的目的，即当任务事件Event繁多的时候多开启一些线程来处理，一旦任务完成则释放大部分空闲线程，保持一小部分线程以等待新任务的分配及提交；nsThreadPool在异步读取网络流数据的时候会经常用到，以后有机会可具体分析其应用场景；&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;二、Gecko主要线程&lt;/strong&gt;&lt;br /&gt;MainThread是Gecko的主线程，也即进程启动时的执行序列，它主要处理图形界面的消息循环以及其他线程向它Dispatch过来的Event，这样可以有机的结合图形界面的处理及网络数据的读取、解析、渲染等。MainThread线程充分利用了Gecko线程模型特点，既能处理原生的窗口消息，又可及时处理其它线程通知给它的Event，其执行主体往往是Gecko的核心，据初步统计其执行时间往往占整个程序执行时间的90%以上，其效率的高低直接决定了是否会让用户产生阻塞停顿的感觉。其主要实现逻辑是在启动XPCOM当中会在nsThreadManager初始化时自动产生一个nsThread实例mMainThread，它代表进程启动时的执行序列，待该执行序列完成其他基本准备后，在nsBaseAppShell::Init中将其Observer设置为nsBaseAppShell实例本身，具体参考如下：&lt;br /&gt;&lt;br /&gt;nsresult nsBaseAppShell::Init()&lt;br /&gt;{ // Configure ourselves as an observer for the current thread:&lt;br /&gt;nsCOMPtr&lt;nsithreadinternal&gt; threadInt = do_QueryInterface(NS_GetCurrentThread()); NS_ENSURE_STATE(threadInt);&lt;br /&gt;threadInt-&gt;SetObserver(this);//mObserver=&gt;this&lt;br /&gt;nsCOMPtr&lt;nsiobserverservice&gt; obsSvc = do_GetService("@mozilla.org/observer-service;1");&lt;br /&gt;if (obsSvc) obsSvc-&gt;AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);&lt;br /&gt;return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;NS_IMETHODIMP nsBaseAppShell::Run(void)&lt;br /&gt;{&lt;br /&gt;nsIThread *thread = NS_GetCurrentThread();&lt;br /&gt;NS_ENSURE_STATE(!mRunWasCalled); // should not call Run twice mRunWasCalled = PR_TRUE;&lt;br /&gt;while (!mExiting) NS_ProcessNextEvent(thread);&lt;br /&gt;NS_ProcessPendingEvents(thread);&lt;br /&gt;return NS_OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;PRBool NS_ProcessNextEvent(nsIThread *thread, PRBool mayWait)&lt;br /&gt;{&lt;br /&gt;nsCOMPtr&lt;nsithread&gt; current;&lt;br /&gt;if (!thread) {&lt;br /&gt;NS_GetCurrentThread(getter_AddRefs(current));&lt;br /&gt;NS_ENSURE_TRUE(current, PR_FALSE);&lt;br /&gt;thread = current.get();&lt;br /&gt;}&lt;br /&gt;PRBool val;&lt;br /&gt;return NS_SUCCEEDED(thread-&gt;ProcessNextEvent(mayWait, &amp;amp;val)) &amp;amp;&amp;amp; val;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;NS_IMETHODIMP nsThread::ProcessNextEvent(PRBool mayWait, PRBool *result)&lt;br /&gt;{&lt;br /&gt;..........&lt;br /&gt;nsCOMPtr&lt;nsithreadobserver&gt; obs = mObserver;&lt;br /&gt;if (obs) obs-&gt;OnProcessNextEvent(this, mayWait &amp;amp;&amp;amp; !ShuttingDown(), mRunningEvent);&lt;br /&gt;&lt;br /&gt;mEvents-&gt;GetEvent(mayWait &amp;amp;&amp;amp; !ShuttingDown(), getter_AddRefs(event));&lt;br /&gt;*result = (event.get() != nsnull);&lt;br /&gt;nsresult rv = NS_OK;&lt;br /&gt;if (event) {&lt;br /&gt;++mRunningEvent;&lt;br /&gt;event-&gt;Run();&lt;br /&gt;--mRunningEvent;&lt;br /&gt;}&lt;br /&gt;else if (mayWait)&lt;br /&gt;{ .........}&lt;br /&gt;&lt;br /&gt;if (obs) obs-&gt;AfterProcessNextEvent(this, mRunningEvent);&lt;br /&gt;..........&lt;br /&gt;return rv;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;其中关键点在于MainThread的mObserver是nsAppShell实例，那么它的OnProcessNextEvent都作了些啥呢？主要是根据情形调用其ProcessNextNativeEvent方法，其实现如下：&lt;br /&gt;&lt;br /&gt;PRBool nsAppShell::ProcessNextNativeEvent(PRBool mayWait)&lt;br /&gt;{&lt;br /&gt;PRBool gotMessage = PR_FALSE;&lt;br /&gt;do&lt;br /&gt;{&lt;br /&gt;MSG msg; // Give priority to system messages (in particular keyboard, mouse, timer, // and paint messages).&lt;br /&gt;if (PeekKeyAndIMEMessage(&amp;amp;msg, NULL) ::PeekMessageW(&amp;amp;msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ::PeekMessageW(&amp;amp;msg, NULL, 0, 0, PM_REMOVE))&lt;br /&gt;{&lt;br /&gt;gotMessage = PR_TRUE;&lt;br /&gt;if (msg.message == WM_QUIT)&lt;br /&gt;{&lt;br /&gt;Exit();&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt;::TranslateMessage(&amp;amp;msg);&lt;br /&gt;::DispatchMessageW(&amp;amp;msg);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;else if (mayWait) {&lt;br /&gt;// Block and wait for any posted application message&lt;br /&gt;::WaitMessage();&lt;br /&gt;}&lt;br /&gt;} while (!gotMessage &amp;amp;&amp;amp; mayWait);&lt;br /&gt;return gotMessage;&lt;br /&gt;}&lt;br /&gt;这个函数是否觉得非常的面熟？？？&lt;br /&gt;&lt;br /&gt;nsSocketTransportService作为异步处理socket读写的线程，在程序启动就会实例化，有时间可以仔细看看\mozilla\network\base\src\nsSocketTransportService2.cpp，其主要代码应该与一般多线程网络程序差不多。&lt;br /&gt;&lt;br /&gt;至于其他关于TimerThread、ThreadPool及javascript垃圾回收线程等以后有时间再来分析。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;三、参考网址&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://developer.mozilla.org/en/docs/The_Thread_Manager"&gt;The Thread Manager&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.mozilla.org/XPCOM:nsIThreadManager"&gt;XPCOM:nsIThreadManager&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-9122567404894815557?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/9122567404894815557/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=9122567404894815557' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/9122567404894815557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/9122567404894815557'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/06/gecko_27.html' title='浅谈Gecko关键部分之三线程管理及主要线程'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-63305908923617284</id><published>2008-06-20T21:25:00.000+08:00</published><updated>2008-06-21T09:03:11.131+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之二内存分配使用回收</title><content type='html'>2008年6月17日Firefox3Release版本已正式发布啦，可喜可贺，毕竟经历3年多的努力Mozilla社区终于又能给大家带来一些震撼、新希望，甚至冲动，其中包含很多人性化的东东以及最近几年发展起来的很多有趣的extensions，并且经过一些比较，似乎这个版本部分解决了困扰人们很久的内存使用大多及内存泄漏的问题，是否完全能化解人们心中的疑问可能还有待时间及实践来证明。借助人们很关注的问题，今天也来了解了解相关的内存分配使用回收问题。内存的使用及防止泄漏是c/c++程序员非常关心的问题，一旦有泄漏发生往往都感觉到非常头痛，所以我们也很有必要关心这方面的问题，看看Firefox这些Hacker们究竟是如何来面对这些问题的。&lt;br /&gt;&lt;br /&gt;     &lt;span style="font-weight: bold;"&gt;一、&lt;/span&gt;内存管理的主要方式&lt;br /&gt;     为了尽可能合理高效的使用内存，不同的系统使用了一些各具特色的内存管理机制，1、以java为代表的garbagecollector，所有的资源经由虚拟机来分配、回收，大大降低了java程序员对内存管理的困扰，但也带来了程序速度启动变慢，占用内存较多的问题，特别在程序使用了多种资源后，当然这种机制还在脚本语言如javascript、python、perl等的实现中也得到充分的使用，并且通过一些优化算法，已经达到了很好的效果；2、以linux内核为代表Slab allocation机制，它通过一些缓存及固定长度分配器来有效解决由于多次及不固定长度内存分配可能带来的内存碎片问题；3、以apache为代表的内存池机制，它往往会先malloc一大块内存，以供后续程序内存申请使用，特别在内存分配申请频繁的情况下大大降低程序对系统层的内存申请次数，同时可以起到类似部分garbagecollector的作用。&lt;br /&gt;&lt;br /&gt;     二、主要Gecko内存管理机制&lt;br /&gt;     1、组件的生命周期可简单归纳为首先在factory的createInstance中通过new出一个类实例，然后通过queryInterface进行接口转换及维护mRefCnt，并检查mRefCnt是否为0，如是则delete该实例，主要实现原理可参考XPCOM组件相关开发资料，对应源代码可参考\mozilla\xpcom\glue\nsISupportsImpl.h及\mozilla\xpcom\glue\nsISupportsUtils.h等。当然也有部分类override operator new方法，但往往都是作清零的处理，根本没涉及到更深层的内存管理，而new/delete动作往往分别直接对应系统层的malloc/free方法，所以几乎没有上面提到的垃圾回收、Slab及内存池的使用，当然对javascript的实现是肯定会有相关垃圾回收机制的，但它的出发点往往为了满足脚本语言的要求。&lt;br /&gt;&lt;br /&gt;    2、对于一些字符串及数组的内存使用往往采用NS_Alloc/NS_Free等，其实现代码对应于XPCom的FrozenFunctions中指定的AllocFunc/FreeFunc，其由\mozilla\nsprpub\pr\src\malloc\Prmem.c中对应的PR_Malloc及PR_Free来实现，其中根据是否使用use_zone_allocator来检查直接调用系统malloc及free还是采取一定类似内存池及slab allocation的方法来统一管理内存的分配。其具体实现代码可详见\mozilla\nsprpub\pr\src\malloc\Prmem.c及Prmalloc.c等。对于NS_Alloc/NS_Free的使用，往往用在一些atoms、tags等当中，总的说来使用不是很多。。&lt;br /&gt;&lt;br /&gt;    3、为了防止组件之间的循环引用，引入了nsICycleCollector来单独处理这个问题，以尽可能的避免无法释放由于程序逻辑造成的内存冗余，具体实现可参考\mozilla\xpcom\base\nsCycleCollector.cpp；同时为了让程序占系统内存达到一定比例后，采用momory reporter机制要求系统flush/swap一些内存，供程序继续使用；另外结合nsGarbageCollector及nsLeakDetector来扫描stack检测是否存在内存泄漏。&lt;br /&gt;&lt;br /&gt;    4、网上关于gecko的内存使用的讨论非常多，现提供一些相关资料以供大家参考，从多方面了解gecko内存管理等方面的问题，从自己的角度来了解它，以拓展我们的思路。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://ajaxian.com/archives/mozilla-hunting-for-memory"&gt;Mozilla hunting for memory&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://www.squarefree.com/2007/09/20/firefox-memory-usage-and-memory-leak-news/"&gt;Firefox memory usage and memory leak news&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://wiki.mozilla.org/Performance:Leak_Tools"&gt;Performance:Leak Tools&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://wiki.mozilla.org/LeakingPages"&gt;Performance:Leak Pages&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://developer.mozilla.org/en/docs/Using_XPCOM_in_JavaScript_without_leaking"&gt;Using XPCOM in JavaScript without leaking&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Slab_allocation"&gt;Slab allocation&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Fragmentation_%28computer%29"&gt;Fragmentation(Computer)&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://swik.net/AllPeers/Blog/Should+Mozilla+Drop+Gecko+for+WebKit%3F/bo76d"&gt;Should Mozilla Drop Gecko for WebKit?&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://www.nabble.com/Update-on-memory-allocation-control-proposal...-td17993067.html"&gt;WebKit update on memory allocation control proposal&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;a href="http://www.nabble.com/WebKit-memory-management--td17638201.html"&gt;WebKit memory management?&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-63305908923617284?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/63305908923617284/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=63305908923617284' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/63305908923617284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/63305908923617284'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/06/gecko.html' title='浅谈Gecko关键部分之二内存分配使用回收'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-1016308113946362689</id><published>2008-06-13T20:26:00.000+08:00</published><updated>2008-08-09T01:39:57.330+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>浅谈Gecko关键部分之一XPCOM组件</title><content type='html'>为了便于统一认识下面将Gecko统称为Firefox内核引擎而不仅仅代表渲染引擎，为了能更加有效的加深对它的理解，能够从本质上了解它的构成，下面从个人认为最为关键的几个部分来分析了解它，争取通过对这几个关键部分的了解总结能让自己从六百万行Gecko代码中逃脱出来，进而产生一点点一览纵山小的感觉，以致对Gecko的认识有本质上的提升。现首先从XPCOM组件开始，因为它是Gecko的基础，就像COM对于windows，没有从根本上对XPCOM的理解与把握就不可能对Gecko有深入的理解，同时对XPCOM的理解也只是对Gecko理解的入门。&lt;br /&gt;&lt;br /&gt;      &lt;span style="font-weight: bold;"&gt;一、&lt;/span&gt;究竟什么是XPCOM？&lt;br /&gt;      XPCOM is a cross platform component object model. It has multiple language bindings, letting the XPCOM components be used and implemented in JavaScript, Java, and Python in addition to C++.它是一个组件对象模型，与Windows中的COM非常类似，如果以前深入接触过COM的朋友，应该对XPCOM的认识会很轻松，个人认为它相对COM来讲可能相对简单点，毕竟它不涉及到线程管理、内存管理，从大体来讲它仅仅包括最基本的对象生命周期管理模型，当中涉及到类工厂、Sington等模式的应用。可能由于XPCOM刚开始在90年代初设计的时候，对组件对象模型的认识还比较浅显，所以它采用了最基本的引用计数形式来管理组件对象，没有更深层次的与内存管理、线程管理结合起来，可能正是由于这个原因在Gecko的代码中经常看到相关的注释提醒作者注意这个变量是referenced，而不会真正的参与到真实对象的生命周期管理，以防止对象间循环引用，从而给可能的内存泄漏埋下了祸根。&lt;br /&gt;&lt;br /&gt;       二、为什么需要XPCOM？&lt;br /&gt;      也许这样问有人或许觉得很白痴。不过个人觉得如能真正理解为什么需要XPCOM，那么针对形式各异的XPCOM组件运用也就会见怪不怪啦。需要XPCOM这个模型个人认为应该是&lt;span style="font-weight: bold;"&gt;基于接口编程&lt;/span&gt;的真实需要，基于接口编程能够&lt;span style="font-weight: bold;"&gt;有效的实现对业务对象基于平台、基于语言及实现形式的扩展&lt;/span&gt;。Gecko作为一个跨平台的内核引擎，倘若没有这种基于接口的模型会使系统变得更加的庞杂，也许为了更加简单及统一Gecko已将XPCOM这一对象模型发挥引用得淋漓尽致，基本上能抽象独立出来的逻辑业务如Timer、Thread、EventQueue、http等等都通通定义成含有相对固定接口的对象模型。其实作为一个大型复杂系统，个人认为这样做是很有必要的。&lt;br /&gt;&lt;br /&gt;      现举两三例来说明，试想不同的平台如windows、linux等都有不同的图形界面接口，其中有的是原生的如xlib、windows原生接口，也有抽象层的如gtk、qt、wxwidget、mfc等，作为一个可以支持多种图形界面接口的内核，首先在结合自身需要及原生图形界面接口的基础之上抽象出诸如nsIBaseWindow、nsIWidget、nsIMenu、nsIEventSink等等公共的接口，然后针对不同平台的具体实现分布在mozilla\widget\src\不同的qt、windows、gtk2、mac目录中，这样直接明了统一。同时值得留意的是mozilla\widget\src\build\目录下有一个nsWinWidgetFactory.cpp，其主要职责在于根据编译选项选定的平台注册对应目录下实现的组件，以供其他组件调用。其主要内容为：&lt;br /&gt;static const nsModuleComponentInfo components[] =&lt;br /&gt;{&lt;br /&gt;{ "nsWindow",&lt;br /&gt;  NS_WINDOW_CID,&lt;br /&gt;  "@mozilla.org/widgets/window/win;1",&lt;br /&gt;  nsWindowConstructor },&lt;br /&gt;{ "Child nsWindow",&lt;br /&gt;  NS_CHILD_CID,&lt;br /&gt;  "@mozilla.org/widgets/child_window/win;1",&lt;br /&gt;  ChildWindowConstructor },&lt;br /&gt;{ "Clipboard",&lt;br /&gt;  NS_CLIPBOARD_CID,&lt;br /&gt;  //    "@mozilla.org/widget/clipboard/win;1",&lt;br /&gt;  "@mozilla.org/widget/clipboard;1",&lt;br /&gt;  nsClipboardConstructor },&lt;br /&gt;{ "Clipboard Helper",&lt;br /&gt;  NS_CLIPBOARDHELPER_CID,&lt;br /&gt;  "@mozilla.org/widget/clipboardhelper;1",&lt;br /&gt;  nsClipboardHelperConstructor },&lt;br /&gt;{ "AppShell",&lt;br /&gt;  NS_APPSHELL_CID,&lt;br /&gt;  "@mozilla.org/widget/appshell/win;1",&lt;br /&gt;  nsAppShellConstructor },&lt;br /&gt;{ "Toolkit",&lt;br /&gt;  NS_TOOLKIT_CID,&lt;br /&gt;  "@mozilla.org/widget/toolkit/win;1",&lt;br /&gt;  nsToolkitConstructor },&lt;br /&gt;{ "Look And Feel",&lt;br /&gt;  NS_LOOKANDFEEL_CID,&lt;br /&gt;  "@mozilla.org/widget/lookandfeel;1",&lt;br /&gt;  nsLookAndFeelConstructor },&lt;br /&gt;{ "Transferable",&lt;br /&gt;  NS_TRANSFERABLE_CID,&lt;br /&gt;  //    "@mozilla.org/widget/transferable/win;1",&lt;br /&gt;  "@mozilla.org/widget/transferable;1",&lt;br /&gt;  nsTransferableConstructor },&lt;br /&gt;{ "HTML Format Converter",&lt;br /&gt;  NS_HTMLFORMATCONVERTER_CID,&lt;br /&gt;  "@mozilla.org/widget/htmlformatconverter;1",&lt;br /&gt;  nsHTMLFormatConverterConstructor },&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;NS_IMPL_NSGETMODULE(nsWidgetModule, components)&lt;br /&gt;&lt;br /&gt;      其实Gecko的实现代码中与此类似的有很多很多，如我们大家了解的MIMI类型有很多如html、xml、svg、txt、jpeg、gif、png等等，首先抽象出nsIDocument，然后依据其类型的不同分别实现其对应的逻辑，具体可参考\mozilla\content\base\public\nsIDocument.h；\mozilla\content\html\document\src\nsHTMLDocument.cpp，nsImageDocument.cpp；\mozilla\content\xul\document\src\nsXULDocument.cpp等；再如我们了解浏览器实现的协议有http、ftp等，为了统一不同协议的实现框架及能扩展到不同的协议，首先抽象出一组接口如nsIURL、nsIStreamListener、nsIStreamLoader、nsIChannel、nsIRequest、nsIRequesetObserver等，然后在不同的目录如http、ftp、file中按公共接口框架实现其逻辑，Gecko利用这种协议接口框架还扩展了about、data、resource等协议模式，如果了解了其公共接口框架并初步了解其中一个协议的实现方式，我们就可很方便的扩充到未实现的协议或自定义的协议实现。Gecko利用XPCOM模型为我们提供了很多很多类似的公共接口框架，以便扩展，其实总的说来，对于Gecko来讲这种方式几乎无处不在，正是这样的架构设计创造了Gecko的强大、丰富而具有生命力。有兴趣的朋友可以按这个基本思路从其代码实现中找到诸如扩展一个html标签、一个css属性、一种文件格式等等实现范例，以掌控其设计精髓以致扩展它为我们所用。&lt;br /&gt;&lt;br /&gt;      三、XPCOM主要特性&lt;br /&gt;      在XPCOM提供了丰富的功能的基础上，个人认为其主要特性有1、需要深入了解其引用计数对象管理机制及内存管理，特别在与跨语言方面如javascript、python等的实现与交互时，须防止跨边界的内存泄漏；2、很多组件通过xpconnect已实现与javascript的交互&lt;其实这是Gecko非常重要的一部分，以后有机会再专题分析&gt;，大大丰富了用c/c++实现的组件的应用场景，当然XPCOM组件也提供了与python、java方面的扩充与交互，不过支持程度没有javascript强，因为毕竟XPCOM组件与javascript的交互是Gecko的基石；3、为了充分利用组件对象模型，Gecko的实现中使用了大量的Sington、Observer、adapter等设计模式，如在nsDocShell中关于nsIWebProgress、AddProgressListener、nsIInterfaceRequestor等相关实现中得到充分的体现。其中Sington模式的使用有时往往具有鲜明的特点。其一般实现为XXXService，如WindowWatcher、CommandLineHandle、UriLoader等等。&lt;br /&gt;///*****************************************************************************&lt;br /&gt;// nsDocShell::nsIInterfaceRequestor&lt;br /&gt;//*****************************************************************************&lt;br /&gt;NS_IMETHODIMP nsDocShell::GetInterface(const nsIID &amp;amp; aIID, void **aSink)&lt;br /&gt;{&lt;br /&gt;  NS_PRECONDITION(aSink, "null out param");&lt;br /&gt;&lt;br /&gt;  *aSink = nsnull;&lt;br /&gt;&lt;br /&gt;  if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {&lt;br /&gt;      *aSink = mContentListener;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) &amp;amp;&amp;amp;&lt;br /&gt;           NS_SUCCEEDED(EnsureScriptEnvironment())) {&lt;br /&gt;      *aSink = mScriptGlobal;&lt;br /&gt;  }&lt;br /&gt;  else if ((aIID.Equals(NS_GET_IID(nsIDOMWindowInternal)) ||&lt;br /&gt;            aIID.Equals(NS_GET_IID(nsPIDOMWindow)) ||&lt;br /&gt;            aIID.Equals(NS_GET_IID(nsIDOMWindow))) &amp;amp;&amp;amp;&lt;br /&gt;           NS_SUCCEEDED(EnsureScriptEnvironment())) {&lt;br /&gt;      return mScriptGlobal-&gt;QueryInterface(aIID, aSink);&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &amp;amp;&amp;amp;&lt;br /&gt;           NS_SUCCEEDED(EnsureContentViewer())) {&lt;br /&gt;      mContentViewer-&gt;GetDOMDocument((nsIDOMDocument **) aSink);&lt;br /&gt;      return *aSink ? NS_OK : NS_NOINTERFACE;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &amp;amp;&amp;amp;&lt;br /&gt;           NS_SUCCEEDED(EnsureScriptEnvironment())) {&lt;br /&gt;      nsresult rv;&lt;br /&gt;      nsCOMPtr&lt;nsiwindowwatcher&gt; wwatch =&lt;br /&gt;          do_GetService(NS_WINDOWWATCHER_CONTRACTID, &amp;amp;rv);&lt;br /&gt;      NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;      nsCOMPtr&lt;nsidomwindow&gt; window(do_QueryInterface(mScriptGlobal));&lt;br /&gt;&lt;br /&gt;      // Get the an auth prompter for our window so that the parenting&lt;br /&gt;      // of the dialogs works as it should when using tabs.&lt;br /&gt;&lt;br /&gt;      nsIPrompt *prompt;&lt;br /&gt;      rv = wwatch-&gt;GetNewPrompter(window, &amp;amp;prompt);&lt;br /&gt;      NS_ENSURE_SUCCESS(rv, rv);&lt;br /&gt;&lt;br /&gt;      *aSink = prompt;&lt;br /&gt;      return NS_OK;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {&lt;br /&gt;      return NS_SUCCEEDED(&lt;br /&gt;              GetAuthPrompt(PROMPT_NORMAL, (nsIAuthPrompt **) aSink)) ?&lt;br /&gt;              NS_OK : NS_NOINTERFACE;&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsISHistory))) {&lt;br /&gt;      nsCOMPtr&lt;nsishistory&gt; shistory;&lt;br /&gt;      nsresult&lt;br /&gt;          rv =&lt;br /&gt;          GetSessionHistory(getter_AddRefs(shistory));&lt;br /&gt;      if (NS_SUCCEEDED(rv) &amp;amp;&amp;amp; shistory) {&lt;br /&gt;          *aSink = shistory;&lt;br /&gt;          NS_ADDREF((nsISupports *) * aSink);&lt;br /&gt;          return NS_OK;&lt;br /&gt;      }&lt;br /&gt;      return NS_NOINTERFACE;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {&lt;br /&gt;      nsresult rv = EnsureFind();&lt;br /&gt;      if (NS_FAILED(rv)) return rv;&lt;br /&gt;&lt;br /&gt;      *aSink = mFind;&lt;br /&gt;      NS_ADDREF((nsISupports*)*aSink);&lt;br /&gt;      return NS_OK;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) &amp;amp;&amp;amp; NS_SUCCEEDED(EnsureEditorData())) {&lt;br /&gt;    nsCOMPtr&lt;nsieditingsession&gt; editingSession;&lt;br /&gt;    mEditorData-&gt;GetEditingSession(getter_AddRefs(editingSession));&lt;br /&gt;    if (editingSession)&lt;br /&gt;    {&lt;br /&gt;      *aSink = editingSession;&lt;br /&gt;      NS_ADDREF((nsISupports *)*aSink);&lt;br /&gt;      return NS_OK;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return NS_NOINTERFACE;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList))&lt;br /&gt;          &amp;amp;&amp;amp; NS_SUCCEEDED(EnsureTransferableHookData())) {&lt;br /&gt;      *aSink = mTransferableHookData;&lt;br /&gt;      NS_ADDREF((nsISupports *)*aSink);&lt;br /&gt;      return NS_OK;&lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {&lt;br /&gt;    nsCOMPtr&lt;nsipresshell&gt; shell;&lt;br /&gt;    nsresult rv = GetPresShell(getter_AddRefs(shell));&lt;br /&gt;    if (NS_SUCCEEDED(rv) &amp;amp;&amp;amp; shell)&lt;br /&gt;      return shell-&gt;QueryInterface(aIID,aSink); &lt;br /&gt;  }&lt;br /&gt;  else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {&lt;br /&gt;    nsCOMPtr&lt;nsidocshelltreeowner&gt; treeOwner;&lt;br /&gt;    nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));&lt;br /&gt;    if (NS_SUCCEEDED(rv) &amp;amp;&amp;amp; treeOwner)&lt;br /&gt;      return treeOwner-&gt;QueryInterface(aIID, aSink);&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;      return nsDocLoader::GetInterface(aIID, aSink);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  NS_IF_ADDREF(((nsISupports *) * aSink));&lt;br /&gt;  return *aSink ? NS_OK : NS_NOINTERFACE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;     四、XPCOM相关参考资源&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/en/docs/XPCOM"&gt;Mozilla XPCOM官方网站&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.csdn.net/absurd"&gt;国内absurd博客&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.cnblogs.com/phinecos/archive/2008/06/02/1212027.html"&gt;Phinecos(洞庭散人)《XPCOM组件开发》笔记&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/nsidocshelltreeowner&gt;&lt;/nsipresshell&gt;&lt;/nsieditingsession&gt;&lt;/nsishistory&gt;&lt;/nsidomwindow&gt;&lt;/nsiwindowwatcher&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-1016308113946362689?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/1016308113946362689/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=1016308113946362689' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1016308113946362689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1016308113946362689'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/06/geckoxpcom.html' title='浅谈Gecko关键部分之一XPCOM组件'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-2532681174096915826</id><published>2008-06-07T20:21:00.000+08:00</published><updated>2008-06-08T00:40:26.364+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mozilla相关'/><title type='text'>认识了解Mozilla,Gecko,FireFox</title><content type='html'>最近关于浏览器的新闻很多如Firefox3RC2已经发布了，过不了多久许多Fans翘首以盼很久的Firefox3正式版本也就粉墨登场啦；IE8、Safari、Opera都正热火朝天的发Beta版，似乎真有浏览器大战的架式；这不国内的Maxthon也想更换或调整其浏览器内核，看样子浏览器开发可正引领目前IT技术发展的一个潮流，再加上所谓AIR平台的发展，简直赚足了人们的眼球，大有当年Java刚出现时所展现的风光及所向披靡。&lt;br /&gt;&lt;br /&gt;        哪其中究竟有什么值得我们这些具有贫瘠IT技术引领创新能力的阿斗所特别需要关注的呢？&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;       首先&lt;/span&gt;作为一个IT技术应用成员，觉得大家应该好好重视这个现象包括浏览器开发、web2.0、手机开发等，因为它或许会决定你我今后5年或10年的IT技术及应用发展方向，直接决定我们的生存方式及能否生存。其中原因应该在于Web的发展日益与人们的生活分不开，它需要更新，需要发展&lt;可以自己从最基本的想想看&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;       其次&lt;/span&gt;这次所谓的浏览器大战的始作俑者应该是Mozilla，这个基金会与浏览器的出现及Web的发展有作千丝万缕的关系(大家有兴趣可以搜索一下浏览器的发展就知道啦)，并且Mozilla开发所涉及的方面也是最为全面的如浏览器、AIR、手机等方面，而Mozilla的重中之重应该就是Gecko内核，所以我们很有必要深入了解认识一下它们Mozilla、Gecko及Firefox，包括它们的过去、现在及将来。&lt;br /&gt;&lt;br /&gt;        下面初步的认识了解一下它们&lt;br /&gt;         &lt;span style="font-weight: bold;"&gt;一、&lt;/span&gt;Mozilla严格说应该是一个开源基金会，不是一家公司，它应该具备世界上开源组织所特有一些特性如非盈利为目的、开源，有一群狂热的IT牛人在捣鼓着，不过目前它应该得到谷歌的大力支持，也许谷歌自己不单独开发浏览器也就是因为Mozilla。有空可去其官方网站&lt;br /&gt;&lt;a href="http://www.mozilla.org/foundation/"&gt;&lt;span style="font-weight: bold;"&gt;http://www.mozilla.org/foundation/&lt;/span&gt;&lt;/a&gt;瞧瞧。。。&lt;br /&gt;       &lt;br /&gt;        &lt;span style="font-weight: bold;"&gt;二、Gecko&lt;/span&gt;应该说&lt;b&gt;&lt;/b&gt;是 a &lt;a href="http://en.wikipedia.org/wiki/Layout_engine" title="Layout engine"&gt;layout engine&lt;/a&gt; originally created by &lt;a href="http://en.wikipedia.org/wiki/Netscape_Communications_Corporation" class="mw-redirect" title="Netscape Communications Corporation"&gt;Netscape Communications Corporation&lt;/a&gt; for the &lt;a href="http://en.wikipedia.org/wiki/Mozilla_application_suite" class="mw-redirect" title="Mozilla application suite"&gt;Mozilla application suite&lt;/a&gt; and now used in all applications developed by &lt;a href="http://en.wikipedia.org/wiki/Mozilla" title="Mozilla"&gt;Mozilla&lt;/a&gt;, including later &lt;a href="http://en.wikipedia.org/wiki/Netscape_Navigator" title="Netscape Navigator"&gt;Netscape Navigator&lt;/a&gt; releases.它包含浏览器及AIR平台的核心，其主要实现支持标准有&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/HTML" title="HTML"&gt;HTML&lt;/a&gt; 4.0&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets" title="Cascading Style Sheets"&gt;CSS&lt;/a&gt; Level 1 (partial support for CSS 2 and 3)&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/JavaScript" title="JavaScript"&gt;JavaScript&lt;/a&gt; 1.7&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Document_Object_Model" title="Document Object Model"&gt;DOM&lt;/a&gt; Level 1 and 2 (partial support for DOM 3)&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/XML" title="XML"&gt;XML&lt;/a&gt; 1.0&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/XHTML" title="XHTML"&gt;XHTML&lt;/a&gt; 1.1&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/XSLT" class="mw-redirect" title="XSLT"&gt;XSLT&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/XPath" title="XPath"&gt;XPath&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/MathML" title="MathML"&gt;MathML&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/XForms" title="XForms"&gt;XForms&lt;/a&gt; (via an official extension)&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Resource_Description_Framework" title="Resource Description Framework"&gt;RDF&lt;/a&gt;&lt;/li&gt;&lt;li&gt;partially supports &lt;a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics" title="Scalable Vector Graphics"&gt;SVG&lt;/a&gt; 1.1&lt;/li&gt;&lt;/ul&gt;      应该说要了解Firefox必须了解Gecko，目前版本为1.9a，是除IE内核Trident之外第二大浏览器内核，同时它具有独到的特点：跨平台，支持windows、类unix、Mac；对XUL的充分实现与支持，仅这一点就超越了以往界面实现方式，并且经过多年的测试及提升应该有了很好的执行效率，其实这也是AIR所创导的核心;当然它也支持SVG、RDF、XBL；还有更重要的是它是定义及实现javascript的鼻祖，并正引领着javascript虚拟机化(大家想想看java的虚拟机的威力)，一旦整合了jvm实现技术中的优缺点，其威力可真不少，再说jvm已经发展10多年啦，相关技术已稳定成熟，那些IT大牛们完全可以采取拿来主义，很有可能比jvm实现得还要好，这样的话也许以后一般的电脑完全真的只需要一个浏览器就可以搞定一切啦。Gecko中的两大主题content/layout/render、javascript发展的好坏直接决定其能否在浏览器大战中胜出，当然其他的浏览器或平台要想在浏览器大战中突出重围必须在这两者之间杀出一条血路，目前综合说来Gecko占有一定先发优势，同时是其他竞争者模仿、想超越的对象，所以对于我们来讲具有很大的参考学习作用，同时毕竟是开源的嘛。&lt;br /&gt;&lt;br /&gt;        &lt;span style="font-weight: bold;"&gt;三、Firefox &lt;/span&gt;应该说仅仅是一个浏览器而已，它能够象IE一样满足大家上网冲浪的切实需求，同时它或许更安全更小巧；但由于它完全基于Gecko内核便于扩充，这不&lt;a href="http://addons.mozilla.org/?application=firefox"&gt;http://addons.mozilla.org/?application=firefox&lt;/a&gt;上就有各种各样好玩的东东等着大家去捣捣，也许会让你发出原来自己的浏览器竟然可以变成这样的感叹，这不Web应用开发两大巨头谷歌、雅虎公司已经在其中开发了不少应用，很值得看一看借鉴借鉴。或许正是这么多因素导致Firefox正引领着浏览器的使用及发展，毕竟使用浏览器上网的人非常非常多，具有个性化的上网活动也许正在形成，应该说Firefox正深深的紧密的参与其中。&lt;br /&gt;&lt;br /&gt;       其实国内听说了解Firefox也许不少，但经常使用Firefox的人相对来说还是蛮少的，真正了解Mozilla及Gecko的人也许就更少啦，但个人觉得Firefox、Gecko这两年发展可真快了，或许它就是未来的发展方向，抛点砖希望大家有空一起了解关注甚至研究研究Firefox/Gecko。&lt;br /&gt;&lt;br /&gt;&lt;h3 id="appendix_1"&gt;参考网址&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Gecko_%28layout_engine%29"&gt;Gecko Wiki&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://baike.baidu.com/view/7681.html"&gt;百度百科Firefox火狐浏览器&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.mozilla.org/"&gt;Mozilla Developer Center&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kb.mozillazine.org/"&gt;MozillaZine Knowledge Base&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-2532681174096915826?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/2532681174096915826/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=2532681174096915826' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/2532681174096915826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/2532681174096915826'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/06/mozillageckofirefox.html' title='认识了解Mozilla,Gecko,FireFox'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1021548603024561100.post-1047160723549575784</id><published>2008-06-01T21:57:00.000+08:00</published><updated>2008-06-01T23:22:13.722+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活随想'/><title type='text'>新的启航，简单快乐的活着！</title><content type='html'>今天第一次开始写点东西，希望能给平平庸庸的生活添点色彩、动力、希望。&lt;br /&gt;&lt;br /&gt;        今天同时也是儿童节，祝一些过成年人儿童节的朋友们节日快乐开心。虽然童年时代已经较远，蓦然回首，是否觉得岁月无情，蹉跎岁月犹如滚滚长江东去水；是否觉得我们的天空与童年时代的有太多的不同；是否觉得我们已不再年轻，不再有理想，不再简单而快乐着；是的，我们长大了，生活环境变了，欲望多了，压力大了，苦恼多了，变得不再那么的简单。&lt;br /&gt;&lt;br /&gt;         过去的就让它过去好啦，我们目前的生活还要继续，但愿能多点童心去发现认识这个世界，多带来一点点快乐，有空可与小朋友一起玩玩，想他所想，按他们喜欢的方式去生活，这不从电视上看到四川灾区的小朋友与外国大朋友一起玩耍是多么的开心与快乐？！也许世界本来就很简单，我们得坚强简单开心的活着。。。&lt;br /&gt;&lt;br /&gt;        作为技术从业人员，每天与似乎冷酷无情的什么语言、工具、Bug打交道，再好的童心也给泯灭啦！这不恕我建议大家把我们学习的语言、工具权且当作我们小时候玩的玩具好啦，找自己喜欢的，有时间就与小朋友一起去切磋，玩的不开心了，换个玩具，换些朋友一起玩；如果有捣鼓拆玩具的冲动，可别忘了带着小时的童心去捣鼓，过不多久，说不定您就变成了胜利大王，天下无敌呢。。。&lt;br /&gt;&lt;br /&gt;        好了，但愿大家面对枯燥的生活，多去捣鼓捣鼓，简单快乐至上。不过有点需要提醒自己的就是童年时代爱好学习或玩的习惯可千万不要丢了(这不有科学家研究发现3岁前我们的思维方式性格等就已基本成型，会无形中影响我们一生呢？何不充分调动起小时就养成的方法方式来面对现在的一切呢？！)，长大了我们必须到社会上去学习去玩，学的越快玩的越开还是一样的很值得骄傲开心哦！如果还能保持点童心，那可就锦上添花啦，说不定您就能变成故事小说中的老顽童呢。&lt;br /&gt;&lt;br /&gt;让我们一起简单快乐的活着，人生苦短，从童年到成年，您感受到了吗？！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1021548603024561100-1047160723549575784?l=ourpgh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ourpgh.blogspot.com/feeds/1047160723549575784/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1021548603024561100&amp;postID=1047160723549575784' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1047160723549575784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1021548603024561100/posts/default/1047160723549575784'/><link rel='alternate' type='text/html' href='http://ourpgh.blogspot.com/2008/06/blog-post.html' title='新的启航，简单快乐的活着！'/><author><name>Suk</name><uri>http://www.blogger.com/profile/06298037612661270352</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
