• <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天堂久久久| 99久久久国产精品免费无卡顿| 国产精品久久久久一区二区三区| 久久香蕉一级毛片| 国产精品久久久久久久久久影院 | 亚洲欧美日韩精品久久亚洲区| 国内精品久久久久影院亚洲| 久久99精品久久久久久hb无码| 久久国产影院| 久久国产精品国产自线拍免费| 日韩欧美亚洲国产精品字幕久久久 | 亚洲AV无码久久精品成人| 99久久免费国产特黄| 人妻少妇精品久久| 国产精品99久久久久久人| 好属妞这里只有精品久久| 一本一本久久A久久综合精品| 国产精品久久久99| 久久精品国产99国产精偷 | 99热成人精品免费久久| 久久久久久九九99精品| 伊人精品久久久久7777| 青青国产成人久久91网| 99久久精品毛片免费播放| 久久婷婷是五月综合色狠狠| 国产精品九九久久精品女同亚洲欧美日韩综合区| 中文精品99久久国产| 日韩一区二区三区视频久久| 四虎国产精品免费久久5151| 国产99久久精品一区二区| 国产精品9999久久久久| 久久久久亚洲Av无码专| 国产激情久久久久久熟女老人| 久久婷婷五月综合国产尤物app| 思思久久99热免费精品6| 亚洲另类欧美综合久久图片区| 看全色黄大色大片免费久久久 |