【簡述】
本文講述了乙個簡單的平台無關的richtext的實現方法。
這個richtext特性如下:
【平台無關】
文字大小獲取。
文字的繪製。
我們把它封裝到乙個字型的純虛介面類中去:
class ifont ;
對於自定義的元素,也是乙個純虛的介面類:
class irichtextcustomelement
public:
// 獲取元素寬度
virtual float getwidth() const = 0;
// 獲取元素的高度
virtual float getheight() const = 0;
// 繪製元素
virtual void draw( float fx, float fy ) const = 0;
【實現】
模組劃分
richtext在這裡劃分為兩個模組:乙個稱為richtextdoc,用來儲存內容的,稱為文件;乙個稱為richtextview,用來儲存表現的,稱為檢視。
模組實現:richtextdoc
richtextdoc主要實現了內容管理。
richtextdoc內部儲存兩項內容
字元元素(不同的元素型別,或者同種元素型別但屬性不同)
字元儲存了文字和鏈結的原始字元,而元素儲存了同屬性的一組字元、鏈結或者乙個自定義元素。他們使用idx和len關聯到字元儲存中的原始字元。對於乙個,在字元中使用了乙個空格作為佔位符。
元素中同時儲存了是否作為乙個段落id,這用來描述一組元素是否在同乙個段落裡,這個id為乙個不為0的正整數。
richtextdoc提供了以下介面來新增內容以及訪問元素。
class irichtextdoc
public:
// 新增一段文字
virtual void addtext( const utf16_char * ptext, size_t utextlen ) = 0;
// 新增乙個鏈結
virtual void addlink( const utf16_char * ptext, size_t utextlen, unsigned long ullinkid ) = 0;
// 新增乙個自定義的元素
virtual void addcustom( irichtextcustomelement * pelement ) = 0;
// 新增乙個段落
virtual unsigned long addparagraph() = 0;
// 設定文字顏色
virtual void settextcolor( unsigned long ulcolor ) = 0;
// 設定文字字型
virtual void settextfont( ifont * pfont ) = 0;
// 獲取元素的數量
virtual void getelementcount() const = 0;
// 獲取元素型別
// result: -1 = 非法索引 0=文字 1=鏈結 2=自定義元素
virtual int getelementtype( size_t uelementindex ) const = 0;
// 獲取元素的字型和顏色
// result: -1 = 失敗 0=成功
// pfont: 返回字型介面
// ulcolor: 返回顏色值
virtual int getelementfontandcolor( size_t uelementindex, ifont *& ppfont, unsigned long & ulcolor ) const = 0;
// 獲取元素的字元
virtual void getelementchars( size_t uelementindex, const utf16_char * &pchars, size_t & ucount ) const = 0;
// 獲取自定義元素
virtual irichtextcustomelement * getcustomelement( size_t uelementindex ) const = 0;
// 獲取元素的段落id
virtual unsigned long getelementparagraphid( size_t uelementindex ) const = 0;
// 獲取元素的鏈結id
virtual unsigned long getelementlinkid( size_t uelementindex ) const = 0;
模組實現:richtextview
richtextview 主要實現了排版和繪製。
a 排版功能
它的基本排版單位是line(行),也就是顯示行。在line的內部儲存了數個run。每個run僅對應乙個doc中的元素,但是乙個doc中的元素可以對應多個run(被拆分成多行的情況)。
richtextview中排版是通過拆分doc中的每個元素實現的。因為有ifont介面以及irichtextcustomelement介面,就可以獲取到文字和自定義元素的大小,依次累加到元素結束或者line寬度溢位,就可以結束乙個run,開始下乙個run。
在這個模組的實現中,需要注意下面幾個問題:
如何確定乙個line的高度:在實現裡,是根據每個run對應的元素的高度取max來實現的。
根據段落來適時的換行。
link根據需求來決定是否可以拆分成多個line中的多個run。(實際需求裡是禁止拆分link)
行間距與run和line的hittest。
run的結構是這樣的:
struct run_s ;
line 的結構是這樣的:
struct line_s ;
b- 繪製功能
繪製功能和拆分排版差不多,主要就是繪製座標根據run和line的寬度和高度的累計。
然後呼叫ifont或irichtextcustomelement的繪製方法。
c- hittest
除了排版和繪製之外,view還提供了hittest,用來檢測點選命中了哪個line、run、或者對應到doc中的元素,從而實現點選鏈結的檢測。
richtextview介面如下:
class irichtextview
public:
// 獲取行數
virtual size_t getlinecount() const = 0;
// 獲取行的run數量
virtual size_t getruncount( size_t ulineindex ) const = 0;
// 獲取run對應的元素索引
virtual size_t getrunelementindex( size_t ulineindex, size_t urunindex ) const = 0;
// 用doc,行寬和行間距建立排版內容。
virtual void build( irichtextdoc * pdoc, float flinewidth, float flinegap ) = 0;
// 檢測點選的行
virtual size_t linehittest( float fx, float fy ) const = 0;
// 檢測點選的run
virtual size_t runhittest( size_t ulineindex, float fx, float fy ) const = 0;
// 檢測點選的元素索引
virtual size_t elementhittest( float fx, float fy ) const = 0;
// 獲取view的高度。
virtual float getheight() const = 0;
// 繪製
virtual void draw(float fx, float fy, float fwidth, float fheight) const = 0;
// 從某行開始繪製
virtual void draw(size_t ubeginlineindex, float fx, float fy, float fwidth, float fheight) const = 0;
【應用】
目前應用在乙個手機網遊的專案中,來顯示聊天內容。
平台目前是ios和win32。ios下字型使用的是coretext+coregraphics來實現的。win32下用的是getglyphoutline api。渲染使用的opengles 1.1,內部用gltexsubimage2d來實現了乙個字形的貼圖緩衝。
在專案中,view被繫結在乙個richtext的ui控制項中。
【擴充套件】
目前只能顯示富文字,後面需要擴充套件為richedit使用。
需要增加游標的位置判定和游標的顯示位置和大小的獲取。
考慮在doc上增加儲存文字寬度,以便於view上進行charhittest時的快速取用。
平台無關的Perl應用
最近由於專案需求,需要把再windows平台上執行的 perl程式移植到linux平台上。由於是第一次做類似的事情,結果折騰了很久,實在是無比痛苦啊。那種看著程式無法執行的感受真的是。憋屈!先說一下背景吧。原來實在windows上利用perl對staf進行包裝,做為整個automation框架中的一...
字長與平台無關的整型資料型別
平台無關性 與平台無關的特性使程式可以方便地被移植到網路上的不同機器 不同平台 c99標準定義乙個叫著的標頭檔案,該標頭檔案定義了一系列各種類別的整數型別typedef名字。儘管速多c 工具支援該標頭檔案已經有一段時間了,但它尚未正式收錄於c 標準,因此,在使用該標頭檔案之前,你應該先閱讀你的編譯器...
C C 中有關字長與平台無關的整數型別
字長與平台無關的整型資料型別 在c c 中,整型的長度跟編譯器相關,編譯器的實現取決於cpu。比如tc 是dos16下的應用程式,dos16是16位的作業系統,所以tc 中sizeof int 16 同理win32中sizeof int 32。c99標準定義乙個叫著的標頭檔案,該標頭檔案定義了一系列...