《深入理解Android》一2.3 WebKit架构概览-阿里云开发者社区

开发者社区> 华章计算机> 正文

《深入理解Android》一2.3 WebKit架构概览

简介:
+关注继续查看

本节书摘来自华章出版社《深入理解Android》一书中的第2章,第2.3节,作者孟德国 王耀龙 周金利 黎欢,更多章节内容可以访问云栖社区“华章计算机”公众号查看

2.3 WebKit架构概览

我们从浏览器的发展历程和现状分析中可以看出,WebKit是一个功能完备、性能优良、相对轻巧、使用广泛的排版内核,是诸多操作系统上开发浏览器的不二之选。本书集中论述Android 4.2平台上的WebKit移植版本,本节将从组成架构、工作流程和设计风格三个方面对Android WebKit做初步介绍,为读者简单梳理其庞大代码的整体样貌,也是对后续章节的引导。

2.3.1 整体组成架构

Android系统中的WebKit如图2-14所示既是一个Native的动态库也是Framework的一部分,从结构上大致可以划分为7个较为独立的组成部分:
WTF:Web Template Framework,公共基础库;
JS Engine: JavaScript引擎,负责JS脚本的执行,Android采用V8而非JavaScript Core;
WebCore:核心所在,负责HTML/CSS解析、排版和显示以及JS的DOM绑定;
Chromium-Net:Chrome浏览器源码中抽取的网络库;
Skia:Android和Chrome共同使用的图形库,负责底层的图形文字绘制工作;
WebKit:封装所有C++层代码,提供与Java层交互的接口;
Framework:对以上Native层代码的Java层封装,对外提供Framework层的WebKit API。

image

WebCore如图2-15所示是WebKit中最大最复杂的部分,也是排版引擎核心所在,其内部结构可大致进一步细分为如下若干子系统,每个子系统包含大小不一功能上彼此关联的若干模块:
Page:提供对外的总入口以及页面相关的Chrome、Setting、History等模块;
Document:解析html/xml/svg,生成DOM树的子系统;
CSS:负责CSS的解析和匹配;
Render:实现Layout和Render过程的子系统;
Graphics:封装底层图形库,对上提供一套平台无关的绘制接口;
Loader: 负责网络IO、Form Submission、Memory Cache等;
Script: 提供JS执行入口以及从C++对象到JS对象转换的Binding和Bridge;
Extension Modules:实现非DOM的HTML 5扩展JS功能模块,如Worker、WebSocket、WebStorage、FileAPI等,可能需要相应的Custom Binding代码;
Plugin:用于加载NPAPI插件,需要Bridge模块完成和JS引擎的互动;
Interaction: Editing、Accessibility等相对较独立的与交互、命令有关的模块。

image

下面重点介绍WebKit渲染主线上的一些关键概念和核心对象,理解了这些对象就等于抓住了主要节点,纲举目张事半功倍,读者可以从源码层面一一对照阅读分析。
Page模块如图2-16所示,Page类(位于Source/WebCore/page/Page.h)代表整个页面,一个Page对象包含一个作为MainFrame 的Frame对象(Source/WebCore/page/Frame.h)。每个Frame表示某URI对应的主文档资源在一个WebKit页面中加载后的可以呈现出可视化结果的一帧,因此对应一个FrameLoader类(Source/WebCore/loader/FrameLoader)、一个文档模型Document类(Source/WebCore/dom/Document.h)和一个视图FrameView类(Source/WebCore/page/FrameView.h)。Frame可以拥有子Frame,Frame之间可能构成一棵FrameTree,对应于网页中的iframe或frameset标签。和Page对象相关联的对象主要还有Setting对象(Source/WebCore/page/Setting.h)和Chrome对象(Source/WebCore/page/Chrome.h),分别表示页面设置和内容以外的外框。

image

WebKit将资源请求分成两类,分别交由主资源MainResourceLoader和子资源SubResourceLoader来处理。MainResourceLoader负责的是能够载入到Frame的HTML文档,SubResourceLoader对应的则是其余的JavaScript/CSS/Image等资源。ResourceLoader将请求和应答交由ResourceHandle类处理,ResourceHandle负责将网络和IO工作交给更底层的平台相关的对象去处理。Android 4.x系统中WebKit已经开始使用Chromium-Net网络库,网络模块单独移出,网络调用接口也直接上移至ResourceLoaderAndroid中。
Load过程都有各自的请求发起者,WebKit还根据请求对象生存期的不同,将Loader类拆分成不同类型。Page和Frame对应于页面标签和暴露给Shell层的WebView,它们请求URL加载,由FrameLoader负责处理。CachedResource类代表那些能够被缓存的资源,如JS/CSS/Image等,它们可以静态的持续存在,并和Cache模块关联,因此其加载由一个全局静态生存期的Loader类来负责。Frame对象load了某个URL之后,会根据其页面HTML生成对应的Document对象,Document对象的加载请求和应答则是通过DocumentLoader来转发完成。
Loader模块核心类的生存期和调用关系如图2-17所示。
文档对象模型(Document Object Model,DOM)是页面文档在浏览引擎内部的模型表示,Page/Frame/FrameView/WebView则相当于是页面的视图表示,Browser端JavaScript定义的事件方法等脚本则可看成是控制器,三者构成了类MVC的架构。WebKit中文档被Document类对象表示,HTML文档则是继承于Document类的HTMLDocument。文档节点由Node类对象表示,HTML页面元素是HTMLElement类,各种HTML标签元素对应的类都继承于HTMLElement。HTMLElement类和Document类中包含了DOM模型大部分接口内容。构成了浏览器端JavaScript的根对象是Window,在WebKit中对应的实现类则是DOMWindow。图2-18描绘了一些核心DOM对象的类型继承体系。
image

image

WebKit中Render树节点也以一系列具有继承体系的类来表示,其基本类型是RenderObject,具备CSS盒子模型的类型是RenderBoxModelObject,以Inline方式和Block方式排版的Render对象类型分别是RenderInline和RenderBox。为了处理CSS动画、页面内Video、定位方式和包含Z-Index元素的排版渲染,WebKit又引入了RenderLayer类。一个RenderLayer代表一个渲染中的分层,RenderLayer也构成一棵树。每个RenderObject都隶属于某个RenderLayer,通常具有共同坐标系的Render节点属于同一个RenderLayer。图2-19描绘了RenderObject部分重要派生类的继承结构。

image

2.3.2 核心工作流程

介绍完Android WebKit内部的架构组成和重点模块的关键对象之后,本节将根据2.1.2节中介绍的排版引擎工作原理来简单说明WebCore排版引擎各阶段工作的流程入口函数,读者可据此分析源码,顺藤摸瓜,一览究竟。
图2-20从整体上勾勒出了WebCore部分的工作流程图,可以看出其中包括HTML Parser、CSS Parser、Render树创建Attachment、Render树排版Layout和Render树绘制Painting这几个核心过程。
网络IO:加载一个URL的流程,在Framework中从WebView的loadUrl开始,在WebCore中则从FrameLoader::loadURL开始。

image

页面解析:HTML文本由DocumentWriter::addData方法传入,调用HTML DocumentParser类来解析页面。后者使用HTMLTokenizer类做词法分析,获取Token,再交由HTMLTreeBuilder去构建DOM树。
DOM树和Render树创建:建树过程从HTMLTreeBuilder::constructTreeFromTok-en开始,然后调用HTMLContructionSite类的insert类函数,依次把根据Token类型创建的HTMLElement对象加入到DOM树。而Render树的创建过程则以Element::attach方法开始,通过RenderObject::createObject静态方法创建,同时会计算出Element的CSSStyle。
布局排版:排版流程以一系列类的layout方法完成,以FrameView::layout方法为布局起始点,调用Render树根节点的layout,递归触发Render树节点的layout过程。FrameView::layout可以被布局timer或者Shell层的WebViewCore::layout方法触发。
绘制显示:在Android WebKit中,Render树的内容排版后要经过Paint和Draw两个阶段才能显示给最终用户,paint阶段是指把RenderObject的内容画到Bitmap上的过程,Draw阶段则使Bitmap内容最终显示出来,这两者分别在WebCore线程和UI线程中完成。Paint阶段和排版类似,以一系列类的paint方法完成,从FrameView::paint开始,调用RenderLayer树根节点的paintLayer,再依次递归调用Render树Object的paint方法绘制节点的内容。Draw阶段则由WebView类的draw或者drawGL方法触发。
脚本执行:WebKit中JS引擎的封装类为ScriptController,脚本执行的入口函数为ScriptController::evaluate方法。
事件处理:WebKit中的UI事件从Framework层传入给WebViewCore类,主要有keyEvent、mouseEvent、dragEvent和touchEvent等。事件处理的入口类是EventHandler,各种事件一般经EventHandler分发给DOM元素依次处理,按照冒泡事件消息传递的方法递归寻找EventHandler,最终被DefaultEventHandler吸收。

2.3.3 代码设计风格

WebKit开源项目在目前看来虽然体量很大,但是可读性很好,这与该项目从一开始就有着清晰的架构设计和良好的代码风格分不开。相比较而言,更加庞大的Gecko内核因种种原因则设计相对复杂,架构比较臃肿。正因如此苹果公司在开发自有Safari浏览器时,才抛弃了同样是开源的老牌Gecko而选择了不够完善但设计精巧的KHTML,即WebKit的前身。

  1. 代码风格
    下面简单说明WebKit中常用的一些代码技巧和风格,读者在阅读源码和本书的同时可加以留意。

内存管理:WebKit C++代码中内存管理最基本的模式是引用计数,RefCounted模板类定义了ref()和unref()计数加减方法,很多类都继承了该模板类。为了避免不正确或者遗漏的计数使用,又进一步引入了RefPtr和PassRefPtr两个智能指针模板类,它们重载了赋值操作符,自动完成有关计数加减的工作。WebCore中需要传递赋值的共享对象大多使用了智能指针代替指针持有,基本没有了内存泄露的可能。关于智能指针更详细的介绍参见第3章。
代码自动生成:WebKit中的DOM在C++有关模块中实现,同时需要把DOM接口暴露给JavaScript执行引擎。从C++对象到JS对象的Binding实现,WebKit采用了代码自动生成方法,使用Perl脚本根据DOM对象的IDL(Interface Description Language)接口描述文件完成code generator的工作,以机器代替手工编写了大量的Wrap代码。此外,CSS和HTML解析过程也或多或少地采用了机器代码生成的技巧,使得CSS属性值和HTML标签属性的自定义添加变得相当容易,只需修改相应的.in配置文件即可。IDL代码自动生成的细节参见第9章,HTML和CSS相关代码自动生成参见第5章。
代码编写风格:WebKit代码书写十分规范,包括缩进、空格、换行和括号的使用,变量的骆驼命名法(CamelCase),成员和静态成员的前缀区分,条件和分支判断,指针和引用,乃至头文件注释名字空间等都有涉及。代码阅读起来整齐优雅,根据命名大致能猜出含义,读者可参考网络上的官方coding style文档(https://www.webkit.org/coding/coding-style.html)。此外,代码文件的组织分布也有其规则,各模块文件层次有序地按目录结构分隔,平台有关的文件代码基本位于Source/WebCore/platform目录或Source/WebKit目录下对应平台名的子目录中。

  1. 设计模式
    设计模式是软件架构中针对普遍存在、反复出现的需求问题而提出的可复用的解决方案。这里给出一些WebKit中出现的设计模式例子,其具体实现方案与GOF经典设计模式可能会有所差异,但面对的问题域基本是一致的,读者可据此更快速地领会其代码设计意图和工作原理。

单例:单例模式是为了确保某个类仅有一个实例并提供全局访问。WebKit中Loader模块负责管理CachedResource的Memory Cache就是一个典型的单例模式,可缓存资源的管理器理所当然有且只有一个全局访问。
工厂方法:工厂方法模式也是一种创建型设计模式,用于解决在不指定对象具体类型的情况下创建对象的问题,WebKit中Parser模块最终创建实际的HTMLElement所面临的情况正与此类似。HTMLTreeBuilder类和HTMLConstructionSite类将HTML标签名传入工厂类HTMLElementFactory的createElement接口,由它来决定实际创建哪个类型的HTMLElement对象。
观察者模式:观察者模式让对象管理自己的观察者对象,发布事件消息或通知状态改变。WebKit中有很多名称的末尾为Client的类,如FrameLoaderClient、CachedResourceClient等,可以将它们看成是一种观察者类,被观察者如FrameLoader、CachedResource向其 Client观察者类通知自身的状态改变。
组合模式:组合模式通常用于将具有树状结构的对象组织成一个组合对象,WebKit中存在多个重要的树状数据结构,如DOM树、Render树、RenderLayer树等,它们的基类如ContainerNode、RenderObject、RenderLayer都有一套Children和Parent的管理方法,也可以视为组合模式的一个具体例子。
代理模式:代理模式使用一个代理类替原始类完成具体的操作,WebKit中Audio/Video有关元素的实现用到了该模式。HTMLMediaElement类包含一个MediaPlayer类对象来完成具体的多媒体播放功能,而MediaPlayer类则通过MediaPlayerPrivate类来实现实际真正的操作,这里MediaPlayerPrivate就可以看作MediaPlayer的Proxy。
命令模式:命令模式将动作及其参数封装起来用面向对象的设计来表示,WebKit中DOM模块的Event类和Editing模块的Command类都可以看作典型的命令模式实现。
责任链模式:责任链模式可以将命令对象在一系列处理对象中传递,处理对象自行决定如何处理命令或将不能处理的命令传递给链条中的下一个处理对象。WebKit对DOM事件处理的实现与该模式有关,Event对象(作为命令对象)在DOM树(作为处理对象)中按照一定规则(如冒泡)传递并寻找其Event Handler/Listener。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
9495 0
怎么设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程
8410 0
带你读《深入理解Android:Java虚拟机ART》之一:本书必读
本书将关注Android系统中至关重要的部分——Java虚拟机ART。随着Android设备的大规模普及,ART虚拟机已经成为当今使用最为广泛的JVM之一。所以,对ART虚拟机进行研究有着非同寻常的意义。本书的出现在一定程度上填补了这方面的空白。
3566 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10843 0
《深入解析Android 虚拟机》——2.5 内存异常和垃圾处理
对于C和C++的开发人员来说,在内存管理领域应该能够游刃有余。在计算机系统中,内存负责维护每一个对象生命的从开始到终结。Java内存分配与管理是Java的核心技术之一,通常Java在内存分配时会涉及到以下区域。
1784 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13183 0
10059
文章
0
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载