【正文】
ing_area)。輸出到PIXMAP并顯示 HTML文件的顯示模塊這部份是整個(gè)瀏覽器最重要的部份之一,綜合了語(yǔ)法分析與HTML的布局、輸出,其算法的好壞直接關(guān)系到網(wǎng)頁(yè)的顯示效果。主要流程: while(pTtokenList!=NULL) {………… switch(pTtokenListtokentype) { case HTML_TITLE: ………… break。 case HTML_TEXT: ………… break。 ………… ………… default: ……… break。 } //switch pTtokenList=pTtokenListnext。 } //while可以看到,這部份與語(yǔ)詞分析結(jié)合的十分緊密,利用詞法分析的結(jié)果,遍歷各元素節(jié)點(diǎn),取出其元素屬性,根據(jù)一定的布局算法來(lái)進(jìn)行布局。例如:當(dāng)遇到title元素時(shí),就使用gtk函數(shù)來(lái)設(shè)定窗口標(biāo)題為指定標(biāo)題gtk_window_set_title(GTK_WINDOW(bwmain_window),pTtokenListtokenpData)。其中pTtokenListtokenpData即為詞法分析分析出的標(biāo)題內(nèi)容。由于程序結(jié)構(gòu)十分簡(jiǎn)單清晰,大部份元素的處理都簡(jiǎn)單易懂,參考源程序即可,下面主要針對(duì)font和相關(guān)標(biāo)記對(duì)字體的設(shè)置闡述其算法。由于font標(biāo)記允許嵌套,所以使用了棧來(lái)對(duì)font元素進(jìn)行管理,例如以下的HTML代碼:font size=4 color=0000FFThis program is not bfree software/b。 you can redistribute it and/or modify it under the terms of the font size=5 color=FF0000GNU General Public License /fontas published by the Free Software Foundation。 either version 2 of the License, or (at your option) any later version./font顯示的效果應(yīng)為GNU General Public License的字號(hào)為5,顏色為FF0000,即紅色;free software應(yīng)為粗體,受首尾兩個(gè)呼應(yīng)的font標(biāo)記約束,其它字字號(hào)均為4,顏色為0000FF,由于free software只被b/b這一對(duì)加粗符號(hào)約束,所以其顏色應(yīng)受首尾的font標(biāo)記的約束,即應(yīng)為0000FF。這種嵌套的約束方式帶來(lái)了HTML元素管理的混亂,也容易產(chǎn)生冗余的HTML代碼,但既然標(biāo)準(zhǔn)是這么定的,也只能想辦法加以解決,固然現(xiàn)在隨著樣式表的廣泛采用,font已面臨壽終正寢,但仍然大量存在,特別在對(duì)字體的顏色的設(shè)置,使用font標(biāo)記很方便。棧式管理的主要算法詳解:void html_open_font(GtkWidget *widget,char * style_str,char *color_str,char *size_str,int html_element,int insert_to_list);該函數(shù)用于指定當(dāng)前的字體屬性,其參數(shù)包括style,color,size,以及改變字體屬性的元素的名稱,int insert_to_list用于標(biāo)記此字體屬性是否入棧,通常是入棧的。這樣,在出現(xiàn)font或相關(guān)元素的首標(biāo)記時(shí),我們將詞法分析的結(jié)果提取出來(lái),即將其元素屬性提取出來(lái),作為參數(shù)傳遞給html_open_font函數(shù),該函數(shù)將這些屬性進(jìn)行組合,設(shè)置成為當(dāng)前字體屬性,并入棧保存;在出現(xiàn)font或相關(guān)元素的尾標(biāo)記時(shí),出于保險(xiǎn)(因?yàn)榇嬖诮诲e(cuò)包含關(guān)系的元素),首先檢驗(yàn)棧頂元素與正在處理的元素尾標(biāo)記是否匹配(名稱相同),如相同則出棧,并將棧內(nèi)下一字體屬性設(shè)為系統(tǒng)的當(dāng)前字體屬性。出棧函數(shù)為void html_close_font(GtkWidget *widget,int html_element)需要注意的是由于并不是所有的font元素都指定所有的屬性,可能只指定其中的一個(gè)或一部份屬性,因此在入棧時(shí)必須做這樣的處理,即首先獲取當(dāng)前的字體屬性,根據(jù)哪些屬性發(fā)生了變化來(lái)組合新的字體屬性,然后入棧。所使用的棧的結(jié)構(gòu)很簡(jiǎn)單,如下。typedef struct _font_list{int html_element。char color_str[15]。char size_str[15]。char style_str[15]。}font_list。此為font_list的類(lèi)型定義,描述了字體屬性的結(jié)構(gòu)font_list font_opening[50]。 定義一個(gè)數(shù)組作為棧的存儲(chǔ)形式int current_font=0。 定義一個(gè)整型變量,作為棧頂指針如此,一個(gè)簡(jiǎn)單的數(shù)組就發(fā)揮了巨大的作用,配以一點(diǎn)點(diǎn)算法,就帶來(lái)了豐富多彩的界面效果。 Netbit實(shí)際應(yīng)用效果及比較下圖為Netbit browser運(yùn)行時(shí)的界面,所打開(kāi)的頁(yè)面源代碼如下:htmlbodyh1font color=FF00FFbNetbit Browser Version Demo/b/font/h1hrh4License/h4pfont size=4 color=0000FFThis program is not bfree software/b。 you can redistribute it and/or modify it under the terms of the font size=5 color=FF0000GNU General Public License /fontas published by the Free Software Foundation。 either version 2 of the License, or (at your option) any later version./fonthrh3Design based on GTK, by sogo and ce!/h3/body/html以下為主菜單以下為工具條輸入網(wǎng)頁(yè)的URL,即可進(jìn)行訪問(wèn)。以下為打開(kāi)文件對(duì)話框以下為查看HTML源碼對(duì)話框下面對(duì)比Netbit Browser,看看其它瀏覽器查看此網(wǎng)頁(yè)的效果。以下為KDE瀏覽該網(wǎng)頁(yè)的效果以下為GZILLA瀏覽該網(wǎng)頁(yè)的效果,GZILLA對(duì)字體顏色的處理比較差,只有黑色的字體。對(duì)字號(hào)的支持也不好。以下為Netscape顯示該網(wǎng)頁(yè)的效果,Netscape默認(rèn)背景色是灰色。IE查看該網(wǎng)頁(yè)的效果,字體不同是由于IE設(shè)置的默認(rèn)字體不同??梢钥吹?,在對(duì)簡(jiǎn)單英文網(wǎng)頁(yè)的支持效果上看,Netbit Browser,已接近于成熟瀏覽器的水平,甚至優(yōu)于一些小型的嵌入式瀏覽器如GZILLA,Netfront,但在復(fù)雜頁(yè)面的顯示上還有較大的差距。可以得出的結(jié)論是,Netbit Browser Demo 版已經(jīng)具有了一定的實(shí)用價(jià)值,但要對(duì)其進(jìn)行完善,工作量還很巨大。對(duì)比Netscape,IE的漫長(zhǎng)的開(kāi)發(fā)歷史和巨大的資金投入,Netbit Browser的未來(lái)依然生死未卜。 Netbit Browser的缺點(diǎn)分析及改進(jìn)辦法基礎(chǔ)的GUI設(shè)計(jì)上存在缺陷Netbit Browser目前的頁(yè)面輸出實(shí)際上還采用了簡(jiǎn)單的畫(huà)圖機(jī)制,無(wú)法在主窗體內(nèi)放置如按鈕、編輯框、單選框等控件,也無(wú)法處理頁(yè)面元素的消息響應(yīng),(Netbit Browser ),而使用GTK作為開(kāi)發(fā)平臺(tái)是完全可以實(shí)現(xiàn)這些要求的,GZILLA就是最好的實(shí)例,它通過(guò)對(duì)現(xiàn)有控件的組合,開(kāi)發(fā)了自己的文檔視圖控件,實(shí)現(xiàn)了上述功能。但之所以目前沒(méi)有采用先進(jìn)的文檔視圖控件,是因?yàn)橐獙?shí)現(xiàn)這樣的有較強(qiáng)實(shí)用性的自畫(huà)文檔視圖控件,是需要很大的工作量的,僅GZILLA為實(shí)現(xiàn)其核心的DW文檔視圖控件,就動(dòng)用了超過(guò)7000行的代碼,比Netbit Browser目前的總代碼量還大。而Netscape由于考慮到支持多個(gè)GUI平臺(tái),還需要一個(gè)抽象的中間層文檔視圖控件,這個(gè)中間層也在萬(wàn)行以上。改進(jìn)措施固然,能容納百川,一觸即發(fā)的文檔視圖控件的開(kāi)發(fā)是很繁重的工作,但原理卻并不復(fù)雜。下面加以闡述。大多數(shù)的GUI平臺(tái)都提供了方便用戶進(jìn)行控件組合的機(jī)制,例如有的控件能包含其它的控件,通常稱之為container(容器),以GTK為例說(shuō)明其原理。GTK控件是以流行的控件組件的觀念來(lái)設(shè)計(jì)的。 不過(guò), 依然是以C來(lái)寫(xiě)的。 比起用C++來(lái)說(shuō), 這可以大大改善可移植性及穩(wěn)定性。 但同時(shí), 這也意味著widget 作者需要小心許多實(shí)際操作上的問(wèn)題。 所有同一類(lèi)別的控件的一般聲明 (例如所有的按鈕控件)是放在 class structure。 只有一個(gè)這樣的結(jié)構(gòu)。 在這個(gè)結(jié)構(gòu)中儲(chǔ)存類(lèi)別信號(hào)的聲明。 要支撐這樣的繼承, 第一欄的資料結(jié)構(gòu)必須是其父類(lèi)別的資料結(jié)構(gòu)。 例如GtkButton的類(lèi)別的聲明看起來(lái)像這樣: struct _GtkButtonClass{ GtkContainerClass parent_class。 void (* pressed) (GtkButton *button)。 void (* released) (GtkButton *button)。 void (* clicked) (GtkButton *button)。 void (* enter) (GtkButton *button)。 void (* leave) (GtkButton *button)。}。當(dāng)一個(gè)按鈕被看成是個(gè)container(容器)時(shí)(例如, 當(dāng)它被縮放時(shí)), 其類(lèi)別結(jié)構(gòu)可被傳到GtkContainerClass, 而其相關(guān)的欄位被用來(lái)處理信號(hào)。具體而言,比如我們使用一個(gè)基礎(chǔ)的layout控件來(lái)作為我們自畫(huà)的文檔視圖控件的基礎(chǔ)控件,layout = gtk_layout_new(NULL, NULL)。接下來(lái)我們就可以使用gtk_layout_put函數(shù)將其它的允許被包含的控件放進(jìn)去,就是這么簡(jiǎn)單,那難度在哪呢?其實(shí),對(duì)于網(wǎng)頁(yè)顯示而言,能放進(jìn)去多少個(gè)按鈕、編輯框、單選框并不是最主要的,這很容易實(shí)現(xiàn),只要采用了類(lèi)似layout這樣的基礎(chǔ)控件,我們?cè)瓌t上可以組合出來(lái)很多種效果。我們迫切關(guān)心的是那些需要用畫(huà)圖方法來(lái)實(shí)現(xiàn)的頁(yè)面元素,如文字、圖片、表格、直線是如何產(chǎn)生的。下面加以闡述。實(shí)際上,無(wú)論在什么情況下,我們要作畫(huà)都需要合適的畫(huà)布,要在可以作畫(huà)的控件上才可以施展拳腳,drawing_area正是這樣的控件,如此,我們只要將畫(huà)畫(huà)在drawing_area上,然后再使用gtk_layout_put函數(shù)將drawing_area放置到layout控件上,不就萬(wàn)事大吉了?不錯(cuò),但只對(duì)了一半,原來(lái)drawing_area本身并沒(méi)有實(shí)現(xiàn)自我重畫(huà)的機(jī)制,當(dāng)最小化窗口或打開(kāi)對(duì)話框時(shí),原有的界面就被破壞,只有進(jìn)行重畫(huà)才能恢復(fù)原貌,重畫(huà)又是怎樣實(shí)現(xiàn)的呢?原來(lái),我們?cè)趯rawing_area放置于layout之前,是做了手腳的,使用以下函數(shù)gtk_object_set_data(GTK_OBJECT(drawing_area), layout, partp)。來(lái)將畫(huà)在drawing_area上的信息對(duì)應(yīng)的數(shù)據(jù)封裝給了drawing_area控件。同時(shí)使用函數(shù)gtk_signal_connect(GTK_OBJECT(drawing_area), expose_event, (GtkSignalFunc)render_line_event, NULL)。來(lái)將expose_event這個(gè)重畫(huà)消息,捆綁給了drawing_area控件。render_line_event即是用于重畫(huà)的函數(shù),到了需要重畫(huà)的時(shí)候,該函數(shù)取出封裝給drawing_area的數(shù)據(jù)進(jìn)行重畫(huà)。如此這般費(fèi)神,終于可以讓線條、文字、表格、圖片得見(jiàn)天日,完美的展現(xiàn)在眾人面前(當(dāng)然,所有的畫(huà)與重畫(huà)的函數(shù)都要自己寫(xiě)好了才行)。不要高興太早,超級(jí)鏈接都不可點(diǎn)擊,GIF動(dòng)畫(huà)也不會(huì)動(dòng),界面還是死的,原來(lái)忘了畫(huà)龍點(diǎn)睛,怎么辦?加消息。加消息的步驟通常如下,以文字的超級(jí)鏈接為例。首先新建一個(gè)消息盒子,event_box = gtk_event_box_new()。如果著急的話先把盒子放到layout上,當(dāng)然用gtk_layout_put函數(shù)。若是最后再放上去,效果是同樣的。將drawing_area裝到盒子里。gtk_container_add(GTK_CONTAINER(event_box),drawing_area)。下面指定消息:if(partpparent amp。amp。 partpparenttype == LAYOUT_PART_LINK) { gtk_signal_connect(GTK_OBJECT(event_box), enter_notify_event, (GtkSignalFunc)activate_text_link, drawing_area)。 gtk_signal_connect(GTK_OBJECT(event_box), leave_notify_event, (GtkSignalFunc)act