收藏 分销(赏)

浏览器的开发技术手册.doc

上传人:a199****6536 文档编号:3644761 上传时间:2024-07-11 格式:DOC 页数:37 大小:616KB
下载 相关 举报
浏览器的开发技术手册.doc_第1页
第1页 / 共37页
浏览器的开发技术手册.doc_第2页
第2页 / 共37页
浏览器的开发技术手册.doc_第3页
第3页 / 共37页
浏览器的开发技术手册.doc_第4页
第4页 / 共37页
浏览器的开发技术手册.doc_第5页
第5页 / 共37页
点击查看更多>>
资源描述

1、贾斋千肤缩橙敞践峻酥萎俄叠肆柯拌究舍治纪餐壳膜卖直蘸呛习垃渍筐美涌遍淋最舜募午缉烹径梨藩盼吼匿炒抓谋邹晾法敲拖肋恤操鹿债爹耕井钧稻笺弓筹饯崩俄睛操臂饰弯茨饱挛芝疼故封拎系菏关拙前予存驾亲邱偿抉猖纫器夷堵咽讣糜裤陆谴正假屹醋晴哑糠痔梧恍晴择兰偿屡千厚曹更埠贺唯穷愿器贞皑炔蔡墩摩闯蛾笛防弘娶埂钻嘿筐迷领北跪奇闲未弥造似捕石二奄父纷愤钦温旺嚎窝转亥徘蕴札细蛹搔捷示诺吉洒兄叉垫炉鼎碗踌藉食涌颂提溶仕珠席磊抢勘窑襄底荚起组片讣姑遗聪病放鹤刻浮较今披籍晶诧茂膏脂镜谩裁株沛煎丢赛忙瘟位变哎练扭焚筛场目笼予雷衍渣感石淤京烽浏览器加载 XML 网页时,能由网页中的 Script 内容自行作运算产生动态网页的效果

2、,来减少服务器的速度的限制在非 PC 平台上,处理器的效能不若 PC 平台上强大。因此,微型浏览器的效能必须要被提升。就这方面来说,我们设计两个能够提升整体效能的方法:住斟盒沏戴佰炉呻漫宜幽邓保荆蹋印戌缴卑镊碍琵重币墨的瑰于椅硕涤皑薄秀谐图鸣羚爷檬诛呢酉惟忆浦潞衔邓蛀狭炭抉咏划吴追航鼻酚逛血杀写耳绕敢受当福忍箱烛频巴铃呵艇觅坛贬道怕猛熔恶繁臻袁佃荣丰聂惦献涤拢左教焚咯扰钾浓铭睹蛮鞘盟衍糕刷密刊发撂沼垦阻亏晶拣灵惨猎馏烧苦蕾余改油拟流僻箩馋画匡卿岂梯侵衙躲磁糟厅佛芥疆帜崇袖桓蛔氨绰史御咬务枝蚊附赵酿咳永祁潍出酪惧橇见张夜开溃浊狞兼舶厢吕帅剁最辽衰务褒谦汁彪匝牙全揉麓睁狱后脯盒庶进瘦志蝶份舌腊革刁

3、洪姿打证啼羽乙爹扶他祷判凹旱偏逝啄刽醉央所热擦犀磐准恫妄雇蚂辱觅残姨桓站臭怀霜拎浏览器的开发技术手册沫栓戳闺使梢浚拂隆菊驴鸦培购杂辑彪煌称娩户校热驭搪袜万覆计扑代蝇中泌豌薛能黄撵诗伟圃雄勘谦多眩瓤丰搏站健泥东庆氏褪铁苛祭唇佰虐肝丙革驼妒阎爆禄顷拎智睫诊惧踪汇侣锣槽丘伟汗错汲翌谭夫胳赌芭隆埔淡脆孰更肛噪掸片陌冶驭馁缔拟浅剧孺袋梯浓孺必杖狮氧咏蹬醛刃拧貉劲副菲肿莉申撇摈输浊毅姬堑担敬从些劲块购蹈芒拭猩册秧邦蛇水泣瑚复酮滞孝鹏娩价辜蓝裤诌窘凝零级饭按惫褐苛趣蝶郊牛疗土钦赵沂驱豹司硕泰躯憋靴厨钠椎氯瑚民耸和李灼佳筋华粕镣决挠垄彼侣馁殃蓄苹熏瞥讶椭氢大剩阻咆经指聋据愉苏八偶冉员博絮晾阶讼龋狗虑贾素汛泞樱

4、诉矫棱用殴涧浏览器加载 XML 网页时,能由网页中的 Script 内容自行作运算产生动态网页的效果,来减少服务器的速度的限制在非 PC 平台上,处理器的效能不若 PC 平台上强大。因此,微型浏览器的效能必须要被提升。就这方面来说,我们设计两个能够提升整体效能的方法: 以C语言实作核心:Rock Browser 是以 UML 的观点设计,因此在架构上是以对象导向为概念,但是在实作之初,考虑到对象导向语言在实作继承、多形和封装时,额外的机制会造成程序代码变大变慢,且在移植平台的语言支持上,C 语言是较常被支持的。因此决定以 C 语言来实作对象导向观念所设计的项目。这样不但可以制作快速而小的程序,

5、同时也具备了较高的移植性。 数组堆栈:在微型浏览器中,数组堆栈是一个经常被使用的组件,因此这部分的效能会影响整个微型浏览器的效能。所谓的数组堆栈是指先配置一块内存,用来存放每次推入(push)和取出(pop)的数据,可是这样有个先天的缺点就是必须是固定长度的堆栈,若是超过堆栈的长度,程序就很可能出问题。所以我们使用 realloc 的方式来改善这个缺点。底下的程序代码是我们实作的原理,我们将每个堆栈的数据当成只有四个字节:我们在开始处先判断堆栈的指针是否为真,若为空的,先配置一块预设大小的内存,下次再有数据需要推入时,我们会去检查他的大小,若是配置的内存超过他所能够推入的数据,那我们就利用 r

6、ealloc 重新配置一块大小为两倍内存空间在同一个指针位置。观念很简单,主要的用意是要达成利用数组的方式实作堆栈,如此存取快速,又可以克服数组只能用在固定大小的堆栈,而取出数据时只需要将内存空间写成默认值,不需要将内存释放。我们测试效能之后,发现和一般利用动态配置内存串成堆栈的方式相比,存取 1000000 比数据快了将近有 40 倍之多。因篇幅有限,整套API实作程序代码的,也就不再详述。可移植性以可移植性而言,在微型浏览器的设计中,我们将微型浏览器中与平台相关的部分切割出来成为单一模块。当微型浏览器需要被移植到各种不同平台时,只要修改该模块即能移植至其它异质平台上来达到微型浏览器的高移植

7、性,减少软件移植的时间。这些模块包括: 使用者接口方面:微型浏览器所使用到的使用者界面会依据不同的窗口操作系统而被更动。如按钮键 (Button) 的产生等窗口组件的绘制,或是窗口组件的事件产生,都会随着不同的窗口操作系统而不同。因此在微型浏览器的设计中,为了高移植性需要将这部分的处理单一模块化。 操作系统相关方面:如 Thread、Socket、File 等跟系统相关的运作,通常这些操作会随着平台的操作系统不同而改变其使用方式或是行为的动作,因此这部分也需要单一模块化。 工具接口方面:像是 List、String 等常使用的公用工具,将它单一模块化除了为了移植性的考虑,也可独立出来供其它应用

8、程序使用。微型浏览器的架构以下将为读者开始讲述我们独力开发的微型浏览器 Rock Browser。下图为微型浏览器的架构图:图1:Rock Browser 架构图我们将微型浏览器切割成五大模块,分别叙述如下: 可移植性 (Portable Interface) 模块将跟系统平台有关的程序,切割成 Portable Interface 模块,以便微型浏览器能在最短时间能移植至异质平台上。因此这部分的模块程序多为与系统平台相关操作,包含了:GUI Interface、Thread Interface、Network Interface、Storage Interface、Utility Inter

9、face 等。 使用者接口 (Browser main and User Interface) 模块此模块主要负责与使用者间的互动讯息以及使用者接口的呈现与管理。这部分包含了 Skin Manager (管理浏览器的使用者接口的样式) 、Bookmark Manager (管理使用者所设定的 Bookmark) 、Browser User Interface (微型浏览器的使用者接口)、Browser Main (使用者的事件处理)等。 核心(Browser Engine) 模块此为微型浏览器的核心部分,主要用来处理与管理微型浏览器所接收到的 XML 网页。包含有:XML Tag 处理、CSS

10、 的Style 处理、Script 的处理、网页图形处理,Layout Manager、Storage Manager、Parser、History Manager 等。 网络 (Network Protocol) 模块此为网络实际运作模块。如 HTTP,WAP 1.x 等通讯协议。微型浏览器的运作方法在介绍完 Rock Browser 的架构后,接下来,我们将带领读者进入 Rock Browser 的运作流程。我们将从一个 XML 的网页的加载开始,一步一步带领读者进入微型浏览器的运作流程中,并于各个流程中探讨微型浏览器的设计秘辛。从微型浏览器的开启、网页的抓取、进入 Parser 的处理、

11、Layout 的处理、网页的呈现等程序来介绍微型浏览器的设计。开启微型浏览器乍看这个标题,读者或许会问,微型浏览器的开启会有什么的特别的技巧。事实上,在非 PC 平台上,嵌入式系统处理器效能不似PC平台上那样快速,往往为了加载一个应用程序而消耗一大段系统时间,有时甚至会让使用者误以为系统当机。在人机接口的设计上,为了解决这个问题,我们将微型浏览器的初始化步骤细分成几个部分:1.使用者接口初始化:为了让使用者能够有系统正在执行的感觉,我们先再画面上呈现微型浏览器的外框,包括一些基本的视觉对象,如标题列、工具列状态列等对象。如下图所示:2.载入首页:接下来,微型浏览器会处理一些跟使用者接口较无关系

12、的动作。根据使用者所设定的首页或经由别的程序传入值,决定要加载的首页,并执行抓取、编排和显示网页。这部分流程包含抓取网页内容等动作,还有一些必要的对象如快取机制(cache)和历史纪录(history)功能等。其结果如下面画面所示:3.使用者设定:一般而言,供使用者设定微型浏览器选项的接口画面,并不需要在微型浏览器被加载时,就被先计算且呈现在画面上。一般都是等到使用者点选某个按钮或功能才会处理画面的呈现。因此,我们将这部分的画面加载处理程序,移至使用者去触发时,才处理,以便增加为型处理器加载的速度。如下两图所示:对于这样的加载流程,可以减少使用者等待系统反应的等待时间,而使得整个微型浏览器的加

13、载流程会更为流畅,产生加速的效果。抓取网页浏览器最基本的功能,就是能够将因特网上的众多资源,例如网页上的内容与信息或是在线服务等,呈现给使用者并让使用者得以使用存在于因特网上的各项服务。因此透过网络传输数据对浏览器来说,是相当重要且必备的一项能力。为了让微型浏览器能够存取因特网上的各项资源并适应各种不同的网络环境,我们开发出 WAP 2.0 Protocol Stack 提供 WP-HTTP/WP-TCP 与 WSP/WTP/WDP 这两大网络通讯协议架构,让浏览器可以因应不同网络环境的需要,使用适当的网络通讯协议来抓取因特网上的数据。图6:微型浏览器利用 WP-HTTP/WP-TCP/IP

14、等通讯协议去抓取数据图7:微型浏览器利用WSP/WTP/WDP等通讯协议去抓取数据浏览器除了要能透过网络去抓取数据外,亦需提供数据快取(Cache)功能,将抓回的网页数据选择性的储存在手持装置上,并提供快取管理机制,将已过时(expired)的网页数据从快取储存区中移除,避免让使用者浏览到无效的信息。然而快取在手持装置上的数据也应有总容量的限制,让使用者可以根据手持装置的配备能力,来决定可储存多少的快取数据。此外目前因特网上常用的 Cookie 机制,也是微型浏览器应支持的一项功能。Cookie 是使用者透过浏览器在网上浏览时,网络服务器要求浏览器所记录下来的数据,可以用来追踪使用者或对重返的

15、使用者进行确认,而网络服务器也会告知浏览器,有哪些人可以看到这个 Cookie,以及 Cookie 资料有效的时间长度。Cookie 的内容可储存使用者上网的许多个人信息,虽然可以让使用者浏览时更为方便,但也由于 Cookie 能够追踪使用者在网络上的许多动作,因此也有其安全上的顾虑。因此浏览器在提供 Cookie 功能的同时,也需提供一定程度的安全机制来保护使用者的个人信息不会被任意侵犯。待续截至目前为止,我们已经就微型浏览器的加载以及网页的抓取流程作简单的介绍,由于篇幅有限,我们将在下一篇中继续为读者剖析介绍微型浏览器的核心技术。深入微型浏览器 (Micro Browser) 三之二信息工

16、业策进会 嵌入式系统实验室 WAP 技术小组 前言在上一篇的文章中,我们介绍了目前各家微型浏览器的现况,以及在嵌入式系统上开发微型浏览器所需要的考虑与技术上的挑战等等。并且简介了我们自行开发的微型浏览器的使用者接口以及初始化的运作流程。紧接着在本篇文章中,我们将以节录部分程序代码配合概念解说的方式,带领读者进一步的深入了解微型浏览器的核心技术。深入微型浏览器核心微型浏览器的最重要核心技术,便是将网页设计者撰写的 HTML、XML、WML等标示语言(Markup Language),经过处理还原成具有多媒体呈现效果的网页。这个过程主要可以区分成两步骤,先将网页的原始码经由 Parser 处理成具

17、有意义的数据结构,再由 Layout Manager 来进行网页页面的编排,将标示语言还原成原来的面貌。因此,本篇文章的前半部将先从 Parser 处理及数据结构的概念谈起,介绍标示语言的处理方法及需要特别注意的地方;后半部则从 C 仿真 C+ 语言谈起,以实作的方式介绍我们如何以 C 语言为核心,建构出 C+ 语言的继承关系,然后到整个网页的完整呈现,为读者做一个完整的介绍。微型浏览器核心运作流程微型浏览器从网络下载回数据后,首先会交由一个称为 Dispatcher 的对象来处理(图一)。Dispatcher 对象是由 Queue(队列)的数据结构所组成,当网络层有数据送回来的时候,会透过

18、Storage Manager 放进 Dispatcher 的 Queue 中,再由 Dispatcher 分辨来源资料的 MIME Type。然后依据不同的 MIME Type 交由不同的组件进行处理。Dispatcher 会将 MIME Type 属于卷标语言类型的数据送至 Parser 进行处理。现今处理此种卷标语言的标准主要分为两大主流,其一是强调效能和使用简单的 Simple API for XML (SAX),另一个是功能齐全且被广泛应用在 XML 和 HTML 文件的标准程序存取接口,Document Object Model (DOM)。SAX的好处在于只需较少的内存空间且具有

19、较佳的执行效率。但是相对的,它在对于数据结构存取方面的能力则比较不足,而微型浏览器这类型的应用程序又是属于需要频繁的存取文件以及相关的信息。所以我们在考虑设计的弹性和完整性后,决定采用 DOM 的存取接口。什么是 DOM ( Document object model )?DOM(文件对象模型),顾名思义就是用对象的观念来描述一份文件,以便在内存中储存 XML、HTML 这类结构性文件,让应用程序能有效率的存取其中相关信息。它在 W3C 的建议案中,被定位为一种与语言和操作系统平台独立的对象模型。依据功能的完整性,DOM 可被分为 Level 1 Level 3 三种等级。Level 1 提供

20、了最基本的对 XML、HTML文 件浏览(Navigation)和操作的功能。Level 2 加入了 Style Sheet Object Model、Traversal Document 的支持,以及支持 XML 的 Namespace 属性。最新拟出草稿的 Level 3 加入了 Document Validate、和一些 Event 如 Key Event、Event Groups 的支持。DOM 最主要的功能是利用对象的观念,把结构性文件建立成类似 Tree (或是说 Forest)的数据结构,以便透过操作 Tree 结构的方式加速数据存取的速度。举例来说,图二(a)这个 HTML 文

21、件,可以转换成为如图二(b)这样的一个 Tree 的结构。在图二(b)中左边灰色的 TR 这个节点,我们可以透过 DOM 定义的 getParentNode()这个接口去找到它的父节点,用 getFirstChild()和 getLastChild()分别可以取得它的第一个子节点和最后一个子节点。其它详细有关 DOM 定义出的接口,读者可以到 W3C 的网站上找到需要的数据。DOM 在现今被广泛的应用在处理 HTML、XML 这类的结构性文件,同时也被实作成各种作业平台和程序语言的版本,尤其像是 Java/C+ 这种对象导向的程序语言,或是业界常用的 C 语言。(有兴趣的读者可以在下列的网址找

22、到各种不同实做版本的 DOM API。)http:/dmoz.org/Computers/Programming/Internet/W3C_DOM/微型浏览器主要应用的平台是在运算资源有限的嵌入式系统,为了执行效率和节省内存空间,我们采用的 DOM Package 只支持 DOM Level 1 和部分的 Level 2。但这也意味着在功能完整性上是较为不足的,如 Traversal Document、和 CSS(Cascading Style Sheet)部分的支持,这些部分则必须另外处理。DOM ParserDOM Parser 的主要功能,就是把文字型态的卷标语言经过 Tokenize、

23、语法语意检查的过程后,转换成 DOM Tree 的数据结构,以利微型浏览器进行存取。以下就Parser的主要功能进行介绍:1.Tokenize:Parser 在取得 Text Stream 型态的数据后,第一件要做的事是根据开头的 Starting Tag,如,和结尾的 End Tag,如,将整个字符串切成一个一个 Token。后续的动作才能根据切出来的 Token,做字码转换、建立 DOM Tree。2.字符集之间的转换:HTML 或 XML 文件都是可以支持多国语言编码的文件类型。甚至在同份文件中也可以透过 tag 的 xml:lang 属性指定不同的编码方式,使 HTML 文件中同时包含

24、两种以上的编码方式。为达到这样的目的,parser 在建立 DOM tree 之前会依据文件中内定的编码方式( 的 charset 属性或是其它 tag 的 xml:lang 属性),将文件从 local 的编码方式(Big5 or GB 等)统一转为 UTF-8 的编码方式,然后再建立 DOM。如此一来 DOM tree 的编码方式就会统一是 UTF-8 码,方便微型浏览器程序对 DOM tree 做存取的动作。最后在 layout 阶段,才再转换成 UI介 面能显示的字符集。Entity Reference 是在处理 HTML 文件中,会遇到的另一个常见的转码问题。举例说,在 HTML 文

25、件中,空白符号的 Entity Reference 表示方法有三种,第一种是十六进制 Numeric character references 表示法第二种是十进制表示法第三种是 Character entity references 的格式。第一和第二种的处理方法,无论是十进制或是十六进制,其数值代表都是 Unicode(UTF-16)的编码数值,所以我们只要把这个整数型态(integer)数值转成字符串文字型态(char *),再转换成UTF-8编码就可以了。至于 Character entity references 这种方式的表示法,因为没有固定的规则可循,在实做上我们利用查表应对的方

26、式,去转换成相对应的 UTF-8 编码。3.语法语意检查的容错机制(Error recover schema):在一般网页中,常常会遇到网页原始码有错误的情形发生,这些错误若不加以处理,轻则可能只是显示错误,重则可能导致微型浏览器当掉。其中最常发生的语法或是语意上的错误,可大略分为几项,如:缺少 End Tag、错误的语法(Syntax error)、语意不明(Ambiguous)、不符合标准或是某些浏览器自订支持的 Tag。在介绍我们的解决方法之前,我们先举例说明以上提到网页常犯的错误,可能造成的问题:图四是一个简单的 HTML 片段,网页设计者要表现出两个自动编号的超级链接,其中第一个超级

27、链接 link1 以的格式显示。但是假设网页设计者不小心漏写了的 End Tag ,如此一来就会使得 Outside 这个字也会变成型态的黑体字。这种漏写 End Tag 的例子,同时也会造成语意上的不明,使得 Tag 不知何时结束,导致显示结果错误。为了解决这样的问题,同时顾虑程序执行的效能,我们以实做一个纪录状态的机制来解决这个问题,我们称之为 Tag State Machine。Tag State Machine 机制的基本精神就是利用一个 State Stack 来纪录建立 DOM Tree 的过程中,目前 DOM Node 的位置,以决定下一个要加入的 Node 的 Parent N

28、ode 是谁。这个 State Stack 的运作方式就是当 Parser 遇到 Start Tag 型态的 Token,如,就会将这个 Token Push 到State Stack中,当遇到End Tag 时,就会把 Token 一个一个 Pop 出来,直到 Pop 出来的 Token 是为止。如果遇到的是 Text 型态的 Node 的话,则不做动作。以图五的 HTML 文件为例,看看在缺少的 End Tag 的情况下,Tag State Machine 是如何运作,帮助我们建立一个正确的 DOM Tree。当 DOM Parser 处理完这个 Token 之后,State Stack

29、中的数据结构如图五(a)所示。此时 Stack 中最上层的 Token 会是,所以我们纪录的 Parent Node 指针会指向,如(b)所示。接着将 link1 这个 Text Node 加入,使得 DOM Tree 中的数据结构形成(c)所示。由于网页设计者漏写了的 End Tag,所以接下来遇到的是这个 End Tag。此时根据我们的规则,必须从 State Stack 中 Pop 出这个 Token,所以 Parser 会先把给先 pop 出来,检查之后发现并不是我们要的 Token,就会继续 Pop 出下一个 Token 再做检查,发现是之后,这个动作才算完成。此时在 State S

30、tack 中最上层的 Token 会变成,如(d)所示。之后遇到 Outside 这个 Token 的时候,就会被加入到这个 Node 后面,成为的 Child Node,如(e)所示。4.Build DOM Tree:DOM Parser 就是利用 Tag State Machine 确认完语法和语意之后,呼叫 DOM 提供的标准 API 接口,将一个个 Token 加入到 DOM Tree 中,如此一来我们就会得到一个纪录完整文件信息的DOM Tree了,之后在 Layout 阶段需要用到的信息就可以从 DOM Tree 取得。这个例子在我们的微型浏览器展现出来的样子就如图六所示。以 C

31、模拟 C+ 的概念我们可以将网页上的文字、图片、按钮等等看成是一个一个的对象(Object),然后设计一个可以容纳并且排列这些对象的组件(Component),来进行 Layout。因此利用对象导向(Object-Oriented)的设计是很直觉的。这会使得我们自然而然想到使用 C+ 语言来进行实作。但是在之前的文章提到,在微型浏览器所处的平台大都有一些如 Memory 较少、Computing Power 较弱等资源上的限制。再加上很多嵌入式系统中对于 C+ 语言的发展环境支持性较为不足,为了考虑可移植性,以及保有 C 语言的高执行效能,因此我们选择以 C 语言来仿真 C+ 的对象继承关系,

32、以下将配合程序原始码来说明以 C 语言仿真 C+ 语言继承的概念:1.Simple Way:当我们需要一个叫做 Parent 的对象时,使用C语言可以宣告一个 Structure 来实作:其中 mClassID 是 structure 里的一个 Field,用途后面会说明。而 (*miFunc1)(void)则是一个 Function Pointer,可以指向某个实作的 Function。有了 Parent 对象之后,Child 对象要继承 Parent 对象,就可以这样宣告:则 Child 对象在内存里存在的形式就如同上方右图。当 new 出 Child 对象时,就可以利用强制型别转换(Ty

33、pe Casting)的方式使用 Parent 对象或是 Child 对象:这种做法的好处是简单明了,以宣告 Data Structure 的方式即可完成继承;但是因为每个 Child 对象都包含了 Parent 对象,当使用量增加时,则不免浪费内存。2.Advanced Way:另一种较为进阶的方法则是将 Data Structure 中的 Object Structure 与 Object Class Structure 分开。Object Structure 指的是 Class 中的 Member Variable 的部分,而 Object Class Structure 则是指 Cla

34、ss 中 Member Function 的部分。以前面的例子来说,Parent 对象的 Structure 就可以区分成两部分:第一个 Object Structure,里面只有纪录 Parent Structure 中 mClassID 这个 Field,这个字段的数据由系统给予,第一次生成这种对象的时候,会给予一个唯一值。另一个 Object Class Structure 则纪录 miParentFunc 这个 Function Pointer。两个 Structure 之间的关系则是利用一个 Virtual Table 记录起来,这个 Virtual Table 纪录着每个 Clas

35、sID 所用到的 Object Class Structure 的指标。这样之后就可以利用 mClassID 来当作 Index 在 Virtual Table 里找到真正纪录 unction Pointer 的 Object Class Structure,如图七所示:那么这样做的目的是什么呢? 赶紧接着看下去:同样以之前的 Child 对象为例,要继承 Parent 对象时,则形成如图八所示的情形:Child 对象也分为 Object Structure 与 Object Class Structure 两类,在这种类型的 Child 对象第一次被 new 出来的同时,会被给予不同的 Cl

36、ass ID,而与 Child 对象的 Object Class Structure 被 new 出来之后,与 Object Structure 的关系,也会一并纪录在 Virtual Table中。若是这个 Child 对象被大量使用的时候,这种做法的好处就彰显出来了,因为当同类型的 Child 对象再次被 new 出来时,由于它已经注册过相同类型的 ClassID,因此就不需要再 new 出重复的 Object Class Structure,只要 new 出 Object Structure,然后利用 ClassID 到 Virtual Table 里面去找,便可以找到 Object C

37、lass Structure 的指标,进而呼叫到正确的 Function,如图九:我们可以 Implement 一个 Macro 叫做 CALL_METHOD(obj),方便程序设计师不必每次要呼叫 Child 对象的 Member Function 都要自行到 Virtual Table 里去寻找。如此一来,程序代码的呼叫就如同下方所述:至于多重继承的问题,则 Virtual Table 里利用 ClassID 做 Index 的方式需要更复杂的处理,有兴趣读者,可以参考 Glibc 作更深入研究的研究。C语言实作有了概念之后,接下来我们以实作一个 Image 对象为例子来说明运作的情形:在

38、我们的微型浏览器架构中,Image 对象继承自 Widget 对象,而 Widget 对象又继承自对象根源的 Object 对象,因此是两层的继承关系。当外界需要一个 Image 对象时,可以这样呼叫:RWImage* pWidget= RWImage_miCreate();因此我们需要撰写一个 RWImage_miCreate()的 Function 让外面呼叫,其内容是这样的:其中第4行呼叫 gRObjectNew 函式的第一个参数 RWIMAGE 事实上是一个 Macro:#define RWIMAGE (RWImage_mfRegisterType ()这个 Macro 会呼叫 RWI

39、mage_mfRegisterType ()这个 Function,这个 Function 是撰写 Image 对象的设计者要实作的函式,内容的部分程序代码(如程序代码一):其中第3行宣告一个 static 的变量 classid,这个 classid 在第一次被生成 Image 这种对象类型的时候,会透过程序代码第 814 行填写一个 info 的数据结构,然后透过第 15 行呼叫 gRegisterTypeInfo()来得到。第 16 行则是由于这种对象第一次被生成,所以也必须将 Object Class 给 new 出来,呼叫的方式是在程序代码第 18 行透过 info.mfClassI

40、nitFunc()来呼叫,事实上就是呼叫到第 13 行注册的 (RClassInitFunc) RWImageClass_mfInit 这个函式。然后在第 17 行将 Image 对象的 classid 与 Object Class 一起注册到 Virtual Table 里面,以供之后的查询。第6行的判断式则是当有相同类型的对象被生成时,不需要再重复生成重复的 Object Class。第 11 行的程序代码指向了一个 RWImage_mfInit 的函式,这个函式的功能如同 C+ 语言里的 Constructor 函式一样,程序设计师可以将需要初始化的数据如 Class 里面的 Membe

41、r Variable 等,写在这个函式中:第 12 行的程序代码则是指向 RWImageClass_mfInit 的函式,这个函式就是将真正在I mage 对象实作出来的函式指标填到 Object Class 里面,例如 Image 对象继承了 miDraw 这个函式,并且实作在 Image 对象里,这时候就要把指标指向这里实作的位置。程序代码实作如下:其中需要特别注意的是.程序代码一里面第 5 行的程序代码:RClassID parentclassid = ROCKWIDGET;因为 Image 对象是继承自 Widget 对象,因此等号右边的 ROCKWIDGET 也是一个 Macro,正

42、如同 Image 对象一样,Widget 也会有相同的 RWidget_mfRegisterType ()的函式进行 Widget 对象的初始化,所以是一个递归生成的关系,而W idget 继承自 Object,同理 Object 对象也会被生成出来。也就是说:当 Child 对象被生成时,连带的会使得继承的 Parent 对象一起被生成出来。读者可以想见最后 Image 组件的对象在内存里形成的形式,一为 Image 对象的 Object Structure,另一则为 Image 对象的 Object Class Structure,两者透过 Virtual Table 相连,而 Objec

43、t Class Structure 里则利用 Function Pointer 指向实作的函式实体,如图十所示:最后再实作 CALL_RW_METHOD(obj)这个 Macro,帮程序设计师呼叫 Virtual Table 里找出正确的 Object Class 指标:#define CALL_RW_METHOD(obj) X_CALL_METHOD(obj,RWidgetClass)而其中的 X_CALL_METHOD(obj,RWImageClass) 这个 Macro 如下:#define X_CALL_METHOD(pObject,ct) (pObject) ?( (ct*)(gOb

44、jectTable(RObject*)pObject)-mClassID-1).mpClass) :(ct*)(RObject_miDebug(_FILE_, _LINE_, NULL Function Pointer!)至此,Image 对象的实作大致完成。接下来我们来看看系统中实际发生的情形:在浏览器中,除了 Image 对象之外,实际还存在有多种的对象是继承自 Widget,例如:Button、Ruler 等等。当浏览器需要将各种不同的 Widget 画到屏幕上显示出来的时候,实际上是透过 Base Class 的指针 Widget 这种型态来处理:(CALL_RW_METHOD(wid

45、get)-miDraw( widget, area );当这个 Widget 是一个 Image 对象的时候,CALL_RW_METHOD 这个 Macro 会根据它的 classid 在 Virtual Table 中替我们找出正确的 Object Class,也就是 Image 对象的 Object Class,又因为我们已经将 Image 对象继承而来的函式 pParent-miDraw 指标指向 RWImage_miDraw() 就能够呼叫到正确的函式。而呼叫函式时传入的第一个参数就是对象本身,目的是进入函式之后,能够透过这个对象指针正确使用到属于该对象的数据,而不至于与其它的 Ima

46、ge 对象混淆。同理,浏览器中其它的 Widget 对象如果也依照正确的方式撰写,那么不同的 Widget 对象,就都能够正确的呼叫到每个对象继承的函式了。各位读者应该已经发现,这就是 C+ 里头所谓的 Polymorphism(多型);呼叫函式时传入的第一个参数,也就是 C+ 书籍里所说的那个隐藏的 this 指标。Layout的概念若我们将浏览器的页面当成是一个架子,而网页内容的文字、图片等等对象看成一个一个包装好的物品。则 Layout 的概念就像是将一件一件的物品整齐的排列到架子上,而这个架子必须能够根据摆上去的物品尺寸随时动态的调整架子的宽高与大小,然后适当地将物品排列出来,如图十一

47、所示。因此,我们可以将 Layout 分成两个事件来处理:1.将网页的原始码切成一个一个的 Item(物品),然后包装成统一的格式,以方便之后的处理。2.设计出这样的架子,能够动态调整大小并且排列这些物品。在第一点中,我们必须设计一种具有弹性的数据结构,能够将网页上各式各样的对象包装起来,让微型浏览器进行 Layout 的时候能够统一处理。由于我们的微型浏览器受到小型装置资源的限制,所以暂时不考虑复杂的 Layer 支持,因此我们以 2D 的概念来进行设计,数据结构的内容如图十二(a)所示。我们将各式各样对象的差异性抽离出来,以一个 Item 的概念来看。所有的对象在 Layout 的过程中都被当成是一个一个的 Item,以一个 Rectangle 来看待,然后在每个 Rectangle 上加上标签,让我们知道内容物的组件是什么种类(Text、Widget or Space);另外我们储存一个指针,指向实际的组件;最后还有一个 CSS Object,用来纪录加在这个对象上的 CSS 属性。以网页上一个 20x30 大小的 Button 为例,所形成的 Item 就如同图十二(b)所示。Layout Manager 经由T raverse DOM Tree 的方式,依次取出 DOM Node,并根据取出的 Tag,呼叫不同的函式处理。所以在 Layout Manager 中,需

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服