平台無關的RICHTEXT實現

2022-03-12 14:47:58 字數 4687 閱讀 7227

【簡述】

本文講述了乙個簡單的平台無關的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標準定義乙個叫著的標頭檔案,該標頭檔案定義了一系列...