• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            飯中淹的避難所~~~~~

            偶爾來避難的地方~

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              94 隨筆 :: 0 文章 :: 257 評論 :: 0 Trackbacks

            【簡述】

            本文講述了一個簡單的平臺無關的RICHTEXT的實現方法。

            這個RICHTEXT特性如下:

            -          使用UTF-16作為字符編碼

            -          使用行來排版,文字從左到右顯示

            -          支持可獨立設置字體顏色的文字和鏈接

            -          支持自定義元素用來實現圖像和動畫

             

            【平臺無關】

             

            平臺無關實際上是使用統一的接口來封裝不同平臺的實現方法來做到的。在RICHTEXT中使用到的平臺相關的有兩個:

            1-       文字大小獲取。

            2-       文字的繪制。

             

            我們把它封裝到一個字體的純虛接口類中去:

            class IFont {

            public:

            // 獲取字體的高度

            virtual float GetHeight() const = 0;

            // 獲取文字的橫向步進

            virtual float GetCharsAdvance( const UTF16_CHAR * pChars, float * pAdvanceArray, size_t uCount ) const = 0;

            // 繪制文字

            virtual void DrawChars( const UTF16_CHAR * pChars, size_t uCount, float fX, float fY, unsigned long ulColor ) const = 0;

            };

             

            對于自定義的元素,也是一個純虛的接口類:

                     class IRichTextCustomElement

                     {

                     public:

                               //      獲取元素寬度

                               virtual float GetWidth() const = 0;

                               //      獲取元素的高度

                               virtual float GetHeight() const = 0;

                               //      繪制元素

                               virtual void Draw( float fX, float fY ) const = 0;

                     };

             

            【實現】

             

            1-       模塊劃分

            RICHTEXT在這里劃分為兩個模塊:一個稱為RichTextDoc,用來存儲內容的,稱為文檔;一個稱為RichTextView,用來存儲表現的,稱為視圖。

             

            2-       模塊實現:RichTextDoc

             

            RichTextDoc主要實現了內容管理。

             

            RichTextDoc內部存儲兩項內容

            1)       字符

            2)       元素(不同的元素類型,或者同種元素類型但屬性不同)

             

            字符存儲了文字和鏈接的原始字符,而元素存儲了同屬性的一組字符、鏈接或者一個自定義元素。他們使用idxlen關聯到字符存儲中的原始字符。對于一個圖片,在字符中使用了一個空格作為占位符。

            元素中同時存儲了是否作為一個段落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;

                     };

             

            3-       模塊實現:RichTextView

            RichTextView 主要實現了排版和繪制。

             

            A        排版功能

            它的基本排版單位是LINE(行),也就是顯示行。在LINE的內部存儲了數個RUN。每個RUN僅對應一個DOC中的元素,但是一個DOC中的元素可以對應多個RUN(被拆分成多行的情況)。

             

            RichTextView中排版是通過拆分DOC中的每個元素實現的。因為有IFont接口以及IRichTextCustomElement接口,就可以獲取到文字和自定義元素的大小,依次累加到元素結束或者LINE寬度溢出,就可以結束一個RUN,開始下一個RUN

             

            在這個模塊的實現中,需要注意下面幾個問題:

             

            1)       如何確定一個LINE的高度:在實現里,是根據每個RUN對應的元素的高度取MAX來實現的。

            2)       根據段落來適時的換行。

            3)       LINK根據需求來決定是否可以拆分成多個LINE中的多個RUN。(實際需求里是禁止拆分LINK

            4)       行間距與RUNLINEHITTEST

             

            RUN的結構是這樣的:

            struct RUN_S {

                             size_t uElementIndex;                       //      元素的索引

                             size_t uInElementCharIndex;           //      在元素的字符中的索引

                             size_t uInElementCharCount;                   //      在元素中的字符數量

                             float fWidth;                                          //      RUN的寬度

                             float fHeight;                                        //      RUN的高度

            };

             

            LINE 的結構是這樣的:

            struct LINE_S {

                               vector<RUN_S*> vecRuns;               //      行內的RUN

                               float fPosY;                                            //      LINE在整個VIEW中的Y坐標。

                               float fHeight;                                        //      LINE的高度

            };

            B- 繪制功能

            繪制功能和拆分排版差不多,主要就是繪制坐標根據RUNLINE的寬度和高度的累計。

            然后調用IFontIRichTextCustomElement的繪制方法。

            C- HITTEST

            除了排版和繪制之外,VIEW還提供了HITTEST,用來檢測點擊命中了哪個LINERUN、或者對應到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;

            };

             

             

            【應用】

                     目前應用在一個手機網游的項目中,來顯示聊天內容。

                   平臺目前是IOSWIN32IOS下字體使用的是CORETEXT+COREGRAPHICS來實現的。WIN32下用的是GetGlyphOutline API。渲染使用的OPENGLES 1.1,內部用glTexSubImage2D來實現了一個字形的貼圖緩沖。

             

                     在項目中,View被綁定在一個RichTextUI控件中。

             

            【擴展】

                     目前只能顯示富文本,后面需要擴展為RICHEDIT使用。

                     需要增加光標的位置判定和光標的顯示位置和大小的獲取。

                     考慮在DOC上增加存儲文字寬度,以便于VIEW上進行CHARHITTEST時的快速取用。

             

             

             

             

            posted on 2012-11-07 15:48 飯中淹 閱讀(3374) 評論(0)  編輯 收藏 引用 所屬分類: 游戲客戶端手機開發(ios)
            久久久久久毛片免费看| 久久精品人妻中文系列| 久久九九青青国产精品| 91亚洲国产成人久久精品| 久久性生大片免费观看性| 亚洲精品乱码久久久久久久久久久久| 精品久久久久久无码专区| 久久av高潮av无码av喷吹| 天天躁日日躁狠狠久久| 久久一区二区三区免费| 狠狠色婷婷久久一区二区三区| 久久成人18免费网站| 国产亚洲综合久久系列| 日韩精品久久久久久久电影| 精品久久综合1区2区3区激情| 亚洲中文字幕久久精品无码喷水| 国产99久久久久久免费看| 国内精品伊人久久久久AV影院| 久久丝袜精品中文字幕| 免费观看久久精彩视频| 国产精品久久久久久| 亚洲精品乱码久久久久久| 久久无码AV中文出轨人妻| 精品无码久久久久久国产| 成人久久久观看免费毛片 | 久久久青草青青亚洲国产免观| 四虎影视久久久免费观看| 国产福利电影一区二区三区久久久久成人精品综合 | 久久精品国产91久久综合麻豆自制| 久久久久99这里有精品10| 久久影视综合亚洲| 久久久久国产一区二区三区| 成人亚洲欧美久久久久| 26uuu久久五月天| 久久香蕉国产线看观看99| 久久97精品久久久久久久不卡| 嫩草影院久久国产精品| 9999国产精品欧美久久久久久| 国产三级久久久精品麻豆三级| 无码人妻少妇久久中文字幕蜜桃| 亚洲AV无码久久精品成人 |