• <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,用來檢測點擊命中了哪個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;

            };

             

             

            【應用】

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

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

             

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

             

            【擴展】

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

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

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

             

             

             

             

            posted on 2012-11-07 15:48 飯中淹 閱讀(3365) 評論(0)  編輯 收藏 引用 所屬分類: 游戲客戶端 、手機開發(ios)
            亚洲国产精品成人AV无码久久综合影院| 亚洲色欲久久久综合网| 国产成人AV综合久久| 久久成人精品| 伊人久久大香线蕉亚洲五月天| 久久久婷婷五月亚洲97号色| 91麻豆精品国产91久久久久久| 午夜精品久久影院蜜桃| 精品久久久久久成人AV| 亚洲国产成人久久综合一区77| 久久精品国产亚洲av麻豆小说| 久久综合给合综合久久| 2021久久国自产拍精品| 18禁黄久久久AAA片| 国产亚洲精午夜久久久久久| 99精品国产综合久久久久五月天| 四虎国产永久免费久久| 久久久无码精品亚洲日韩蜜臀浪潮 | 久久精品国产99国产精偷| 国产精品日韩欧美久久综合| 久久中文骚妇内射| 亚洲人AV永久一区二区三区久久 | 2021国产成人精品久久| 久久精品国产久精国产果冻传媒 | 国产精品久久久久久影院| 伊人热热久久原色播放www| 精品久久久久国产免费| 精品无码久久久久国产| 中文字幕乱码久久午夜| 狠狠色丁香久久婷婷综合图片| 久久se这里只有精品| 91精品国产综合久久香蕉| 精品久久久久久中文字幕人妻最新| 99久久做夜夜爱天天做精品| 久久综合久久伊人| 亚洲国产成人精品无码久久久久久综合| 狠狠色丁香久久婷婷综| 久久综合久久综合久久| 久久青青草原精品影院| 大美女久久久久久j久久| 国产免费久久精品99久久|