• <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++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              94 隨筆 :: 0 文章 :: 257 評論 :: 0 Trackbacks

            【簡述】

            本文講述了一個簡單的平臺無關(guān)的RICHTEXT的實現(xiàn)方法。

            這個RICHTEXT特性如下:

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

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

            -          支持可獨(dú)立設(shè)置字體顏色的文字和鏈接

            -          支持自定義元素用來實現(xiàn)圖像和動畫

             

            【平臺無關(guān)】

             

            平臺無關(guān)實際上是使用統(tǒng)一的接口來封裝不同平臺的實現(xiàn)方法來做到的。在RICHTEXT中使用到的平臺相關(guān)的有兩個:

            1-       文字大小獲取。

            2-       文字的繪制。

             

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

            class IFont {

            public:

            // 獲取字體的高度

            virtual float GetHeight() const = 0;

            // 獲取文字的橫向步進(jìn)

            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;

                     };

             

            【實現(xiàn)】

             

            1-       模塊劃分

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

             

            2-       模塊實現(xiàn):RichTextDoc

             

            RichTextDoc主要實現(xiàn)了內(nèi)容管理。

             

            RichTextDoc內(nèi)部存儲兩項內(nèi)容

            1)       字符

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

             

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

            元素中同時存儲了是否作為一個段落ID,這用來描述一組元素是否在同一個段落里,這個ID為一個不為0的正整數(shù)。

             

                     RichTextDoc提供了以下接口來添加內(nèi)容以及訪問元素。

             

                     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;

                               //      設(shè)置文字顏色

                               virtual void SetTextColor( unsigned long ulColor ) = 0;

                               //      設(shè)置文字字體

                               virtual void SetTextFont( IFont * pFont ) = 0;

                               //      獲取元素的數(shù)量

                               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-       模塊實現(xiàn):RichTextView

            RichTextView 主要實現(xiàn)了排版和繪制。

             

            A        排版功能

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

             

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

             

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

             

            1)       如何確定一個LINE的高度:在實現(xiàn)里,是根據(jù)每個RUN對應(yīng)的元素的高度取MAX來實現(xiàn)的。

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

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

            4)       行間距與RUNLINEHITTEST

             

            RUN的結(jié)構(gòu)是這樣的:

            struct RUN_S {

                             size_t uElementIndex;                       //      元素的索引

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

                             size_t uInElementCharCount;                   //      在元素中的字符數(shù)量

                             float fWidth;                                          //      RUN的寬度

                             float fHeight;                                        //      RUN的高度

            };

             

            LINE 的結(jié)構(gòu)是這樣的:

            struct LINE_S {

                               vector<RUN_S*> vecRuns;               //      行內(nèi)的RUN

                               float fPosY;                                            //      LINE在整個VIEW中的Y坐標(biāo)。

                               float fHeight;                                        //      LINE的高度

            };

            B- 繪制功能

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

            然后調(diào)用IFontIRichTextCustomElement的繪制方法。

            C- HITTEST

            除了排版和繪制之外,VIEW還提供了HITTEST,用來檢測點(diǎn)擊命中了哪個LINERUN、或者對應(yīng)到DOC中的元素,從而實現(xiàn)點(diǎn)擊鏈接的檢測。

             

            RichTextView接口如下:

             

             

            class IRichTextView

            {

            public:

                       //      獲取行數(shù)

                       virtual size_t GetLineCount() const = 0;

                       //      獲取行的RUN數(shù)量

                       virtual size_t GetRunCount( size_t uLineIndex ) const = 0;

                       //      獲取RUN對應(yīng)的元素索引

                       virtual size_t GetRunElementIndex( size_t uLineIndex, size_t uRunIndex ) const = 0;

                       //      DOC,行寬和行間距建立排版內(nèi)容。

                       virtual void Build( IRichTextDoc * pDoc, float fLineWidth, float fLineGap ) = 0;

                       //      檢測點(diǎn)擊的行

                       virtual size_t LineHitTest( float fX, float fY ) const = 0;

                       //      檢測點(diǎn)擊的RUN

                       virtual size_t RunHitTest( size_t uLineIndex, float fX, float fY ) const = 0;

                       //      檢測點(diǎn)擊的元素索引

                       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;

            };

             

             

            【應(yīng)用】

                     目前應(yīng)用在一個手機(jī)網(wǎng)游的項目中,來顯示聊天內(nèi)容。

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

             

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

             

            【擴(kuò)展】

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

                     需要增加光標(biāo)的位置判定和光標(biāo)的顯示位置和大小的獲取。

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

             

             

             

             

            posted on 2012-11-07 15:48 飯中淹 閱讀(3374) 評論(0)  編輯 收藏 引用 所屬分類: 游戲客戶端手機(jī)開發(fā)(ios)
            久久精品青青草原伊人| 久久婷婷国产麻豆91天堂| 久久午夜福利无码1000合集| 日韩AV无码久久一区二区| 久久亚洲国产午夜精品理论片| 久久精品亚洲欧美日韩久久| 精品久久亚洲中文无码| 色综合久久精品中文字幕首页| 久久妇女高潮几次MBA| 久久久久亚洲精品天堂久久久久久 | 无码AV中文字幕久久专区| 久久国产精品久久久| 亚洲国产精品18久久久久久| 久久久久无码精品| 久久久久夜夜夜精品国产| 久久精品国产亚洲av麻豆色欲| 婷婷久久综合九色综合九七| 欧美久久综合性欧美| 国产成人综合久久综合| 亚洲AV日韩精品久久久久| 亚洲日本va午夜中文字幕久久| 成人午夜精品久久久久久久小说| 久久精品国产亚洲AV香蕉| 国产69精品久久久久9999APGF| 久久久久无码精品国产app| 久久精品二区| 精品无码久久久久久久动漫| 国产成人AV综合久久| 成人a毛片久久免费播放| 91秦先生久久久久久久| 国产激情久久久久影院| 99久久综合国产精品二区| 91精品免费久久久久久久久| 久久精品国产亚洲麻豆| 91久久精品无码一区二区毛片| 久久青草国产手机看片福利盒子| 日韩欧美亚洲综合久久影院d3| 91精品免费久久久久久久久| 久久久久国产一级毛片高清板| 精品久久久久久久久久久久久久久 | 99久久精品免费|