一種快速刷新richedit中內嵌動畫的方法的實現


在IM中使用動畫表情是一種非常有趣的方式,然而選擇一種合適的方式來實現卻並不容易。

一般來說,除了自己去實現一個富文本控件,目前主要的解決方案有3種:

1、使用瀏覽器做容器。

2、使用QT提供的Richtext做容器。

3、使用Richedit做容器。

使用瀏覽器做容器好處是使用簡單,效率應該也不錯(沒有測試,只是感覺),缺點也很明顯:內存占用太高,依賴於瀏覽器內核。基於IE內核雖然不需要帶一個大的安裝包,但IE內核問題不少,有了問題很難解決;webkit內核雖然開源,但是體積寵大。

而要使用QT的Richtext則要求程序是基於QT開發,如YY語音。對於一般的客戶端程序來說,QT也還是太大了,而且QT中的Richtext能夠實現的功能和windows中的richedit相比也還是略顯單薄。

這里重點談談第三種方式,也是在各大IM中廣泛使用的方式:基於Richedit的插入OLE對象的方式實現動畫表情。

目前看來在QQ中實現的動畫表情刷新效率應該是最高的,可以看到QQ從歷史版本以來就一直堅持使用richedit來顯示聊天內容。

使用Richedit的優點很多,和瀏覽器相比如體積小,內存占用小,效率在經過適當優化后也可以很高(現在的QQ在動畫刷新上應該是首屈一指的);和QT的richtext相比,不需要依賴QT(這里只限於windows平台),功能豐富,而且MS也還在不斷推出新版本。

雖然說在QQ中使用Richedit顯示動畫表情性能不錯,然而不是隨便哪個客戶端開發人員簡單實現一個OLE對象就可以實現的。到底能達到什么樣的性能還要看最后優化的功力。

說了這么多,干貨出場......

我們知道,Richedit是一個OLE對象的容器。通過自己實現一個新的OLE對象,就可以實現在Richedit中顯示自繪的圖象,當然也包含表情動畫。

動畫要動起來,不外乎定時去刷新這些OLE對象。

要刷新一個OLE對象,首先需要知道OLE對象的位置。

獲得對象位置在我看來可以有兩種方式:

1、每次都向richedit查詢自己的位置(如本博客上一篇提供的方法類似)。

2、在OLE對象的OnDraw函數中緩存對象的繪制位置。

當容器中顯示的表情數量相對較少時,如<100,這時第一種方式簡單有效,但是當顯示對象很多時(如滿屏的小動畫,>1000個),盡管采用兩分法去查詢坐標,CPU占用也不簡單。

第二種方法簡單直接,因為對象插入后是要顯示的,一顯示容器就要調用OLE的OnDraw方法來繪制這個OLE對象,其中的參數就有顯示位置,只需要在這時把這個位置緩存起來即可,不需要每次都去查詢。但是問題也來了,這種方法只知道誰要顯示,不知道誰不要顯示,那么那些不需要顯示的表情的定時器如何處理呢?

解決這個問題的答案在於一個由Richedit在刷新時發出來的消息:EN_UPDATE。該消息在Richedit每次繪制前都會由Richedit Send到應用程序。有了這個消息,我們就可以在窗口刷新的時候清空那些已經隱藏了的表情的定時器。

到此我們的選擇已經有了,那就是直接緩存表情坐標。

有了坐標如何定時刷新表情呢?

刷新對象有兩種方式:

1、通過InvalidateRect來刷新Richedit中表情的位置。

2、直接在Richedit中表情顯示位置繪制新的表情幀。

如果同時只顯示少量的表情,采用哪種方法都沒有問題。這里要解決的同時大量小表情刷新的問題(如>1000),這個時候臟矩形甚至都變得沒有意義了,基本上都是整個窗口的刷新。

既然是整個窗口刷新,采用InvalidateRect和自己繪制會有什么不同嗎?

在昨天以前我也一直不相信這樣一個殘酷的實現:Richedit在刷新滿屏的小動畫時效率非常低,低到讓你無法忍受(單核CPU可以占到100%)。查了半天一直不明白瓶頸在哪。

經過不斷排查,最后定位到Richedit的渲染問題上:當OLE對象很多時,Richedit在一個1920*1020的屏幕上刷新小表情動畫一次要用掉200ms左右(CPU I5, 2.3G)。通過編譯一份網上獲得的Wince上使用的Richedit源碼並運行,采用Intel的VTune分析性能瓶頸發現,在Richedit的繪制內容是一個字符串,每個Richedit對象在這個字符串中以0xFFFE代表,要繪制這個OLE對象,Richedit需要去一個OLE列表中查詢哪一個OLE對象指向當前的0xFFFE所在的索引,盡管在查詢時采用兩分法去查詢OLE對象的指針,當對象數量比較大時,效率依然非常低下(假定顯示1024個對象,顯示一個平均查詢10次,那么就需要1024*10次查詢)。

定位了瓶頸答案就顯而易見了,直接通過Richedit的繪制來更新OLE顯然對象這樣的場景是不合適的,剩下的就只能是自己繪制表情了。

繪制表情就需要涉及到表情的選擇狀態,背景,及其它一些不需要更新的內容的剪裁等細節問題,只需要做好適當處理即可。

下面帖出在SOUI中插入大量小表情和在QQ中插入大量小表情CPU占用比較:

1920×1080:soui占用3%, QQ占用19%。(身邊沒有機器,沒有截圖)

1366*768:soui占用0%, QQ占用8%(見下圖)。

SOUI.DEMO

QQ


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM