ABSTRACT
This paper is focused on the technology of embedded browser.Html scanner, JavaScript support for browser, linux and gtk programming are deeply discussed.and introduce the development of Netbit browser, analyse the main module of Netbit, the algorithm is presented.
what’s more, other typical embedded browsers are analysed, include Gzilla,Mozilla,Thunder and zen,and summarize the important technology and the policy of browser development
In addition,at the head of the paper,introduce the present status of embedded browser product,the general form of embedded browser and description of the main parts.
HTML scanner is a important technological problem, the data structure and the flow of the program are presented.
The development of Netbit Browser is mainly discussed,and analysed by module,give the opinion to improve it.
KEY WORDS:
embedded browser,HTML token,Javascript,linux,gtk
目 录
引言………………………………………………………………5
第一章 嵌入式浏览器设计概述 ………………………… 6
1.1目前嵌入式浏览器产品的发展现状 ……………………… 6
1.2嵌入式浏览器的组成和各部份功能说明 ………………… 8
1.3开发难度分析 ……………………………………………… 9
1.4开发的前期策划 …………………………………………… 10
第二章 HTML词法分析器的设计及其应用 …………… 12
2.1 Bit Token的组成及其功能 ………………………………12
2.2 数据结构 ……………………………………………………12
2.3 算法 …………………………………………………………13
2.4词法分析结果示意……………………………………………15
2.4 HTML词法分析的应用 ………………………………………15
第三章 浏览器JavaScript支持的实现 …………………18
3.1基本的JavaScript 开发环境 ………………………………18
3.2 JavaScript Engine …………………………………………18
3.3 JavaScript与浏览器接合 ………………………………… 19
3.4 浏览器消息响应 …………………………………………… 21
第四章 Linux程序开发技术及 GTK图形程序开发…… 23
4.1 Linux下的程序开发环境 ……………………………………23
4.2 GTK图形程序开发 ……………………………………………29
第五章 Netbit浏览器开发与分析 ……………………… 31
5.1 Netbit 浏览器简介 ………………………………………… 31
5.2 Netbit Browser浏览器各部份的功能 …………………… 31
5.3 界面模块………………………………………………………32
5.4 控制模块………………………………………………………34
5.5词法分析模块… ………………………………………………34
5.6使用PIXMAP的画图模块………………………………………35
5.7 文本文件的显示模块…………………………………………36
5.8 HTML文件的显示模块 ……………………………………… 37
5.9 Netbit实际应用效果及比较 ……………………………… 40
5.10 Netbit Browser的缺点分析及改进办法 …………………44
5.11 Netbit Browser未来的展望 ………………………………48
第六章 其它浏览器分析…………………………………… 50
6.1 Dillo(Gzilla)浏览器分析 ……………………………… 50
6.2 Thunder浏览器分析…………………………………………55
6.3 Mozilla浏览器分析…………………………………………56
6.4 ZEN浏览器分析………………………………………………57
6.5 浏览器分析工作的总结………………………………………58
致 谢…………………………………………………………… 60
参考文献表………………………………………………………61
引 言
随着计算机、网络技术的迅猛发展,新型的高科技含量的电子产品层出不穷,遍及家电、生产、军事等各个领域。嵌入式系统因其体积小,速度快而受到重视。在掌上电脑、PDA、手机、导航设备、信息家电领域嵌入式系统被广泛采用,这也是近期产品研发的热点。嵌入式浏览器作为重要的嵌入式系统应用软件,是不可或缺的。但目前,嵌入式浏览器产品的市场被少数国外大公司垄断,众多的小型嵌入式浏览器也尚处于发展期,而国内的自主技术的嵌入式浏览器更屈指可数,刚刚进入实用阶段。迫切需要更多的人来关注嵌入式浏览器技术,开发中国自主知识产权的浏览器产品。
本文阐述了嵌入式浏览器开发的关键技术,并详细说明Netbit Browser的实际开发过程,技术细节。并以网站的方式公布了其源代码,为国内嵌入式浏览器的发展做了有益的尝试。
第一章 嵌入式浏览器设计概述
1.1目前嵌入式浏览器产品的发展现状
1.1.1桌面浏览器简介及其与嵌入式浏览器的区别:
常见的桌面浏览器有微软的Internet Explorer,网景的Netscape,开放源码的Mozilla,以及opera,mosaic,Hotjava,字符模式的lynx等。其中IE,Opera已有嵌入式版本,以上的大多数浏览器均有跨多平台的版本。这些桌面型浏览器功能参差不齐,但大多能实现基本的浏览功能。其中IE与Netscape对HTML页面的显示效果均堪称完美(对于XML,WML等标准的网页浏览,本文不予讨论)。
与完美的浏览效果,功能丰富,支持多种媒体格式和视音频插件等优点形成对立的是,这些浏览器庞大的体积和对机器配置的高要求。这也是桌面浏览器和嵌入式浏览器最大的区别。另外,桌面型浏览器通常是基于通用的操作系统,用于桌面电脑如PC机、MAC机等。而嵌入式浏览器通常基于专用系统。
需要指出的是,我们在网上常看到的一些所谓的优秀浏览器,如Netcaptor,魔装网神,腾讯,飓风,Fantasia,金山WPS office的浏览器等等,均为使用IE内核的浏览器,使用了多页面多线程的方式,降低了系统资源的耗费,方便了浏览,但软件本身没有多少技术可言,可以用Delphi,VB等工具轻易开发出来(如果不要求完善的功能,只需简单到拖一个IE控件过去就行了),这也体现了微软的COM+及ActiveX技术的强大。
1.1.2常见嵌入式浏览器
(1)Internet Explorer for WinCE,是IE的Windows CE版,这也意味着用户为了使用它,必须选用基于WinCE平台的产品,随着微软势力在掌上终端领域的蔓延,WinCE版的IE必将大行其道。
(2)Access Netfront,Access是日本的浏览器大厂,占据了大部份的日本浏览器市场,其产品广泛应用于手持设备、机顶盒、游戏机等产品。其新推出的Netfront Linux版本可以免费下载,网址是:http://www.access.co.jp/product/develop。经试用,发现Netfront浏览效果非常好,对中文的支持和表格的显示效果,甚至超过Netscape 4.6 for Linux。而且支持键盘操作。可以使用箭头键来选择网址进行跳转。但显然为了简化设计,Netfront使用了一定的权宜手段。比如它不支持使用<font>标记来设置字体,也不支持样式表,所有字体的大小是固定的,但一般情况不易发现,不过由于Linux版本不是商业性版本,无法就此推断其他版本的特性。Netfront Linux版大小为1.9M,如再加以简化(比如去掉一些图片按钮)可以做的更小。
(3)Gzilla,现名Dillo,是基于Linux,使用GTK作为GUI平台开发的浏览器,其开发目的也包含嵌入式的应用。是开放源码项目。我们在设计Netbit Browser时主要参考了该浏览器的界面设计。该浏览器的缺点是不支持表格,布局过于简单,不支持中文,浏览效果比较差,优点是网络功能完善,支持cache缓冲,能够支持多种图片格式。网址是:http://www.gzilla.com。
(4)Viewml,使用FLTK作为GUI平台开发的浏览器,主要面向嵌入式的应用。是开放源码项目。使用C++面向对象的设计。因为使用FLTK,所以可以在嵌入式的Micro Window平台运行,该浏览器支持简单的表格,界面还没有做(只有一个主窗口),不支持中文,由于FLTK的BUG比较多,我们在实际编译时经常出错,即使编译通过,也常常是还没运行就core dump了,但曾经由某人编译成功,基本可用,网址是:http://www.gzilla.com。
(5)ZEN,一个并不知名的嵌入式浏览器,但却十分优秀,开放源码项目,不仅支持表格,支持多种图像格式,而且在设计上很有特色,将涉及到GUI平台的部分独立出来,用户可以指定不同的GUI平台运行,内置了对字符,SVGA和GTK的支持,开发这只需按照相应规范编写该软件的涉及GUI的部份,就可以将其移植到其它GUI平台,而无须对整个软件进行修改。缺点是网络功能比较弱,不支持多线程,另外其必须等到所有图片下载完毕才开始布局,若某文件传输失败则会导致死锁,需用户中断。网址是:http://www.nocrew.org/software/zen/。
以上主要介绍了开放源码的嵌入式浏览器,因为其对本项目具有实际的参考价值。
1.1.3 嵌入式浏览器的应用领域
嵌入式浏览器主要应用于手持终端和信息家电,例如掌上电脑、3G手机、网络机顶盒、具有网络功能的其它家电,如可上网的电冰箱等,另外,在军事等领域也有一定的应用需求。
1.2嵌入式浏览器的组成和各部份功能说明
下面简介主要的组成部份,其设计原理后面将进行专门论述。
1.2.1 词法分析
主要是针对HTML进行词法分析,该词法分析器实际是通用的,还可用于XML、WML的词法分析,只需替换元素名称即可。
HTML词法分析是浏览器设计的基础环节之一,也是整个设计过程中重要的前端工作,其数据结构的拟定与接下来的语法分析和布局算法密切相关,词法分析的效率与准确性、容错性也关系到整个浏览器设计的质量。
1.2.2语法分析
在大型的浏览器中,语法分析通常是独立的模块,但在嵌入式浏览器中,语法分析通常是与布局混合在一起的,即一边进行语法分析,一边布局,不设立相应的数据结构来存储语法分析的结果。语法分析对布局的算法有直接的指导意义。
1.2.3布局
本文中的布局应理解为界面输出前的预演和处理位置等信息的算法,而不是具体的画图和界面输出。布局算法的好坏直接关系到界面的输出效果,但布局算法也是要根据GUI所能实现的输出效果来设计的,所以,GUI往往成为系统的瓶颈,如果GUI提供的支持有限,即使有再好的布局算法,也是纸上谈兵,无用武之地。
1.2.4 GUI及软件界面
GUI是指图形用户界面,浏览器无疑是一个图形函数库的大需求者,选择好的GUI环境实属不易,为了能够实现专有的功能,浏览器开发者往往还要对基础的GUI库进行包装、改写,甚至写自己的控件。所有这些,是需要有专业的GUI库开发经验的专职人员来完成。
GUI的功劳第一在于软件的操作界面,如窗口、菜单、工具条、滚动条等。第二在于主浏览窗体中的图形元素的输出(通常以自画控件的方式)。前者通常直接使用GUI库中的已有控件,编程难度很小,后者主要利用基本的点线函数,编程难度比较大。
1.2.5 JavaScript支持
实际上JavaScript的编译器是开放源码的,而且全世界通用,包括IE、Mozilla、Netscape等浏览器都使用相同的JavaScript的编译器,但为何其对JavaScript的支持不尽相同呢,这是因为JavaScript在浏览器里主要是用于操纵界面元素和与浏览器内部命令进行结合。这实际上是程序员努力的结果,而不是JavaScript编译器的功劳。这其中的机制将在后面专门介绍。
1.2.6 IO
主要是指通过HTTP协议或文件系统来读取网页内容,网络部份超出了本论文的讨论范围,不予详述,后面将介绍与网络部份的接口。
以上主要按工作的性质进行分类,介绍了浏览器设计的主要几个部份,但与实际开发工作的人员划分不同,实际工作要考虑人员的实际能力和经验,结合要实现的目标,对各部份的投入也有轻重缓急之分,比如,如果没有词法分析的先行实现,语法分析与布局都是纸上谈兵。GUI平台不确定,布局工作也无法展开。
1.3开发难度分析
我们也可以看到,要设计效果较好的浏览器产品,决不是三五个人、两三条枪就能办到的,参与工作的人员不仅需要有相关经验,还需要有一定的投入,一方面对程序员艰苦的工作给予鼓励,另一方面也可能需要购买一些成熟的开发包,在基础的开发平台、测试平台上也要有一定的投资,总的来说,开发自主技术的浏览器产品是有一定的风险的,这也是国内目前相关产品为数不多的原因。国外大公司在相关领域的科研与实践已很成熟,在大量投入之后,其产品已为广大用户所接受,国内的企业若从零做起,也很难追赶。因而买断技术,加以改进也可以成为快速成长的一条道路。
1.4开发的前期策划
以下的工作均是建立在大量的调查基础上的。是浏览器开发前期准备工作所解决的问题。
1.4.1 平台的选取
目前的商业化嵌入式操作系统功能完善,但使用费用高昂,使用Linux内核的嵌入式操作系统不仅功能强大,便于开发移植,而且费用低廉,基于Linux的嵌入式系统已日渐成熟,也有相应的窗口系统可以使用,我们使用PC上的Linux来进行浏览器开发,是再好不过的了,软件从PC移植到嵌入式设备只需重新编译一下就可以了(前提是使用的函数库、开发包同时具有PC和嵌入式的版本)。
1.4.2 GUI的选取
GUI的选取是颇费脑筋的问题,一方面要考虑嵌入式系统是否有对应的版本,一方面要考虑该GUI的功能是否足够实用。
目前常见的基于Linux的GUI开发包主要有GTK、FLTK、QT、KDE等,其中FLTK有Micro Window的版本,是比较好的选择,但使用FLTK开发的软件还比较少,对于初学者进入的难度更大,而且目前BUG较多,而GTK比较成熟,使用GTK的软件比比皆是,资料也很丰富,我们的参考对象Gzilla也使用GTK,也就是说如果使用GTK,将有很好的原型进行参考,这使得GTK对于目前毫无GUI开发经验的浏览器开发组而言,充满了巨大的诱惑。考虑到GUI是可以成为独立模块的,如浏览器ZEN的设计,我们决定使用GTK,待时机成熟可换用其它平台,也并非难事。
在前期,我们也对FLTK加以了研究,还尝试了以FLTK为基础构建GUI中间层的办法,但由于工作量巨大,初步估算需2万行程序,而不得不暂缓该计划。建立GUI中间层在理论上是可行的,这样,在必要时可以釜底抽薪,替换掉基础的GUI平台,应用软件完全不需修改,但中间层与基础层的接口要重写,其工作量也很大,未必是核算的买卖。
1.4.3 确定要实现的基本功能
鉴于对浏览器开发难度的充分考虑,以及现有人员的水平,拟定实现以下功能,以及需要考虑但暂不予实现的功能。
需要实现的包括:
(1) 界面:包括窗口,菜单,输入框,工具条,滚动条等的支持。
(2) 词法分析:必须实现实用的HTML词法分析,支持HTML4.0全部元素。
(3) 实现简单网页的布局:实现对简单网页的查看。
(4) 支持基本IO,支持采用线程的网络传输。
需要考虑的功能:
(1) JavaScript支持
(2) 汉字支持
(3) 图片格式支持
(4) 表单支持
(5) 页面元素的消息响应
1.4.4 人员分工
由于情况的变动,造成了人员比较紧张,在前期准备工作中,人力充沛,使得收集的资料比较完备,打下了较好的基础。在后期简化了目标,虽然人员减少,但也能够实现主要的工作。考虑到网络是比较独立的部份,把它分出去由专人负责。
第二章 HTML词法分析器的设计及其应用
HTML词法分析是浏览器设计的基础环节之一,也是整个设计过程中重要的前端工作,其数据结构的拟定与接下来的语法分析和布局算法密切相关,词法分析的效率与准确性、容错性也关系到整个浏览器设计的质量。
下面将介绍一个HTML词法分析器——Bit Token的设计思路。
Bit Token是Netbit Browser的HTML词法分析器,使用标准C编程,Netbit Browser是基于Linux/Gtk的浏览器,开放源码项目,网址是http://netbit_browser.myetang.com。
2.1 Bit Token的组成及其功能
Bit Token作为Netbit Browser的词法分析部份,负责对接收的HTML代码进行词法分析,主要的目的是提取网页中元素的名称及其属性,并以恰当的形式(即按一定的数据结构)加以保存,也就是完成了将数据流离散化、结构化的过程。
主要由以下几个部分组成:
1、初始化:完成对数据结构的初始化,主要是分配内存,变量赋初值。
2、主体的数据流分析:逐字符的进行判断,确定数据的归属类型。
3、元素的分析:提取元素的名称、属性和值域。
4、释放:主要是对内存的释放。
2.2 数据结构
typedef struct BitTokenContext
{char * strBuffer; //当前正在处理的HTML代码
int bufferLength;
int curPosition;
char * global_strBuffer; //全局HTML代码
int global_bufferLength;
int global_curPosition;
BitTokenList *tokenList; //元素节点链表
BitTokenList *tokenList_tail;
BitPTagList pTagList; //元素名称表,指向静态数据
}BitTokenContext,*BitPTokenContext;
BitTokenContext是用于存储当前待分析网页全局属性的数据结构,其中TokenList是核心的元素节点链表。词法分析的目的就是生成这样一个链表。下面给出该链表的数据结构,是很简单的双向链表。
typedef struct TokenList
{ BitToken *token; //元素节点
struct TokenList *priou;
struct TokenList *next;
}BitTokenList,*BitPTokenList;
以下是元素节点的数据结构:
typedef struct BitToken
{int type; //节点类型,如定义的HTML_BODY,HTML_TXT等。
char *pData; //如果是HTML_TXT型元素,则为其内容,否则为空
BOOL end; //是否是结束元素,如</body>
BitTokenAttrList *attrList; //元素属性链表,因为可能有多个属性,所以使用链表存储
BitTokenAttrList *attrList_tail;
}BitToken,*BitPToken;
请注意,以上出现tail标记的指针变量,如BitTokenList * tokenList_tail等,其作用是用于保存链表结尾节点指针,便于在释放内存时,直接找到链尾,提高了算法的效率。
2.3 算法
2.3.1 基本算法:
首先介绍基本的算法:
(1) 从存储网页的字符串中,顺序读入一个字符
(2) 如果遇到 < ,认为遇到TAG(元素),处理该元素,使用函数Token_ConsumTag(),处理完毕后,指针移到该元素尾。
(3) 如果遇到回车、空格,则跳过。
(4) 如果遇到 > ,则跳过(不应该出现此情况,为了容错)。
(5) 如果非以上情况,则认为遇到文字,处理这段文字,使用函数Token_Consum_PlainText()。处理完毕,指针指向下一个元素首。
(6) 循环以上操作,直到该网页分析完毕。
由此看来,主算法十分简单而清晰,主要是Token_ConsumTag()和Token_Consum_PlainText()这两个函数起关键作用,由于其中涉及到许多细节问题,此处不予详述。
2.3.2 算法效率与改进:
采用以上的基本算法,是可用的,但当网页比较大的时候,比如600K,该算法的效率成倍下降,这主要是由于要处理的字符串太大,在内存中完成查找、替换、复制、移动等操作,响应时间明显下降。对此的改进办法就是分段进行词法分析,不仅极大的提高了效率(在某些情况下约提高30倍),也有利于浏览器整体设计,因为当网页较大时,若等待全部内容传输完毕,再一次性完成词法分析和布局,用户会感到等待时间过长,一般现在成熟的浏览器都采用边传输,边分析,边显示。
分段进行词法分析的算法复杂度明显增加,比如,当每段定为1024字节,在第1024字节处,可能正好将一个完整元素截断,按常规分析方法会造成错误。解决的办法是,采用回溯,确认要分析的部份至少包含1个完整元素。
具体做法是:判断1024字节处是否为元素结束字符 ‘>’,如果不是,则判断前一个字节,直到找到元素结束字符为止,这样可保证至少包含一个元素。
采用分段进行词法分析,实际每次分析的代码会不足1024字节,余下的部份汇入到下一段的分析过程即可,直到所有内容被分析完毕。
2.4词法分析的结果
下面是一段很简单的HTML代码。
<html>
<img src=“go.gif” width=200 height=100>
<a HREF="http://www.263.net">首都在线</a>
</html>
分析后,数据存储结构如下
:
<img>
<a>
text
</a>
src
go.gif
width
200
height
100
href
http://www.263.net
data
首都在线
可以看到,词法分析的结果是一个元素节点链表,每个节点的属性也形成了一个链表,元素节点是有先后顺序的,元素属性的先后顺序是无所谓的。
词法分析将网页的文本数据流以清晰的结构表现出来,这样,在后面的应用中就可以很容易的遍历各节点,并轻松地获得各元素节点的属性。
2.5 HTML词法分析的应用
2.5.1 应用举例:
HTML词法分析程序通常应用于浏览器设计、网页制作软件设计等领域,本人以一个使用VC开发的软件“HTML智能分析”来举例说明,下载网址:
http://netbit_browser.myetang.com/introduce.html。
“HTML智能分析”同样使用Bit Token词法分析器,“HTML智能分析”是一个网页信息提取、处理软件。
具有以下主要功能:
1、智能提取网页中的文字信息,智能排版,并可在进行编辑后保存。
2、统计网页的有关信息。
3、根据用户设置的版式,将分析和编辑的结果,自动生成新的网页。
用户可使用该软件来将HTML转为TXT格式,其对HTML中文字内容的提取准确、快速、不含冗余信息,版式工整清晰,保持本来面貌。
其主要设计思路是,在Bit Token词法分析器的基础上,结合浏览器布局的基本算法,对影响到TXT版面效果的元素进行处理。
比如<PRE>标记,代表所包含的内容浏览器应不予分析,按TXT格式输出,而如表格<TR>等元素则意味着需要换行。而在HTML中,在无<PRE>这种特殊情况时,回车都是忽略不记的。这就造成了矛盾。使用常规的简单算法进行HTML到TXT的转换无法解决这些问题。造成转换后的版式“失真“。而“HTML智能分析”却能很好的解决。
由于“HTML智能分析”使用了底层的词法分析技术,还可以很容易的过滤掉<SCRIPT>与<STYLE>(样式表)。并可以对网页中的元素进行统计和语法校验。
以下是该程序的片断:
pTtokenList=global_cx->tokenList; //取首节点
while(pTtokenList!=NULL) //循环直至处理完所有节点
{
switch(pTtokenList->token->type)
{//根据节点类型,做不同的处理
case HTML_TITLE: ……
case HTML_TEXT: ……
default: ……
} //switch
pTtokenList=pTtokenList->next; //取下一个节点
} //while
这段程序实际上就是一个简单的语法分析和布局的过程。
2.5.2 Bit Token在应用中存在的问题及修改意见
由于HTML的标记多是成对出现的,并且存在<SCRIPT>这样的特殊元素,其内容为Javascript程序,函数的字符串参数等可能包含其它的元素标记。例如语句:Alert(“<font> is a tag”);
因此,在词法分析时要对<SCRIPT>标记进行特殊处理,遇到<SCRIPT>就应逐字符读入后面的内容,直到遇到下一个</SCRIPT>标记。目前的Bit Token由于开发时间所限,未对其加以特殊处理,存在一些问题,但由于浏览器对Javascript的支持是较复杂的工作,目前的Netbit Browser尚不予实现,因而没有导致明显问题,而“HTML智能分析”这个软件只是需要对Javascript进行删除操作,也不会造成影响。尽管如此,对<SCRIPT>的特殊处理还是有待完善,尽管这同时也会带来一些问题,需要进行大量的测试,来保证新加入代码的稳定性。
正如前面所述,HTML词法分析是浏览器设计的基础环节之一,但并非最重要和最具难度的环节,若想开发出效果较好的浏览器产品,还要在布局和GUI设计上多下功夫。
第三章 浏览器JavaScript支持的实现
本部份主要针对Mozilla和Netscape浏览器源代码的JavaScript部份进行了分析,阐述了浏览器Javascript实现的机制。
3.1基本的JavaScript 开发环境
JavaScript Reference与JavaScript API:
JavaScript Reference是Mozilla所使用JavaScript开发环境,是使用ANSI C的独立的开发包,据Mozilla文档介绍,该开发包涉及到超过160家公司的版权。而且被广泛使用,实际已成为了进行JavaScript应用开发的标准平台。
JavaScript Reference可以用于建立包含JavaScript runtime的Library或 DLL。既可以编译成小的 "shell" 程序(像早期的BASIC),又连接Library后生成交互式的JavaScript解释器,也可以用来解释.js 文件。由于使用了ANSI C编程,可以用VC、GCC等编译器在不同平台下编译。
生成的"shell" 程序,对比浏览器对JavaScript的支持,相同之处是使用相同的包含JavaScript runtime的Library 或 DLL,我们把这部份相同的Library或 DLL称为JavaScript API,我们实际开发JavaScript应用,也是在JavaScript API基础上工作,而不用过多考虑其内部的实现。关于JavaScript API,参见JavaScript API详解。JavaScript API实际就是Javscript解释器的对外接口函数库。
3.2 JavaScript Engine
JavaScript Engine是浏览器开发者为了利用JavaScript API来实现实际应用而设立的中间层,用于初始化JavaScript环境,提供对JavaScript解释、执行的接口。浏览器主体程序的设计者可以通过JavaScript Engine,方便的实现各种应用,毕竟JavaScript API太基础了,直接使用不太方便。
下面介绍JavaScript Engine的主要功能和实现方法。这也包含了利用JavaScript API进行应用的基本思路。
(1) 初始化:
内存分配:rt=JS_Init(10000L);
初始化cx:cx = JS_NewContext(rt, STACK_CHUNK_SIZE);
初始化globalObj:globalObj = JS_NewObject(cx, &globalClass, 0, 0);
定义标准类:JS_InitStandardClasses(cx, globalObj);
定义系统函数:JS_DefineFunctions(cx, globalObj, g_functions);
定义报错函数:JS_SetErrorReporter(cx,JS_ErrorReporter);
注册其它类:
RegisterClassPoint (cx,globalObj);
RegisterClassSize (cx,globalObj);
RegisterClassRect (cx,globalObj);
RegisterClassPolygon (cx,globalObj);
RegisterClassColorKey (cx,globalObj);
RegisterClassTDTimer (cx,globalObj);
初始化定时器:TDTimerListInit();
(2) 提供对JavaScript解释、执行的接口函数:
TD_EvaluateScript(JSContext *cx,JSObject *obj, const char *bytes, uintN length,const char *filename, uintN lineno,jsval *rval)
3.3 JavaScript与浏览器接合
基本概念:JavaScript操作HTML元素的常见方式
例:
<html><head>
<script><!--
function ChangeImage(index)
{image0.src="a"+index+".gif";}
--></script>
</head>
<a onmouseover="ChangeImage(0);">军人</a><br>
<a onmouseover="ChangeImage(1);">眼睛</a><br>
<img id="image0" src="a0.gif"></img>
</html>
当鼠标移到文字上时,触发事件mouseover,调用ChangeImage()函数,使得图像源(SRC)发生变化,重新调入新图片。
由此产生两个关键问题:
1. javascript如何获取HTML元素的名称和属性。
2. javascript如何改变HTML元素的属性,并操作WIDGET重画。
下面分别阐述这两个问题:
首先介绍涉及到的浏览器流程:
PARSE
Tokenize
BuildModel
BuildPres
ProcessElement
WidgetPaint
问题1解决:HTML元素作为Javascript对象进行注册。
注册过程在BuildModel中进行。BuildModel的首要任务是将Token后的结点按包含关系展成一棵树。其次就是要将某些结点注册为JavaScript对象。
注册的过程是:
定义新对象:JSObject *proto;
初始化该对象:
TD_JSXMLElementClassInit(JS_GetGlobalContext(),
(void **)&proto))
使用JS_DefineObject或JS_NewObject定义对象属性:
根据是否定义了该元素的名称区别对待:
if(TD_XMLContentIsNamedItem(aElement,&aName))
{ parent = js_GetGlobalObject();
*aReturn=JS_DefineObject(JS_GetGlobalContext(),js_GetGlobalObject(),aName->mStr,&ElementClass,proto,JSPROP_ENUMERATE);
}
else
{ parent=aElement->parent->mScriptObject;
*aReturn = JS_NewObject(JS_GetGlobalContext(), &ElementClass, proto, parent);
}
将对象加入:
JS_SetPrivate(JS_GetGlobalContext(), (JSObject *)*aReturn, aElement);这样,在编译时,HTML元素的标识就能被Javascript编译器识别,否则会报错变量未定义。
问题2解决:利用注册给对象的函数实现操作符的功能化。
具体可理解为:当image0.src=”1.gif”被执行时,相当于为对象设置或改变属性,此时SetElementProperty函数被调用(该函数在注册该对象时由JSXMLElementClassInit捆绑给该对象,其内容由用户自己定义),SetElementProperty通过函数指针调用函数TD_JSXMLSetAtrByID,改变结点树上结点属性,并重新生成该节点对应的widget,重画界面。
问题3:如何建立Javascript对象与结点树上结点的对应?
解决: Javascript对象与结点树是同时生成的,它们的共同性质是结点具有相同属性,Javascript对象根据ID属性查找树,找到要操作的对应结点。
3.4 浏览器消息响应
在主消息循环中调用TDWidgetProcessMsg,处理与widget有关消息。
首先:取得当前焦点所在的widget
pWidget=TDWidgetGetAtPoint(pThis->baseDoc.base.mWidget,pt,&index);
处理该widget对该消息的响应。
最后一般为调用JavaScript执行,实现实际响应。
TDVOID TDWidgetDoAction(TDPWidgetAction pAnchor)
{
jsval jval;
if(pAnchor)
TD_EvaluateScript(JS_GetGlobalContext(),js_GetGlobalObject(),pAnchor->mAction.mStr,pAnchor->mAction.mLength,TDNULL,0,&jval);
}
其中pAnchor->mAction.mStr即为界面对象(widget)对应的JavaScript源码,解释执行的结果就是调用为该对象注册的函数来重画该widget,从而实现动态效果。
第四章 Linux程序开发技术及 GTK图形程序开发
4.1 Linux下的程序开发环境
4.1.1基本知识
(1) 标准 (ANSI C, POSIX, SVID, XPG, ...)
ANSI C:这一标准是 ANSI(美国国家标准局)于 1989 年制定的 C 语言标准。 后来被 ISO(国际标准化组织)接受为标准,因此也称为 ISO C。
POSIX:该标准最初由 IEEE 开发的标准族,部分已经被 ISO 接受为国际标准。
SVID:System V 的接口描述。System V 接口描述(SVID)是描述 AT&T Unix System V 操作 系统的文档,是对 POSIX 标准的扩展超集。
XPG:X/Open 可移植性指南。X/Open 可移植性指南(由 X/Open Company, Ltd.出版), 是比 POSIX 更为一般的标准。
(2) 函数库和系统调用
glibc:众所周知,C 语言并没有为常见的操作,例如输入/输出、内存管理,字符串操作等提供内置的支持。相反,这些功能一般由标准的“函数库”来提供。GNU 的 C 函数库,即 glibc,是 Linux 上最重要的函数库,它定义了 ISO C 标准指定的所有的库函数,以及由 POSIX 或其他 UNIX 操作系统变种指定的附加特色,还包括有与 GNU 系统相关的扩展。目前,流行的 Linux 系统使用 glibc 2.0 以上的版本。glibc 基于如下标准:ISO C: C 编程语言的国际标准,即 ANSI C,POSIX,Berkeley Unix,SVID,XPG。
其他重要函数库:除 glibc 之外,流行的 Linux 发行版中还包含有一些其他的函数库,这些函数库具有重要地位,例如:GNU Libtool,CrackLib,LibGTop。图形文件操作函数库包括: libungif、libtiff、libpng、Imlib, libjpeg 等,可分别用来操作 GIF、TIFF、PNG、JPEG 以及其他一些格式图形文件。
(3) 系统调用
系统调用是操作系统提供给外部程序的接口。在 C 语言中,操作系统的系统调用通常通过函数调用的形式完成,在 Linux 系统中,系统调用函数定义在 glibc 中。
谈到系统调用时,需要注意如下几点:系统调用函数通常在成功时返回 0 值,不成功时返回非零值。errno 中包含有错误代码。系统调用是一个非常耗时 的过程。
(4) C 语言编程风格
良好的编程风格可以在许多方面帮助开发人员,可以增加代码的可读性,并帮助你理清头绪。编程风格最能体现一个程序员的综合素质。
在 Linux 中,我们经常看到的是定义非常简单的函数接口和变量名称。C 语言最初来自 UNIX 操作系统,与 UNIX 的设计原则一样,C 语言被广泛认可和使用的一个重要原因是它的灵活性以及简洁性。在利用 C 语言编写程序时,应当符合其简洁的设计原则,而不应当使用非常复杂的变量命名方法。Linus 为 Linux 内核定义的 C 语言编码风格要点如下:
缩进时,使用长度为 8 个字符宽的 Tab 键。如果程序的缩进超过 3 级,则应考虑重新设计程序。
大括号的位置。除函数的定义体外,应当将左大括号放在行尾,而将右大括号放在行首。函数的定义体应将左右大括号放在行首。如下所示:
int function(int x, int y)
{
if (x == y) {
...
}
else {
...
}
return 0;
}
应采用简洁的命名方法。对变量名,不赞成使用大小写混写的形式,但鼓励使用描述性的名称;尽可能不使用全局变量;不采用匈牙利命名法表示变量的类型;采用短小精悍的名称表示局部变量;保持函数短小,从而避免使用过多的局部变量。保持函数短小精悍。不应过分强调注释的作用,应尽量采用好的编码风格而不是添加过多的注释。
(5) 库和头文件的保存位置
函数库:
/lib:系统必备共享库
/usr/lib:标准共享库和静态库
/usr/i486-linux-libc5/lib:libc5 兼容性函数库
/usr/X11R6/lib:X11R6 的函数库
/usr/local/lib:本地函数库
头文件:
/usr/include:系统头文件
/usr/local/include:本地头文件
4.1.2 Linux 上的编译器和调试器
(1) Linux 上的 C/C++ 编译器和调试器
运行 gcc/egcs:Linux 中最重要的软件开发工具是 GCC。GCC 是 GNU 的 C 和 C++ 编译器。实际上,GCC 能够编译三种语言:C、C++ 和 Object C(C 语言的一种面向对象扩展)。利用 gcc 命令可同时编译并连接 C 和 C++ 源程序。
例如利用如下的命令可编译生成可执行文件,并执行程序:
$ gcc -o factorial main.c factorial.c
$ ./factorial 5
GCC 可同时用来编译 C 程序和 C++ 程序。一般来说,C 编译器通过源文件的后缀名来判断是 C 程序还是 C++ 程序。在 Linux 中,C 源文件的后缀名为 .c,而 C++ 源文件的后缀名为 .C 或 .cpp。
但是,gcc 命令只能编译 C++ 源文件,而不能自动和 C++ 程序使用的库连接。因此,通常使用 g++ 命令来完成 C++ 程序的编译和连接,该程序会自动调用 gcc 实现编译。
例如可以如下调用 g++ 命令编译、连接并生成可执行文件:
$ g++ -o hello hello.C
$ ./hello
(2) gcc/egcs 的主要选项
-ansi 只支持 ANSI 标准的 C 语法。这一选项将禁止 GNU C 的某些特色,
-c 只编译并生成目标文件。
-DMACRO 以字符串“1”定义 MACRO 宏。
-DMACRO=DEFN 以字符串“DEFN”定义 MACRO 宏。
-E 只运行 C 预编译器。
-g 生成调试信息。GNU 调试器可利用该信息。
-IDIRECTORY 指定额外的头文件搜索路径DIRECTORY。
-LDIRECTORY 指定额外的函数库搜索路径DIRECTORY。
-lLIBRARY 连接时搜索指定的函数库LIBRARY。
-m486 针对 486 进行代码优化。
-o FILE 生成指定的输出文件。用在生成可执行文件时。
-O0 不进行优化处理。
-O 或 -O1 优化生成代码。
-O2 进一步优化。
-O3 比 -O2 更进一步优化,包括 inline 函数。
-shared 生成共享目标文件。通常用在建立共享库时。
-static 禁止使用共享连接。
-UMACRO 取消对 MACRO 宏的定义。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。
(3)gdb
GNU 的调试器称为 gdb,该程序是一个交互式工具,工作在字符模式。在 X Window 系统中,有一个 gdb 的前端图形工具,称为 xxgdb。gdb 是功能强大的调试程序,可完成如下的调试:设置断点;监视程序变量的值;程序的单步执行;修改变量的值。
在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量:CFLAGS = -g,运行 gdb 调试程序时通常使用如下的命令:gdb progname
(4) 创建和使用静态库
创建一个静态库是相当简单的。通常使用 ar 程序把一些目标文件(.o)组合在一起,成为一个单独的库,然后运行 ranlib,以给库加入一些索引信息。
(5) 创建和使用共享库
特殊的编译和连接选项-D_REENTRANT使得预处理器符号 _REENTRANT 被定义,这个符号激活一些宏特性。-fPIC选项产生位置独立的代码。由于库是在运行的时候被调入,因此这个选项是必需的,-shared选项告诉编译器产生共享库代码。
作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/1919/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!